|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T r
Length: 16335 (0x3fcf)
Types: TextFile
Names: »read.c«
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
└─⟦this⟧ »./DVIware/laser-setters/quicspool/libprofile/read.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
└─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z«
└─⟦ca79c7339⟧
└─⟦this⟧ »DVIware/laser-setters/quicspool/libprofile/read.c«
static char *rcs = "$Header: read.c,v 1.1 88/01/15 12:17:05 simpson Rel $";
/*
$Log: read.c,v $
* Revision 1.1 88/01/15 12:17:05 simpson
* initial release
*
* Revision 0.1 87/12/11 17:02:13 simpson
* beta test
*
*/
#include <stdio.h>
#include <ctype.h>
#include "profile.h"
#define isoctal(d) ('0' <= d && d <= '7')
#define ishex(x) (isdigit(x) || ('a' <= x && x <= 'f') || ('A' <= x && x <= 'F'))
#define isprime(c) (c == '\'')
#define isbackslash(c) (c == '\\')
#define iscaret(c) (c == '^')
extern char *strcpy();
extern PROFILE_STANZA *profile_stanza_space();
extern PROFILE_MARKER *profile_marker_space();
extern PROFILE_BINDING *profile_binding_space();
extern PROFILE_VALUE *profile_value_space();
static PROFILE_BINDING *get_binding();
static PROFILE_BINDING *get_bindings();
static PROFILE_MARKER *get_marker();
static PROFILE_MARKER *get_markers();
static PROFILE_VALUE *get_value();
static PROFILE_VALUE *get_values();
static char parse_character();
static PROFILE_VALUE *parse_value();
PROFILE_STANZA *profile_read_stanza (f)
FILE *f;
{
PROFILE_STANZA *stanza;
stanza = profile_stanza_space();
if (stanza == NULL)
return(NULL);
stanza->marker = get_markers(f);
if (get_open_bindings(f))
stanza->binding = get_bindings(f);
else {
profile_free_stanza(stanza);
return(NULL);
}
if (get_close_bindings(f))
return(stanza);
else {
profile_free_stanza(stanza);
return(NULL);
}
}
/* Returns the list of markers at the head of a stanza. */
static PROFILE_MARKER *get_markers (f)
FILE *f;
{
PROFILE_MARKER *head, *tail, *m;
head = tail = NULL;
while (m = get_marker(f))
if (tail) {
tail->next = m;
m->previous = tail;
tail = m;
} else
head = tail = m;
return(head);
}
/* Returns the next marker from the head of the stanza. */
static PROFILE_MARKER *get_marker (f)
FILE *f;
{
int n;
PROFILE_MARKER *m;
char scratch[PROFILE_MAX_TEXT+1];
for (;;)
if (n = get_name_text(f, scratch)) {
if ((m = profile_marker_space(n)) == NULL)
return(NULL);
strcpy(m->text, scratch);
return(m);
} else if (get_end_of_line(f))
continue;
else
return(NULL);
}
/* Returns the list of bindings in the body of the stanza. */
static PROFILE_BINDING *get_bindings (f)
FILE *f;
{
PROFILE_BINDING *head, *tail, *b;
head = tail = NULL;
while (b = get_binding(f))
if (tail) {
tail->next = b;
b->previous = tail;
tail = b;
} else
head = tail = b;
return(head);
}
/* Returns the next binding in the body of the stanza. */
static PROFILE_BINDING *get_binding (f)
FILE *f;
{
int n;
PROFILE_BINDING *b;
char scratch[PROFILE_MAX_TEXT+1];
for (;;)
if (n = get_name_text(f, scratch)) {
if ((b = profile_binding_space(n)) == NULL)
return(NULL);
strcpy(b->name, scratch);
break;
} else if (get_end_of_line(f))
continue;
else
return(NULL);
b->value = get_values(f);
return(b);
}
/* Returns the list of values following the name of the binding. */
static PROFILE_VALUE *get_values (f)
FILE *f;
{
PROFILE_VALUE *head, *tail, *v;
head = tail = NULL;
while (v = get_value(f))
if (tail) {
tail->next = v;
v->previous = tail;
tail = v;
} else
head = tail = v;
return(head);
}
/* Returns the next value in the binding. */
static PROFILE_VALUE *get_value (f)
FILE *f;
{
char text[PROFILE_MAX_TEXT+1];
int n;
for (;;)
if (n = get_value_text(f, text))
return(parse_value(text, n));
else if (get_end_of_line(f))
return(NULL);
else
return(NULL);
}
/*
* Reads the text of the next value (if any) in the binding. Returns
* the length of the literal text in characters.
*/
static int get_value_text (f, text)
FILE *f;
char *text;
{
register int c;
char *s = text;
while ((c = getc(f)) != EOF)
switch (c) {
case '\b': case '\f':
case '\r': case '\t': case ' ':
/* white space terminates any text gathered so far */
if (s > text) {
*s = '\0';
return(s - text);
}
continue;
case '\n':
/* newline terminates a binding */
ungetc(c, f);
*s = '\0';
return(s - text);
case '#':
/* gobble up the comment */
while ((c = getc(f)) != EOF && c != '\n')
continue;
if (c == '\n')
ungetc(c, f);
*s = '\0';
return(s - text);
case '{': case '}':
ungetc(c, f);
*s = '\0';
return(s - text);
case '"': /* string quotes */
ungetc(c, f);
if (s > text) {
*s = '\0';
return(s - text);
} else
return(get_string(f, s));
case '\'': /* character quotes */
ungetc(c, f);
if (s > text) {
*s = '\0';
return(s - text);
} else
return(get_character(f, s));
case '\\': /* newline escape */
c = getc(f);
if (c == '\n') {
if (s > text) {
*s = '\0';
return(s - text);
}
continue; /* just like a blank */
}
ungetc(c, f);
if (s < &text[PROFILE_MAX_TEXT])
*s++ = '\\';
continue;
default:
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
continue;
}
*s = '\0';
return(s - text);
}
/* Digests the raw value text returning a new value structure. */
static PROFILE_VALUE *parse_value (s, length)
char *s; /* literal text */
int length; /* in characters */
{
PROFILE_VALUE *v;
if (is_integer(s)) {
if ((v = profile_value_space(0)) == NULL)
return(NULL);
v->class = PROFILE_INTEGER;
sscanf(s, "%D", &v->value.i);
} else if (is_octal(s)) {
if ((v = profile_value_space(0)) == NULL)
return(NULL);
v->class = PROFILE_OCTAL;
/* skip the `0o' prefix */
sscanf(s+2, "%O", &v->value.i);
} else if (is_hex(s)) {
if ((v = profile_value_space(0)) == NULL)
return(NULL);
v->class = PROFILE_HEX;
/* skip the `0x' prefix */
sscanf(s+2, "%X", &v->value.i);
} else if (is_string(s)) {
/* be careful when dealing with the empty string "" */
if ((v = profile_value_space(length > 2 ? length - 2 : 1)) == NULL)
return(NULL);
v->class = PROFILE_STRING;
/* erase the terminating double quote */
s[length - 1] = '\0';
/* skip past the initial quote */
parse_string(s + 1, v->value.s);
} else if (is_character(s)) {
if ((v = profile_value_space(0)) == NULL)
return(NULL);
v->class = PROFILE_CHARACTER;
/* erase the end single quote */
s[length - 1] = '\0';
v->value.c = parse_character(s + 1);
} else if (is_float(s)) {
if ((v = profile_value_space(0)) == NULL)
return(NULL);
v->class = PROFILE_FLOAT;
sscanf(s, "%E", &v->value.f);
} else {
if ((v = profile_value_space(length)) == NULL)
return(NULL);
v->class = PROFILE_OTHER;
strcpy(v->value.s, s);
}
return(v);
}
/* Converts a string literal to the internal representation. */
static parse_string (source, result)
char *source;
char *result;
{
for (; *source; source++)
if (*source == '\\')
switch (*++source) {
case 'b': /* backspace */
*result++ = '\b';
continue;
case 'f': /* formfeed */
*result++ = '\f';
continue;
case 'n': /* newline */
*result++ = '\n';
continue;
case 'r': /* carriage return */
*result++ = '\r';
continue;
case 't': /* horizontal tab */
*result++ = '\t';
continue;
case '\'': /* single quote */
*result++ = '\'';
continue;
case '"': /* double quote */
*result++ = '"';
continue;
case '\\': /* backslash */
*result++ = '\\';
continue;
case '^': /* caret */
*result++ = '^';
continue;
case '0': case '1': /* octal constant */
case '2': case '3':
case '4': case '5':
case '6': case '7':
source += parse_octal(source, result) - 2;
result++;
continue;
default:
*result++ = *source; /* ignore backslash */
}
else if (*source == '^') { /* control escape */
char c = *++source;
*result++ = ('@' <= c && c <= '_') ? c - '@' :
(c == '?') ? '\177' : c;
continue;
} else
*result++ = *source;
*result = '\0';
}
/* Converts a character literal to the internal representation. */
static char parse_character (source)
char *source;
{
char c;
if (*source == '\\')
switch (*++source) {
case 'b': /* backspace */
return('\b');
case 'f': /* formfeed */
return('\f');
case 'n': /* newline */
return('\n');
case 'r': /* carriage return */
return('\r');
case 't': /* horizontal tab */
return('\t');
case '\'': /* single quote */
return('\'');
case '\\': /* backslash */
return('\\');
case '^':
return('^');
case '0': case '1': /* octal constant */
case '2': case '3':
case '4': case '5':
case '6': case '7':
parse_octal(source, &c);
return(c);
default:
return(*source); /* ignore backslash */
}
else if (*source == '^') { /* control escape */
c = *++source;
return(('@' <= c && c <= '_') ? c - '@' : (c == '?') ? '\177' : c);
} else
return(*source);
}
/* Converts an octal escape `\ddd' to its byte representation. */
static int parse_octal (source, result)
char *source;
char *result;
{
int count;
char byte = '\0';
char digit;
for (count = 1; count <= 3; count++) {
digit = *source++;
if ('0' <= digit && digit <= '7')
byte = (byte * 8) + (digit - '0');
else
break;
}
*result = byte;
return(count);
}
/*
* Reads the literal text for markers and binding names. Returns the
* length in characters of the literal text.
*/
static int get_name_text (f, text)
FILE *f;
char *text;
{
register int c;
char *s = text;
while ((c = getc(f)) != EOF)
switch (c) {
case '\b': case '\f':
case '\r': case '\t': case ' ':
/* white space terminates text gathered so far */
if (s > text) {
*s = '\0';
return(s - text);
}
continue;
case '\n':
ungetc(c, f);
*s = '\0';
return(s - text);
case '#':
/* gobble up the comment */
while ((c = getc(f)) != EOF && c != '\n')
continue;
if (c == '\n')
ungetc(c, f);
*s = '\0';
return(s - text);
case '{': case '}':
ungetc(c, f);
*s = '\0';
return(s - text);
case '[':
/* sets may contain embedded white space */
if (s + 1 < &text[PROFILE_MAX_TEXT]) {
*s++ = '[';
if ((c = getc(f)) != EOF)
*s++ = c;
}
while ((c = getc(f)) != EOF) {
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
if (c == ']')
break;
}
continue;
case '\\':
c = getc(f);
if (c == '\n') {
if (s > text) {
*s = '\0';
return(s - text);
}
continue; /* just like a blank */
}
ungetc(c, f);
if (s < &text[PROFILE_MAX_TEXT])
*s++ = '\\';
continue;
default:
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
continue;
}
*s = '\0';
return(s - text);
}
/* Returns non-zero on end of line and zero otherwise. */
static int get_end_of_line (f)
FILE *f;
{
int c;
if ((c = getc(f)) == '\n')
return(1);
ungetc(c, f);
return(0);
}
/* Returns non-zero on seeing `{' and zero otherwise. */
static int get_open_bindings (f)
FILE *f;
{
int c;
if ((c = getc(f)) == '{')
return(1);
ungetc(c, f);
return(0);
}
/* Returns non-zero on seeing `}' and zero otherwise. */
static int get_close_bindings (f)
FILE *f;
{
int c;
if ((c = getc(f)) == '}')
return(1);
ungetc(c, f);
return(0);
}
/* Reads a string literal returning the length of the literal text in characters */
static int get_string (f, text)
FILE *f;
char *text;
{
register int c;
char *s = text;
/* the first double quote is guaranteed */
*s++ = getc(f);
while ((c = getc(f)) != EOF)
switch (c) {
case '\\':
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
c = getc(f);
if (c == EOF)
return(s - text);
else if (c == '\n') {
ungetc(c, f);
return(s - text);
} else if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
continue;
case '"':
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
*s = '\0';
return(s - text);
case '\n':
ungetc(c, f);
*s = '\0';
return(s - text);
default:
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
continue;
}
*s = '\0';
return(s - text);
}
/* Reads a character literal returning the length of the literal text in characters. */
static int get_character (f, text)
FILE *f;
char *text;
{
register int c;
char *s = text;
/* the first single quote is guaranteed */
*s++ = getc(f);
while ((c = getc(f)) != EOF)
switch (c) {
case '\\':
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
c = getc(f);
if (c == EOF)
return(s - text);
else if (c == '\n') {
ungetc(c, f);
return(s - text);
} else if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
continue;
case '\'':
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
*s = '\0';
return(s - text);
case '\n':
ungetc(c, f);
*s = '\0';
return(s - text);
default:
if (s < &text[PROFILE_MAX_TEXT])
*s++ = c;
continue;
}
*s = '\0';
return(s - text);
}
/* all regular expressions below are in lex notation */
/* returns non-zero iff -?[0-9]+ matches */
static int is_integer (s)
char *s;
{
char *x;
/* -? */
if (*s == '-')
s++;
/* [0-9]+ */
for (x = s; isdigit(*s); s++)
continue;
return(s > x && !*s);
}
/* returns non-zero iff 0[oO][0-7]+ matches */
static int is_octal (s)
char *s;
{
char *x;
/* 0 */
if (*s == '0')
s++;
else
return(0);
/* [oO] */
if (*s == 'o' || *s == 'O')
s++;
else
return(0);
/* [0-7]+ */
for (x = s; isoctal(*s); s++)
continue;
return(s > x && !*s);
}
/* returns non-zero iff 0[xX][0-9a-fA-F]+ matches */
static int is_hex (s)
char *s;
{
char *x;
/* 0 */
if (*s == '0')
s++;
else
return(0);
/* [xX] */
if (*s == 'x' || *s == 'X')
s++;
else
return(0);
/* [0-9a-fA-F]+ */
for (x = s; ishex(*s); s++)
continue;
return(s > x && !*s);
}
/* returns non-zero iff [eE][-+]?[0-9]+ matches */
static int is_exponent (s)
char *s;
{
char *x;
/* [eE] */
if (*s == 'e' || *s == 'E')
s++;
else
return(0);
/* [-+]? */
if (*s == '-' || *s == '+')
s++;
/* [0-9]+ */
for (x = s; isdigit(*s); s++)
continue;
return(s > x && !*s);
}
static int is_float (s)
char *s;
{
return(is_integer_part_float(s) ||
is_fractional_part_float(s) ||
is_power_float(s));
}
/* returns non-zero iff -?[0-9]+"."[0-9]*({exponent})? matches */
static int is_integer_part_float (s)
char *s;
{
char *x;
/* -? */
if (*s == '-')
s++;
/* [0-9]+"." */
for (x = s; isdigit(*s); s++)
continue;
if (x == s || *s != '.')
return(0);
/* [0-9]* */
for (s++; isdigit(*s); s++)
continue;
/* ({exponent})? */
return(*s ? is_exponent(s) : 1);
}
/* returns non-zero iff -?"."[0-9]+({exponent})? matches */
static int is_fractional_part_float (s)
char *s;
{
char *x;
/* -? */
if (*s == '-')
s++;
/* "." */
if (*s == '.')
s++;
else
return(0);
/* [0-9]+({exponent})? */
for (x = s; isdigit(*s); s++)
continue;
return(s > x ? !*s || is_exponent(s) : 0);
}
/* returns non-zero iff -?[0-9]+{exponent} matches */
static int is_power_float (s)
char *s;
{
char *x;
/* -? */
if (*s == '-')
s++;
/* [0-9]+{exponent} */
for (x = s; isdigit(*s); s++)
continue;
return(s > x ? is_exponent(s) : 0);
}
/* returns non-zero iff '[^^\]' | '\^.' | '\\\\' | '\\'' | '\[0-7]{1-3}' matches */
static int is_character (s)
char *s;
{
char *x;
if (isprime(*s))
s++;
else
return(0);
if (isbackslash(*s)) {
s++;
if ((isbackslash(s[0]) || isprime(s[0]) || !isdigit(s[0])) &&
isprime(s[1]) && !s[2])
return(1);
for (x = s; isoctal(*s); s++)
continue;
return(x < s && s < (x+4) && isprime(s[0]) && !s[1]);
} else if (iscaret(*s))
s++;
return(isprint(s[0]) && isprime(s[1]) && !s[2]);
}
/* returns non-zero iff s is a string constant */
static int is_string (s)
char *s;
{
char *x;
if (*s != '"')
return(0);
for (s++; *s; s++) {
if (*s == '"')
return(!*++s); /* quote must be followed by null */
if (isbackslash(*s) || iscaret(*s)) {
if (*++s)
continue; /* legal escape */
return(0); /* null follows \ or ^ */
}
}
return(0);
}
/*
* read an entire profile, making a bidirectional
* circularly linked list
* returns pointer to the first stanza or NULL on error
*/
PROFILE_STANZA *profile_read_profile(f)
FILE *f;
{
PROFILE_STANZA *head = NULL;
PROFILE_STANZA *tail = NULL;
PROFILE_STANZA *x = NULL;
while ((x = profile_read_stanza(f)) != NULL) {
if (head == NULL)
head = tail = x;
else {
tail->next = x;
x->previous = tail;
tail = x;
}
}
if (head != NULL) {
tail->next = head;
head->previous = tail;
}
return(head);
}