diff options
Diffstat (limited to 'dviware/quicspool/libprofile/read.c')
-rw-r--r-- | dviware/quicspool/libprofile/read.c | 834 |
1 files changed, 834 insertions, 0 deletions
diff --git a/dviware/quicspool/libprofile/read.c b/dviware/quicspool/libprofile/read.c new file mode 100644 index 0000000000..3ab17765bf --- /dev/null +++ b/dviware/quicspool/libprofile/read.c @@ -0,0 +1,834 @@ +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); +} |