home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
net
/
LaTex.index.2
< prev
next >
Wrap
Internet Message Format
|
1986-06-01
|
57KB
From simpson@trwrb.UUCP (Scott Simpson) Fri May 30 20:19:30 1986
Path: seismo!lll-crg!styx!nike!cad!ucbvax!sdcsvax!sdcrdcf!trwrb!simpson
From: simpson@trwrb.UUCP (Scott Simpson)
Newsgroups: net.sources
Subject: LaTeX Index Processor (Part 2)
Message-ID: <1110@trwrb.UUCP>
Date: 31 May 86 00:19:30 GMT
Organization: TRW EDS, Redondo Beach, CA
Lines: 2864
Keywords: LaTeX, Index Processor
#! /bin/sh
# To extract, remove mail header lines and type "sh filename"
if [ ! -d libglob ]
then
mkdir libglob
echo mkdir libglob
fi
echo x - libglob/Makefile
sed -e 's/^X//' > libglob/Makefile << '!FaR!OuT!'
X# @(#)Makefile 1.1 (TRW) 1/14/86
X
XCFLAGS = -O
XOBJECTS = glob.o
XDESTDIR = /
XINCLUDE = /usr/include/local
X
X.c.o:
X ${CC} ${CFLAGS} -c $*.c
X -ld -x -r $*.o
X mv a.out $*.o
X
Xall: libglob.a
X
Xlibglob.a: ${OBJECTS}
X ar cr libglob.a ${OBJECTS}
X ranlib libglob.a
X chmod 644 libglob.a
X
Xinstall: all
X mv libglob.a ${DESTDIR}/usr/local/lib
X ranlib ${DESTDIR}/usr/local/lib/libglob.a
X install -c glob.h ${INCLUDE}/glob.h
X
Xclean:
X rm -f *.o
!FaR!OuT!
if [ ! -d libglob ]
then
mkdir libglob
echo mkdir libglob
fi
echo x - libglob/glob.3
sed -e 's/^X//' > libglob/glob.3 << '!FaR!OuT!'
X.\" %W% (TRW) %G%
X.TH GLOB 3 TRW
X.UC
X.SH NAME
Xglob \- shell style pattern matching
X.SH SYNOPSIS
X.nf
X.B #include <local/glob.h>
X
X.B int glob_compile(pattern, buffer)
X.B char *pattern;
X.B char *buffer;
X
X.B int glob_execute(buffer, s)
X.B char *buffer;
X.B char *s;
X
X.B int glob_match (pattern, s)
X.B char *pattern;
X.B char *s;
X.fi
X
X.B cc
X[ flags ] files
X.B -lglob
X[ libraries ]
X.fi
X.SH DESCRIPTION
X.I Glob
Xis a pattern matching facility similar to that of
X.IR sh (1)
Xand
X.IR csh (1).
X.PP
XA pattern specifies a set of strings of characters.
XA member of this set of strings is said to be matched by the pattern.
X.TP
X(1)
XAny character except a special character matches itself.
XThe special characters are [ * and ?.
X.TP
X(2)
XA ? matches any character.
X.TP
X(3)
XA nonempty string
X.I s
Xbracketed
X.RI [ s ]
Xmatches any character in
X.IR s .
XIn
X.I s
X] may only appear as the first letter.
XA substring
X.IR a \- b ,
Xwith
X.I a
Xand
X.I b
Xin ascending ASCII order,
Xstands for the inclusive range of ASCII characters.
X.TP
X(4)
XA * matches 0 or more characters.
X.PP
X.I Glob_compile
Xcompiles a
X.I pattern
Xinto an internal form suitable for matching,
Xplacing the result in the character array
X.IR buffer .
X.I Buffer
Xmust be a character array of size
X.BR GLOB_MAX_PATTERN .
X.I Glob_compile
Xreturns 0 if the
X.I pattern
Xwas compiled successfully;
Xotherwise a negative error code is returned.
X.PP
X.I Glob_execute
Xchecks the argument string
X.I s
Xagainst the compiled
X.IR pattern .
X.I Glob_execute
Xreturns 1 if the string
X.I s
Xmatches the compiled pattern in
X.IR buffer ,
X0 if the string
X.I s
Xfailed to match the compiled pattern in
X.IR buffer ,
Xand a negative error code if the compiled pattern was invalid.
X.PP
XThe strings passed to both
X.I glob_compile
Xand
X.I glob_execute
Xmay have trailing or embedded newline characters;
Xthey are terminated by nulls.
X.PP
X.I Glob_match
Xcompiles
X.I pattern
Xand matches it against the argument string
X.IR s .
XIt returns 1 if the string
X.I s
Xmatches the pattern;
X0 if the string
X.I s
Xfails to match the pattern
Xand a negative error code if the pattern was invalid.
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xregex(3)
X.SH DIAGNOSTICS
XThe following diagnostic codes are provided:
X.TP
XGLOB_OK
Xreturned by
X.I glob_compile
Xindicating the pattern compiled successfully;
X.TP
XGLOB_PATTERN_TOO_BIG
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating the compiled pattern overflowed the buffer;
X.TP
XGLOB_PATTERN_EMPTY
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating the pattern is the empty string;
X.TP
XGLOB_BRACKET_MISSING
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating that a set expression
X.RI [ s ]
Xis missing the terminating bracket ];
X.TP
XGLOB_RANGE_INVERTED
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating a range expression in a set
Xis inverted, for example [z-a];
X.TP
XGLOB_SET_TOO_BIG
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating a compiled set requires more than 127 bytes
X(a single character consumes 2 bytes and a range consumes 3 bytes);
X.TP
XGLOB_EXECUTION_ERROR
Xreturned by
X.I glob_execute
Xor
X.I glob_match
Xindicating an internal error.
!FaR!OuT!
if [ ! -d libglob ]
then
mkdir libglob
echo mkdir libglob
fi
echo x - libglob/glob.c
sed -e 's/^X//' > libglob/glob.c << '!FaR!OuT!'
Xstatic char *trwsccs= "@(#)glob.c 1.1 (TRW) 1/14/86";
X#include "glob.h"
X
X#define SLOP 5
X#define MAX_SET 0177
X
X/* control codes for regular expression evaluation */
X#define PATTERN_ANY '?'
X#define PATTERN_CHARACTER 'X'
X#define PATTERN_END '$'
X#define PATTERN_SET '['
X#define PATTERN_SET_MEMBER 'M'
X#define PATTERN_SET_RANGE '-'
X#define PATTERN_STAR '*'
X
X/*
X * Examples (=> denotes `compiles into')
X *
X * a => Xa
X * ? => ?
X * [x0-9] => [^EMx-09 (^E is control-E)
X * * => *
X * END => $
X *
X * a?[x0-9]* => Xa?[^EMx-09*$
X */
X
Xglob_compile (pattern, buffer)
Xchar *pattern;
Xchar *buffer; /* compiled pattern */
X{
X char *x; /* pointer into compiled pattern */
X int c;
X int result;
X
X if (pattern == 0 || pattern[0] == 0)
X return(GLOB_PATTERN_EMPTY);
X
X x = buffer;
X while (x < &buffer[GLOB_MAX_PATTERN - SLOP]) {
X c = *pattern++;
X if (c == 0) {
X *x++ = PATTERN_END;
X return(GLOB_OK);
X }
X
X switch (c) {
X case '?':
X *x++ = PATTERN_ANY;
X continue;
X
X case '[':
X if ((result = compile_set(pattern, x, &buffer[GLOB_MAX_PATTERN - SLOP])) < 0)
X return(result);
X pattern += result + 1;
X x += x[1] + 2;
X continue;
X
X case '*':
X *x++ = PATTERN_STAR;
X continue;
X
X default:
X *x++ = PATTERN_CHARACTER;
X *x++ = c;
X continue;
X }
X }
X return(GLOB_PATTERN_TOO_BIG);
X}
X
Xint glob_execute (pattern, s)
Xchar *pattern; /* compiled pattern */
Xchar *s; /* string to be matched against */
X{
X char *current;
X int result;
X
X for (;;)
X switch (*pattern++) {
X case PATTERN_ANY:
X if (*s++)
X continue;
X return(0);
X
X case PATTERN_CHARACTER:
X if (*pattern++ == *s++)
X continue;
X return(0);
X
X case PATTERN_END:
X return(*s == 0);
X
X case PATTERN_SET:
X if ((result = in_set(pattern, *s++)) == 1) {
X pattern += *pattern + 1;
X continue;
X }
X return(result);
X
X case PATTERN_STAR:
X current = s;
X while (*s++)
X continue;
X do {
X s--;
X if (result = glob_execute(pattern, s))
X return(result);
X } while (s > current);
X return(0);
X
X default:
X return(GLOB_EXECUTION_ERROR);
X }
X}
X
Xint glob_match (pattern, s)
Xchar *pattern;
Xchar *s;
X{
X int result;
X char buffer[GLOB_MAX_PATTERN];
X
X if ((result = glob_compile(pattern, buffer)) < 0)
X return(result);
X else
X return(glob_execute(buffer, s));
X}
X
X/* returns 1 if character c is member of set and 0 otherwise */
Xstatic int in_set (set, c)
Xchar *set; /* compiled set pattern */
Xchar c;
X{
X int n;
X
X if (c == 0)
X return(0);
X n = *set++;
X while (n > 0)
X switch (*set++) {
X case PATTERN_SET_MEMBER:
X if (*set++ == c)
X return(1);
X n -= 2;
X continue;
X
X case PATTERN_SET_RANGE:
X if (*set++ <= c && c <= *set++)
X return(1);
X n -= 3;
X continue;
X
X default:
X return(GLOB_EXECUTION_ERROR);
X }
X return(0);
X}
X
X#define IS_RANGE(s) (s[1] && s[2] && s[1] == '-' && s[2] != ']')
X
X/* compiles a set returning the number of pattern characters consumed */
Xstatic int compile_set (pattern, x, limit)
Xchar *pattern;
Xchar *x;
Xchar *limit;
X{
X char *slot; /* size of set goes here */
X int size; /* number of bytes in compiled set */
X char *start = pattern;
X
X if (*pattern == 0)
X return(GLOB_BRACKET_MISSING);
X
X *x++ = PATTERN_SET;
X slot = x++;
X size = 0;
X
X if (IS_RANGE(pattern)) {
X if (pattern[0] > pattern[2]) /* pattern[1] == '-' */
X return(GLOB_RANGE_INVERTED);
X *x++ = PATTERN_SET_RANGE;
X *x++ = pattern[0];
X *x++ = pattern[2];
X pattern += 3;
X size += 3;
X } else {
X *x++ = PATTERN_SET_MEMBER;
X *x++ = *pattern++;
X size += 2;
X }
X
X while (*pattern != ']' && x < limit) {
X if (*pattern == 0)
X return(GLOB_BRACKET_MISSING);
X if (IS_RANGE(pattern)) {
X if (pattern[0] > pattern[2]) /* pattern[1] == '-' */
X return(GLOB_RANGE_INVERTED);
X *x++ = PATTERN_SET_RANGE;
X *x++ = pattern[0];
X *x++ = pattern[2];
X pattern += 3;
X size += 3;
X } else {
X *x++ = PATTERN_SET_MEMBER;
X *x++ = *pattern++;
X size += 2;
X }
X }
X if (size > MAX_SET)
X return(GLOB_SET_TOO_BIG);
X *slot = size;
X return(pattern - start);
X}
!FaR!OuT!
if [ ! -d libglob ]
then
mkdir libglob
echo mkdir libglob
fi
echo x - libglob/glob.h
sed -e 's/^X//' > libglob/glob.h << '!FaR!OuT!'
X/* @(#)glob.h 1.1 (TRW) 1/14/86 */
X#define GLOB_MAX_PATTERN 1024
X#define GLOB_OK 0
X#define GLOB_PATTERN_TOO_BIG -1
X#define GLOB_PATTERN_EMPTY -2
X#define GLOB_BRACKET_MISSING -3
X#define GLOB_RANGE_INVERTED -4
X#define GLOB_SET_TOO_BIG -5
X#define GLOB_EXECUTION_ERROR -6
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/Makefile
sed -e 's/^X//' > libprofile/Makefile << '!FaR!OuT!'
X# @(#)Makefile 1.1 (TRW) 1/14/86
XCFLAGS = -O
XOBJECTS = boolean.o free.o has.o read.o space.o write.o
XDEST = /usr/local
X
X.c.o:
X ${CC} ${CFLAGS} -c $*.c
X -ld -r -x $*.o
X mv a.out $*.o
X
Xall: libprofile.a
X
Xlibprofile.a: ${OBJECTS}
X ar cr libprofile.a ${OBJECTS}
X ranlib libprofile.a
X chmod 644 libprofile.a
X
Xinstall: all
X mv libprofile.a ${DEST}/lib
X ranlib ${DEST}/lib/libprofile.a
X install -c profile.h /usr/include/local
X
Xclean:
X rm -f *.o
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/boolean.c
sed -e 's/^X//' > libprofile/boolean.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)boolean.c 1.1 (TRW) 1/14/86";
X#include <ctype.h>
X#include "profile.h"
X
Xstatic char *Yes[] = {
X "yes",
X "on",
X "true",
X "enable",
X "available",
X "present",
X 0
X};
X
Xstatic char *No[] = {
X "no",
X "off",
X "false",
X "disable",
X "unavailable",
X "absent",
X 0
X};
X
Xint profile_boolean (v)
XPROFILE_VALUE *v;
X{
X char x[16];
X int i;
X
X if (v == 0)
X return(0);
X
X switch (v->class) {
X case PROFILE_OTHER:
X case PROFILE_STRING:
X strncpy(x, v->value.s, sizeof(x)-1);
X x[sizeof(x)-1] = 0;
X downshift(x);
X for (i = 0; Yes[i]; i++)
X if (strcmp(x, Yes[i]) == 0)
X return(1);
X else if (strcmp(x, No[i]) == 0)
X return(0);
X return(-1); /* unknown string */
X
X case PROFILE_HEX:
X case PROFILE_INTEGER:
X case PROFILE_OCTAL:
X return(v->value.i != 0);
X
X case PROFILE_CHARACTER:
X return(v->value.c != 0);
X
X case PROFILE_FLOAT:
X return(v->value.f != 0.0);
X
X default:
X return(-1); /* unknown class */
X }
X}
X
X/* downshift a string in place */
Xstatic downshift (s)
Xchar *s;
X{
X for (; *s; s++)
X if (isupper(*s))
X *s = tolower(*s);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/free.c
sed -e 's/^X//' > libprofile/free.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)free.c 1.1 (TRW) 1/14/86";
X#include "profile.h"
X
Xprofile_free_profile (s)
XPROFILE_STANZA *s;
X{
X PROFILE_STANZA *x;
X
X for (x = s; x != (PROFILE_STANZA *)0 && x != s; x = x->next)
X profile_free_stanza(x);
X}
X
Xprofile_free_stanza (s)
XPROFILE_STANZA *s;
X{
X free_markers(s->marker);
X free_bindings(s->binding);
X free(s);
X}
X
Xstatic free_markers (m)
XPROFILE_MARKER *m;
X{
X PROFILE_MARKER *x;
X
X for (; m; m = x) {
X x = m->next;
X free(m);
X }
X}
X
Xstatic free_bindings (b)
XPROFILE_BINDING *b;
X{
X PROFILE_BINDING *x;
X
X for (; b; b = x) {
X x = b->next;
X free_values(b->value);
X free(b);
X }
X}
X
Xstatic free_values (v)
XPROFILE_VALUE *v;
X{
X PROFILE_VALUE *x;
X
X for (; v; v = x) {
X x = v->next;
X free(v);
X }
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/has.c
sed -e 's/^X//' > libprofile/has.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)has.c 1.1 (TRW) 1/14/86";
X#include <stdio.h>
X#include "profile.h"
X
XPROFILE_MARKER *profile_has_marker (s, m)
XPROFILE_STANZA *s;
Xchar *m;
X{
X PROFILE_MARKER *x;
X int result;
X
X for (x = s->marker; x; x = x->next)
X if(glob_match(x->text, m) > 0)
X return(x);
X return((PROFILE_MARKER *)0);
X}
X
X/*
X * read down a linked list of stanzas looking
X * for a stanza that has the requested markers
X */
XPROFILE_STANZA *profile_has_stanza(s, marker)
XPROFILE_STANZA *s;
Xchar *marker[]; /* terminated by a null pointer */
X{
X int i;
X PROFILE_STANZA *x;
X
X if (s == NULL)
X return(s);
X x = s;
X do {
X for (i = 0; marker[i] != NULL; i++)
X if (profile_has_marker(x, marker[i]) == NULL)
X break;
X if (marker[i] == NULL)
X return(x);
X x = x->next;
X } while (x != s && x != NULL);
X
X return((PROFILE_STANZA *)NULL);
X}
X
XPROFILE_BINDING *profile_has_binding (s, b)
XPROFILE_STANZA *s;
Xchar *b;
X{
X PROFILE_BINDING *x;
X
X for (x = s->binding; x; x = x->next)
X if (glob_match(x->name, b) > 0)
X return(x);
X return((PROFILE_BINDING *)0);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/profile.3
sed -e 's/^X//' > libprofile/profile.3 << '!FaR!OuT!'
X.\" %W% (TRW) %G%
X.TH PROFILE 3 TRW
X.UC 4
X.SH NAME
Xprofile \- read/write configuration files
X.SH SYNOPSIS
X.nf
X.B #include <stdio.h>
X.B #include <local/profile.h>
X
X.B PROFILE_STANZA *profile_read_stanza(f)
X.B FILE *f;
X
X.B PROFILE_STANZA *profile_read_profile(f)
X.B FILE *f;
X
X.B profile_write_stanza(f, s)
X.B FILE *f;
X.B PROFILE_STANZA *s;
X
X.B profile_write_profile(f, s)
X.B FILE *f;
X.B PROFILE_STANZA *s;
X
X.B profile_free_stanza(s)
X.B PROFILE_STANZA *s;
X
X.B PROFILE_MARKER *profile_has_marker(s, m)
X.B PROFILE_STANZA *s;
X.B char *m;
X
X.B PROFILE_STANZA *profile_has_stanza(s, marker)
X.B PROFILE_STANZA *s;
X.B char *marker[];
X
X.B PROFILE_BINDING *profile_has_binding(s, b)
X.B PROFILE_STANZA *s;
X.B char *b;
X
X.B PROFILE_STANZA *profile_stanza_space()
X
X.B PROFILE_MARKER *profile_marker_space(n)
X.B int n;
X
X.B PROFILE_BINDING *profile_binding_space(n)
X.B int n;
X
X.B PROFILE_VALUE *profile_value_space(n)
X.B int n;
X.fi
X.SH DESCRIPTION
X.I Profile_read_stanza
Xreads a single stanza from a configuration file returning
Xa pointer to the stanza if successful and NULL on error or end of file.
XA stanza is defined as:
X.nf
X.ta 1i +\w'typedef 'u
X
X typedef struct PROFILE_STANZA {
X PROFILE_MARKER *marker;
X PROFILE_BINDING *binding;
X struct PROFILE_STANZA *previous;
X struct PROFILE_STANZA *next;
X } PROFILE_STANZA;
X.fi
X.PP
X.I Marker
Xand
X.I binding
Xpoint to linked lists of markers and bindings respectively.
XIf
X.I marker
Xis
X.B NULL
Xthe stanza has no markers.
XIf
X.I binding
Xis
X.B NULL
Xthe stanza has no bindings.
X.I Previous
Xand
X.I next
Xare ignored and may be used to doubly link successive stanzas together.
X.DT
X.PP
XA marker is defined as:
X.nf
X.ta 1i +\w'typedef 'u
X
X typedef struct PROFILE_MARKER {
X char *text;
X struct PROFILE_MARKER *previous;
X struct PROFILE_MARKER *next;
X } PROFILE_MARKER;
X.fi
X.DT
X.PP
X.I Text
Xis a string containing the literal text of the marker
Xand is always nonempty.
X.IR Previous " (" next )
Xis a pointer to the previous (next) marker in the sequence.
XIn the first (last) marker
X.IR previous " (" next )
Xis
X.BR NULL .
X.PP
XA binding is defined as:
X.nf
X.ta 1i +\w'typedef 'u
X
X typedef struct PROFILE_BINDING {
X char *name;
X PROFILE_VALUE *value;
X struct PROFILE_BINDING *previous;
X struct PROFILE_BINDING *next;
X } PROFILE_BINDING;
X.fi
X.DT
X.PP
X.I Name
Xis the literal text of the name of the binding and is always nonempty.
X.I Value
Xis a pointer to the list of values associated with the name.
XIf
X.I value
Xis
X.B NULL
Xthen the binding consists solely of a name with no associated value.
X.IR Previous " (" next )
Xpoints to the previous (next) binding in the sequence.
XIn the first (last) binding
X.IR previous " (" next )
Xis
X.BR NULL .
X.PP
XA value is defined as:
X.nf
X.ta 1i +\w'typedef 'u +\w'union { 'u
X
X typedef struct PROFILE_VALUE {
X char class;
X union {
X long int i;
X double f;
X char c;
X char *s;
X } value;
X struct PROFILE_VALUE *previous;
X struct PROFILE_VALUE *next;
X } PROFILE_VALUE;
X.fi
X.DT
X.PP
X.I Class
Xis always one of:
X.TP
XPROFILE_CHARACTER
Xthe value is a character constant contained in
X.IR c .
X.TP
XPROFILE_HEX
Xthe value is a hex constant contained in
X.IR i .
X.TP
XPROFILE_INTEGER
Xthe value is an integer constant contained in
X.IR i .
X.TP
XPROFILE_FLOAT
Xthe value is a real constant contained in
X.IR f .
X.TP
XPROFILE_OCTAL
Xthe value is an octal constant contained in
X.IR i .
X.TP
XPROFILE_STRING
Xthe value is a string constant contained in
X.IR s .
X.TP
XPROFILE_OTHER
Xthe value is not recognizably
Xcharacter,
Xhex,
Xinteger,
Xfloat,
Xoctal
Xor string.
XThe literal text is contained in
X.IR s .
X.PP
X.IR Previous " (" next )
Xpoints to the previous (next) value in the sequence.
XIn the first (last) value
X.IR previous " (" next )
Xis
X.BR NULL .
X.PP
X.I Profile_read_profile
Xreads an entire configuration file and builds a bi-directional,
Xcircularly linked list of stanzas using the
X.I previous
Xand
X.I next
Xpointers.
XThe value returned is a pointer to the first stanza in the list.
X.PP
X.I Profile_write_stanza
Xwrites a stanza in a canonical form suitable for input by
X.IR profile_read_stanza .
XMarkers are output one to a line.
XEach binding is indented by a single tab.
XNames and values are separated, one from the other,
Xby a single blank.
X.PP
X.I Profile_write_profile
Xwrites all the stanzas in a linked list by applying
X.I profile_write_stanza
Xto each stanza in the list.
XThe list need not be doubly linked.
X.PP
X.I Profile_free_stanza
Xfrees all storage associated with a stanza.
X.PP
X.I Profile_has_marker
Xsearches the marker list of a stanza for a match to the given marker,
X.IR m .
XA pointer to the marker is returned on success and
X.B NULL
Xon failure.
X.PP
X.I Profile_has_stanza
Xsearches a linked list of stanzas for a stanza that has all the
Xmarkers in
X.I marker.
X.I Marker
Xmust be terminated by a null entry.
X.PP
X.I Profile_has_binding
Xsearches the binding list of a stanza
Xfor a binding with a match to the given name.
XA pointer to the binding is returned on success and
X.B NULL
Xon failure.
X.PP
XThe following routines are useful for constructing stanzas on the fly.
X.I Profile_stanza_space
Xallocates storage for a stanza.
X.I Profile_marker_space
Xallocates storage for a marker including sufficient space for
X.I n
Xcharacters of text plus a terminating null byte.
X.I Profile_binding_space
Xallocates storage for a binding including sufficient space for
X.I n
Xcharacters of name text plus a terminating null byte.
X.I Profile_value_space
Xallocates storage for a value.
XIf
X.I n
Xis positive and non-zero the component
X.IR value . s
Xis initialized as a
X.IR n +1
Xcharacter array.
XAll of the above routines return a pointer on success and
X.B NULL
Xon failure.
XAll storage is zero filled.
XThe routine
X.IR free (3)
Xmay be safely used to release storage allocated by these routines.
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xmalloc(3), profile(5)
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/profile.5
sed -e 's/^X//' > libprofile/profile.5 << '!FaR!OuT!'
X.\" @(#)profile.5 1.1 (TRW) 6/11/84
X.TH PROFILE 5 TRW
X.UC 4
X.SH NAME
Xprofile \- configuration file format
X.SH SYNOPSIS
X.B #include <local/profile.h>
X.SH DESCRIPTION
X.I Profile
Xis a general purpose configuration file facility.
X.PP
XEach profile is an ASCII file containing a sequence of one or more
X.IR stanzas .
XEach stanza in turn consists of a sequence of
X.I markers
Xfollowed by a sequence of
X.IR bindings .
XThe characters `{' (left brace) and `}' (right brace)
Xdelimit the beginning and end respectively of the stanza bindings.
XEach binding consists of a name
Xfollowed by an optional sequence of values.
X.SH MARKERS
XMarkers are arbitrary patterns in the style of
X.IR glob (3)
Xdelimited by white space.
XThe list of markers may be empty.
XThere is no limit to the number of markers.
XExamples of markers are:
X.nf
X
X queue
X /usr/lib
X 1776
X a_long_marker
X file[0-9]*.?
X.fi
X.SH BINDINGS
XBindings are the association of names with values.
XThere is one binding to a line each consisting of a name followed
Xby an optional sequence of values.
XNames and values are separated,
Xone from the other,
Xby blanks or tabs.
XHere a newline preceded by a backslash is equivalent to a blank.
XThe list of bindings may be empty.
XThere is no limit to the number of bindings.
XBy convention each binding is indented by a single tab.
X.SH NAMES
XNames are arbitrary patterns in the style of
X.IR glob (3)
Xdelimited by white space.
X.SH VALUES
XValues are
Xinteger,
Xreal,
Xoctal,
Xhex,
Xcharacter,
Xor
Xstring
Xconstants.
XArbitrary text,
Xnot recognizably one of the aforementioned types,
Xis classified as
X.I other
Xand is a legitimate value.
X.TP
Xinteger
XA sequence of digits optionally preceded by a minus sign.
XEvery integer constant is taken to be long.
X.TP
Xfloating
XA floating constant consists of an optional minus sign,
Xan integer part
Xa decimal point,
Xa fraction part,
Xan
X.B e
Xor
X.BR E ,
Xand an optionally signed integer exponent.
XThe integer and fraction parts both consist of a sequence of digits.
XEither the integer part or the fraction part (not both)
Xmay be missing;
Xeither the decimal point or the
X.B e
Xand the exponent (not both) may be missing.
XEvery floating constant is taken to be double-precision.
X.TP
Xhex
XA sequence of hexidecimal digits preceded by
X.B 0x
Xor
X.BR 0X .
XThe hexidecimal digits are 0-9, a-e and A-F.
XEvery hex constant is taken to be long.
X.TP
Xoctal
XA sequence of octal digits preceded by
X.B 0o
Xor
X.B 0O
X(digit zero followed by a letter o).
XThe octal digits are 0-7.
XEvery octal constant is taken to be long.
X.TP
Xcharacter
XA character constant is a character enclosed in single quotes.
XCertain non-graphic characters,
Xthe single quote ',
Xthe caret ^ and
Xthe backslash \\,
Xmay be represented according to the following table of escape sequences:
X.ta 1i +\w'carriage return 'u
X.nf
X
X newline \\n
X horizontal tab \\t
X backspace \\b
X carriage return \\r
X form feed \\f
X escape \\e
X backslash \\\\
X single quote \\'
X caret \\^
X control-@ ^@
X control-A ^A
X ... ...
X control-Z ^Z
X control-[ ^[
X control-\\ ^\\
X control-^ ^^
X control-_ ^_
X delete ^?
X bit pattern \\\fIddd\fR
X
X.fi
X.DT
XThe escape \\\fIddd\fR
Xconsists of the backslash followed by 1, 2, or 3 octal digits
Xwhich are taken to specify the value of the desired character.
XIf the character following a backslash (caret) is not one of those
Xspecified, the backslash (caret) is ignored.
X.TP
Xstring
XA string is a sequence of characters surrounded by double quotes, as in
X\fB"..."\fR.
XIn a string,
Xthe double quote character \fB"\fR must be preceded by a \\;
Xin addition,
Xthe same escapes as described for character constants may be used.
X.PP
XExamples of values are:
X.nf
X
X 7
X -1.293e3
X 0x10a5
X 0o1273
X 'x'
X "a string"
X an_other_value
X.fi
X.SH COMMENTS
XComments may appear anywhere within a profile.
XThey are introduced by the character `#' and are terminated by
Xthe succeeding newline.
X.SH EXAMPLES
XThe empty stanza.
X.nf
X
X{
X}
X.fi
X.PP
XA stanza in the configuration file of a fictitious network server.
X.nf
X.ta \w'queue 'u +\w'cost_per_packet 'u +\w'0o125 0x1af 'u
X
Xqueue net*
X{
X priority 7 # integer
X expect "who is it" # string
X send '?' # character
X flags[0-9] 0o125 0x1af # octal and hex
X cost_per_packet 0.28 # floating
X device /dev/net # other
X homebrew # a name with no associated value
X}
X.fi
X.DT
X.PP
XA password file entry recast as a stanza.
X.nf
X.ta \w'brown 'u +\w'password 'u
X
Xbrown
X{
X password /bObOZtyGclMV
X userid 225
X groupid 30
X home /home/brown
X shell /bin/csh
X}
X.fi
X.DT
X.PP
XA termcap entry recast as a stanza.
X.nf
X.ta \w'adm3a 'u +\w'mm 'u
X
Xadm3a
X{
X fullname "lsi adm3a"
X am
X bs
X cm "\\e=%+ %+ "
X cl "1^Z"
X co 80
X li 24
X ho '^^'
X ma "^K^P"
X nd '^L'
X up '^K'
X}
X.fi
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xglob(3), profile(3)
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/profile.h
sed -e 's/^X//' > libprofile/profile.h << '!FaR!OuT!'
X/* @(#)profile.h 1.1 (TRW) 1/14/86 */
Xtypedef struct PROFILE_VALUE {
X char class;
X union {
X long int i;
X double f;
X char c;
X char *s;
X } value;
X struct PROFILE_VALUE *previous;
X struct PROFILE_VALUE *next;
X} PROFILE_VALUE;
X
Xtypedef struct PROFILE_BINDING {
X char *name;
X PROFILE_VALUE *value;
X struct PROFILE_BINDING *previous;
X struct PROFILE_BINDING *next;
X} PROFILE_BINDING;
X
Xtypedef struct PROFILE_MARKER {
X char *text;
X struct PROFILE_MARKER *previous;
X struct PROFILE_MARKER *next;
X} PROFILE_MARKER;
X
Xtypedef struct PROFILE_STANZA {
X PROFILE_MARKER *marker;
X PROFILE_BINDING *binding;
X struct PROFILE_STANZA *previous;
X struct PROFILE_STANZA *next;
X} PROFILE_STANZA;
X
X/* classes */
X#define PROFILE_INTEGER 01
X#define PROFILE_FLOAT 02
X#define PROFILE_STRING 03
X#define PROFILE_CHARACTER 04
X#define PROFILE_OTHER 05
X#define PROFILE_OCTAL 06
X#define PROFILE_HEX 07
X
X/* no single lexical element may exceed this size in characters */
X#define PROFILE_MAX_TEXT 255
X
XPROFILE_STANZA *profile_read_stanza();
XPROFILE_STANZA *profile_read_profile();
XPROFILE_MARKER *profile_has_marker();
XPROFILE_STANZA *profile_has_stanza();
XPROFILE_BINDING *profile_has_binding();
XPROFILE_STANZA *profile_stanza_space();
XPROFILE_MARKER *profile_marker_space();
XPROFILE_BINDING *profile_binding_space();
XPROFILE_VALUE *profile_value_space();
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/read.c
sed -e 's/^X//' > libprofile/read.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)read.c 1.1 (TRW) 1/14/86";
X#include <stdio.h>
X#include <ctype.h>
X#include "profile.h"
X
X#define isoctal(d) ('0' <= d && d <= '7')
X#define ishex(x) (isdigit(x) || ('a' <= x && x <= 'f') || ('A' <= x && x <= 'F'))
X#define isprime(c) (c == '\'')
X#define isbackslash(c) (c == '\\')
X#define iscaret(c) (c == '^')
X
Xextern char *strcpy();
Xextern PROFILE_STANZA *profile_stanza_space();
Xextern PROFILE_MARKER *profile_marker_space();
Xextern PROFILE_BINDING *profile_binding_space();
Xextern PROFILE_VALUE *profile_value_space();
X
Xstatic PROFILE_BINDING *get_binding();
Xstatic PROFILE_BINDING *get_bindings();
Xstatic PROFILE_MARKER *get_marker();
Xstatic PROFILE_MARKER *get_markers();
Xstatic PROFILE_VALUE *get_value();
Xstatic PROFILE_VALUE *get_values();
Xstatic char parse_character();
Xstatic PROFILE_VALUE *parse_value();
X
XPROFILE_STANZA *profile_read_stanza (f)
XFILE *f;
X{
X PROFILE_STANZA *stanza;
X
X stanza = profile_stanza_space();
X if (stanza == NULL)
X return(NULL);
X stanza->marker = get_markers(f);
X if (get_open_bindings(f))
X stanza->binding = get_bindings(f);
X else {
X profile_free_stanza(stanza);
X return(NULL);
X }
X if (get_close_bindings(f))
X return(stanza);
X else {
X profile_free_stanza(stanza);
X return(NULL);
X }
X}
X
X/* Returns the list of markers at the head of a stanza. */
Xstatic PROFILE_MARKER *get_markers (f)
XFILE *f;
X{
X PROFILE_MARKER *head, *tail, *m;
X
X head = tail = NULL;
X while (m = get_marker(f))
X if (tail) {
X tail->next = m;
X m->previous = tail;
X tail = m;
X } else
X head = tail = m;
X return(head);
X}
X
X/* Returns the next marker from the head of the stanza. */
Xstatic PROFILE_MARKER *get_marker (f)
XFILE *f;
X{
X int n;
X PROFILE_MARKER *m;
X char scratch[PROFILE_MAX_TEXT+1];
X
X for (;;)
X if (n = get_name_text(f, scratch)) {
X if ((m = profile_marker_space(n)) == NULL)
X return(NULL);
X strcpy(m->text, scratch);
X return(m);
X } else if (get_end_of_line(f))
X continue;
X else
X return(NULL);
X}
X
X/* Returns the list of bindings in the body of the stanza. */
Xstatic PROFILE_BINDING *get_bindings (f)
XFILE *f;
X{
X PROFILE_BINDING *head, *tail, *b;
X
X head = tail = NULL;
X while (b = get_binding(f))
X if (tail) {
X tail->next = b;
X b->previous = tail;
X tail = b;
X } else
X head = tail = b;
X return(head);
X}
X
X/* Returns the next binding in the body of the stanza. */
Xstatic PROFILE_BINDING *get_binding (f)
XFILE *f;
X{
X int n;
X PROFILE_BINDING *b;
X char scratch[PROFILE_MAX_TEXT+1];
X
X for (;;)
X if (n = get_name_text(f, scratch)) {
X if ((b = profile_binding_space(n)) == NULL)
X return(NULL);
X strcpy(b->name, scratch);
X break;
X } else if (get_end_of_line(f))
X continue;
X else
X return(NULL);
X b->value = get_values(f);
X return(b);
X}
X
X/* Returns the list of values following the name of the binding. */
Xstatic PROFILE_VALUE *get_values (f)
XFILE *f;
X{
X PROFILE_VALUE *head, *tail, *v;
X
X head = tail = NULL;
X while (v = get_value(f))
X if (tail) {
X tail->next = v;
X v->previous = tail;
X tail = v;
X } else
X head = tail = v;
X return(head);
X}
X
X/* Returns the next value in the binding. */
Xstatic PROFILE_VALUE *get_value (f)
XFILE *f;
X{
X char text[PROFILE_MAX_TEXT+1];
X int n;
X
X for (;;)
X if (n = get_value_text(f, text))
X return(parse_value(text, n));
X else if (get_end_of_line(f))
X return(NULL);
X else
X return(NULL);
X}
X
X/*
X * Reads the text of the next value (if any) in the binding. Returns
X * the length of the literal text in characters.
X */
Xstatic int get_value_text (f, text)
XFILE *f;
Xchar *text;
X{
X register int c;
X char *s = text;
X
X while ((c = getc(f)) != EOF)
X switch (c) {
X case '\b': case '\f':
X case '\r': case '\t': case ' ':
X /* white space terminates any text gathered so far */
X if (s > text) {
X *s = '\0';
X return(s - text);
X }
X continue;
X
X case '\n':
X /* newline terminates a binding */
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X case '#':
X /* gobble up the comment */
X while ((c = getc(f)) != EOF && c != '\n')
X continue;
X if (c == '\n')
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X case '{': case '}':
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X case '"': /* string quotes */
X ungetc(c, f);
X if (s > text) {
X *s = '\0';
X return(s - text);
X } else
X return(get_string(f, s));
X
X case '\'': /* character quotes */
X ungetc(c, f);
X if (s > text) {
X *s = '\0';
X return(s - text);
X } else
X return(get_character(f, s));
X
X case '\\': /* newline escape */
X c = getc(f);
X if (c == '\n') {
X if (s > text) {
X *s = '\0';
X return(s - text);
X }
X continue; /* just like a blank */
X }
X ungetc(c, f);
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = '\\';
X continue;
X
X default:
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X continue;
X }
X *s = '\0';
X return(s - text);
X}
X
X/* Digests the raw value text returning a new value structure. */
Xstatic PROFILE_VALUE *parse_value (s, length)
Xchar *s; /* literal text */
Xint length; /* in characters */
X{
X PROFILE_VALUE *v;
X
X if (is_integer(s)) {
X if ((v = profile_value_space(0)) == NULL)
X return(NULL);
X v->class = PROFILE_INTEGER;
X sscanf(s, "%D", &v->value.i);
X } else if (is_octal(s)) {
X if ((v = profile_value_space(0)) == NULL)
X return(NULL);
X v->class = PROFILE_OCTAL;
X /* skip the `0o' prefix */
X sscanf(s+2, "%O", &v->value.i);
X } else if (is_hex(s)) {
X if ((v = profile_value_space(0)) == NULL)
X return(NULL);
X v->class = PROFILE_HEX;
X /* skip the `0x' prefix */
X sscanf(s+2, "%X", &v->value.i);
X } else if (is_string(s)) {
X /* be careful when dealing with the empty string "" */
X if ((v = profile_value_space(length > 2 ? length - 2 : 1)) == NULL)
X return(NULL);
X v->class = PROFILE_STRING;
X /* erase the terminating double quote */
X s[length - 1] = '\0';
X /* skip past the initial quote */
X parse_string(s + 1, v->value.s);
X } else if (is_character(s)) {
X if ((v = profile_value_space(0)) == NULL)
X return(NULL);
X v->class = PROFILE_CHARACTER;
X /* erase the end single quote */
X s[length - 1] = '\0';
X v->value.c = parse_character(s + 1);
X } else if (is_float(s)) {
X if ((v = profile_value_space(0)) == NULL)
X return(NULL);
X v->class = PROFILE_FLOAT;
X sscanf(s, "%E", &v->value.f);
X } else {
X if ((v = profile_value_space(length)) == NULL)
X return(NULL);
X v->class = PROFILE_OTHER;
X strcpy(v->value.s, s);
X }
X return(v);
X}
X
X/* Converts a string literal to the internal representation. */
Xstatic parse_string (source, result)
Xchar *source;
Xchar *result;
X{
X for (; *source; source++)
X if (*source == '\\')
X switch (*++source) {
X case 'b': /* backspace */
X *result++ = '\b';
X continue;
X case 'f': /* formfeed */
X *result++ = '\f';
X continue;
X case 'n': /* newline */
X *result++ = '\n';
X continue;
X case 'r': /* carriage return */
X *result++ = '\r';
X continue;
X case 't': /* horizontal tab */
X *result++ = '\t';
X continue;
X case '\'': /* single quote */
X *result++ = '\'';
X continue;
X case '"': /* double quote */
X *result++ = '"';
X continue;
X case '\\': /* backslash */
X *result++ = '\\';
X continue;
X case '^': /* caret */
X *result++ = '^';
X continue;
X case '0': case '1': /* octal constant */
X case '2': case '3':
X case '4': case '5':
X case '6': case '7':
X source += parse_octal(source, result) - 1;
X result++;
X continue;
X default:
X *result++ = *source; /* ignore backslash */
X }
X else if (*source == '^') { /* control escape */
X char c = *++source;
X *result++ = ('@' <= c && c <= '_') ? c - '@' :
X (c == '?') ? '\177' : c;
X continue;
X } else
X *result++ = *source;
X *result = '\0';
X}
X
X/* Converts a character literal to the internal representation. */
Xstatic char parse_character (source)
Xchar *source;
X{
X char c;
X
X if (*source == '\\')
X switch (*++source) {
X case 'b': /* backspace */
X return('\b');
X case 'f': /* formfeed */
X return('\f');
X case 'n': /* newline */
X return('\n');
X case 'r': /* carriage return */
X return('\r');
X case 't': /* horizontal tab */
X return('\t');
X case '\'': /* single quote */
X return('\'');
X case '\\': /* backslash */
X return('\\');
X case '^':
X return('^');
X case '0': case '1': /* octal constant */
X case '2': case '3':
X case '4': case '5':
X case '6': case '7':
X parse_octal(source, &c);
X return(c);
X default:
X return(*source); /* ignore backslash */
X }
X else if (*source == '^') { /* control escape */
X c = *++source;
X return(('@' <= c && c <= '_') ? c - '@' : (c == '?') ? '\177' : c);
X } else
X return(*source);
X}
X
X/* Converts an octal escape `\ddd' to its byte representation. */
Xstatic int parse_octal (source, result)
Xchar *source;
Xchar *result;
X{
X int count;
X char byte = '\0';
X char digit;
X
X for (count = 1; count <= 3; count++) {
X digit = *source++;
X if ('0' <= digit && digit <= '7')
X byte = (byte * 8) + (digit - '0');
X else
X break;
X }
X *result = byte;
X return(count);
X}
X
X/*
X * Reads the literal text for markers and binding names. Returns the
X * length in characters of the literal text.
X */
Xstatic int get_name_text (f, text)
XFILE *f;
Xchar *text;
X{
X register int c;
X char *s = text;
X
X while ((c = getc(f)) != EOF)
X switch (c) {
X case '\b': case '\f':
X case '\r': case '\t': case ' ':
X /* white space terminates text gathered so far */
X if (s > text) {
X *s = '\0';
X return(s - text);
X }
X continue;
X
X case '\n':
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X case '#':
X /* gobble up the comment */
X while ((c = getc(f)) != EOF && c != '\n')
X continue;
X if (c == '\n')
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X case '{': case '}':
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X case '[':
X /* sets may contain embedded white space */
X if (s + 1 < &text[PROFILE_MAX_TEXT]) {
X *s++ = '[';
X if ((c = getc(f)) != EOF)
X *s++ = c;
X }
X while ((c = getc(f)) != EOF) {
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X if (c == ']')
X break;
X }
X continue;
X
X case '\\':
X c = getc(f);
X if (c == '\n') {
X if (s > text) {
X *s = '\0';
X return(s - text);
X }
X continue; /* just like a blank */
X }
X ungetc(c, f);
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = '\\';
X continue;
X
X default:
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X continue;
X }
X *s = '\0';
X return(s - text);
X}
X
X/* Returns non-zero on end of line and zero otherwise. */
Xstatic int get_end_of_line (f)
XFILE *f;
X{
X int c;
X
X if ((c = getc(f)) == '\n')
X return(1);
X ungetc(c, f);
X return(0);
X}
X
X/* Returns non-zero on seeing `{' and zero otherwise. */
Xstatic int get_open_bindings (f)
XFILE *f;
X{
X int c;
X
X if ((c = getc(f)) == '{')
X return(1);
X ungetc(c, f);
X return(0);
X}
X
X/* Returns non-zero on seeing `}' and zero otherwise. */
Xstatic int get_close_bindings (f)
XFILE *f;
X{
X int c;
X
X if ((c = getc(f)) == '}')
X return(1);
X ungetc(c, f);
X return(0);
X}
X
X/* Reads a string literal returning the length of the literal text in characters */
Xstatic int get_string (f, text)
XFILE *f;
Xchar *text;
X{
X register int c;
X char *s = text;
X
X /* the first double quote is guaranteed */
X *s++ = getc(f);
X while ((c = getc(f)) != EOF)
X switch (c) {
X case '\\':
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X c = getc(f);
X if (c == EOF)
X return(s - text);
X else if (c == '\n') {
X ungetc(c, f);
X return(s - text);
X } else if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X continue;
X
X case '"':
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X *s = '\0';
X return(s - text);
X
X case '\n':
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X
X default:
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X continue;
X }
X *s = '\0';
X return(s - text);
X}
X
X/* Reads a character literal returning the length of the literal text in characters. */
Xstatic int get_character (f, text)
XFILE *f;
Xchar *text;
X{
X register int c;
X char *s = text;
X
X /* the first single quote is guaranteed */
X *s++ = getc(f);
X while ((c = getc(f)) != EOF)
X switch (c) {
X case '\\':
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X c = getc(f);
X if (c == EOF)
X return(s - text);
X else if (c == '\n') {
X ungetc(c, f);
X return(s - text);
X } else if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X continue;
X case '\'':
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X *s = '\0';
X return(s - text);
X case '\n':
X ungetc(c, f);
X *s = '\0';
X return(s - text);
X default:
X if (s < &text[PROFILE_MAX_TEXT])
X *s++ = c;
X continue;
X }
X *s = '\0';
X return(s - text);
X}
X
X/* all regular expressions below are in lex notation */
X
X/* returns non-zero iff -?[0-9]+ matches */
Xstatic int is_integer (s)
Xchar *s;
X{
X char *x;
X
X /* -? */
X if (*s == '-')
X s++;
X /* [0-9]+ */
X for (x = s; isdigit(*s); s++)
X continue;
X return(s > x && !*s);
X}
X
X/* returns non-zero iff 0[oO][0-7]+ matches */
Xstatic int is_octal (s)
Xchar *s;
X{
X char *x;
X
X /* 0 */
X if (*s == '0')
X s++;
X else
X return(0);
X /* [oO] */
X if (*s == 'o' || *s == 'O')
X s++;
X else
X return(0);
X /* [0-7]+ */
X for (x = s; isoctal(*s); s++)
X continue;
X return(s > x && !*s);
X}
X
X/* returns non-zero iff 0[xX][0-9a-fA-F]+ matches */
Xstatic int is_hex (s)
Xchar *s;
X{
X char *x;
X
X /* 0 */
X if (*s == '0')
X s++;
X else
X return(0);
X /* [xX] */
X if (*s == 'x' || *s == 'X')
X s++;
X else
X return(0);
X /* [0-9a-fA-F]+ */
X for (x = s; ishex(*s); s++)
X continue;
X return(s > x && !*s);
X}
X
X/* returns non-zero iff [eE][-+]?[0-9]+ matches */
Xstatic int is_exponent (s)
Xchar *s;
X{
X char *x;
X
X /* [eE] */
X if (*s == 'e' || *s == 'E')
X s++;
X else
X return(0);
X /* [-+]? */
X if (*s == '-' || *s == '+')
X s++;
X /* [0-9]+ */
X for (x = s; isdigit(*s); s++)
X continue;
X return(s > x && !*s);
X}
X
Xstatic int is_float (s)
Xchar *s;
X{
X return(is_integer_part_float(s) ||
X is_fractional_part_float(s) ||
X is_power_float(s));
X}
X
X/* returns non-zero iff -?[0-9]+"."[0-9]*({exponent})? matches */
Xstatic int is_integer_part_float (s)
Xchar *s;
X{
X char *x;
X
X /* -? */
X if (*s == '-')
X s++;
X /* [0-9]+"." */
X for (x = s; isdigit(*s); s++)
X continue;
X if (x == s || *s != '.')
X return(0);
X /* [0-9]* */
X for (s++; isdigit(*s); s++)
X continue;
X /* ({exponent})? */
X return(*s ? is_exponent(s) : 1);
X}
X
X/* returns non-zero iff -?"."[0-9]+({exponent})? matches */
Xstatic int is_fractional_part_float (s)
Xchar *s;
X{
X char *x;
X
X /* -? */
X if (*s == '-')
X s++;
X /* "." */
X if (*s == '.')
X s++;
X else
X return(0);
X /* [0-9]+({exponent})? */
X for (x = s; isdigit(*s); s++)
X continue;
X return(s > x ? !*s || is_exponent(s) : 0);
X}
X
X/* returns non-zero iff -?[0-9]+{exponent} matches */
Xstatic int is_power_float (s)
Xchar *s;
X{
X char *x;
X
X /* -? */
X if (*s == '-')
X s++;
X /* [0-9]+{exponent} */
X for (x = s; isdigit(*s); s++)
X continue;
X return(s > x ? is_exponent(s) : 0);
X}
X
X/* returns non-zero iff '[^^\]' | '\^.' | '\\\\' | '\\'' | '\[0-7]{1-3}' matches */
Xstatic int is_character (s)
Xchar *s;
X{
X char *x;
X
X if (isprime(*s))
X s++;
X else
X return(0);
X if (isbackslash(*s)) {
X s++;
X if ((isbackslash(s[0]) || isprime(s[0]) || !isdigit(s[0])) &&
X isprime(s[1]) && !s[2])
X return(1);
X for (x = s; isoctal(*s); s++)
X continue;
X return(x < s && s < (x+4) && isprime(s[0]) && !s[1]);
X } else if (iscaret(*s))
X s++;
X return(isprint(s[0]) && isprime(s[1]) && !s[2]);
X}
X
X/* returns non-zero iff s is a string constant */
Xstatic int is_string (s)
Xchar *s;
X{
X char *x;
X
X if (*s != '"')
X return(0);
X for (s++; *s; s++) {
X if (*s == '"')
X return(!*++s); /* quote must be followed by null */
X if (isbackslash(*s) || iscaret(*s)) {
X if (*++s)
X continue; /* legal escape */
X return(0); /* null follows \ or ^ */
X }
X }
X return(0);
X}
X
X/*
X * read an entire profile, making a bidirectional
X * circularly linked list
X * returns pointer to the first stanza or NULL on error
X */
XPROFILE_STANZA *profile_read_profile(f)
XFILE *f;
X{
X PROFILE_STANZA *head = NULL;
X PROFILE_STANZA *tail = NULL;
X PROFILE_STANZA *x = NULL;
X
X while ((x = profile_read_stanza(f)) != NULL) {
X if (head == NULL)
X head = tail = x;
X else {
X tail->next = x;
X x->previous = tail;
X tail = x;
X }
X }
X if (head != NULL) {
X tail->next = head;
X head->previous = tail;
X }
X return(head);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/space.c
sed -e 's/^X//' > libprofile/space.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)space.c 1.1 (TRW) 1/14/86";
X#include "profile.h"
X
Xextern char *calloc();
X
XPROFILE_STANZA *profile_stanza_space ()
X{
X return((PROFILE_STANZA *)calloc(1, sizeof(PROFILE_STANZA)));
X}
X
XPROFILE_MARKER *profile_marker_space (n)
Xint n;
X{
X char *space;
X PROFILE_MARKER *m = (PROFILE_MARKER *)0;
X
X if (space = calloc(1, sizeof(PROFILE_MARKER) + n + 1)) {
X m = (PROFILE_MARKER *)space;
X m->text = space + sizeof(PROFILE_MARKER);
X }
X return(m);
X}
X
XPROFILE_BINDING *profile_binding_space (n)
Xint n; /* length of binding name in characters */
X{
X char *space;
X PROFILE_BINDING *b = (PROFILE_BINDING *)0;
X
X if (space = calloc(1, sizeof(PROFILE_BINDING) + n + 1)) {
X b = (PROFILE_BINDING *)space;
X b->name = space + sizeof(PROFILE_BINDING);
X }
X return(b);
X}
X
XPROFILE_VALUE *profile_value_space (n)
Xint n;
X{
X char *space;
X PROFILE_VALUE *v = (PROFILE_VALUE *)0;
X
X if (n > 0) {
X if (space = calloc(1, sizeof(PROFILE_VALUE) + n + 1)) {
X v = (PROFILE_VALUE *)space;
X v->value.s = space + sizeof(PROFILE_VALUE);
X }
X } else
X v = (PROFILE_VALUE *)calloc(1, sizeof(PROFILE_VALUE));
X return(v);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
mkdir libprofile
echo mkdir libprofile
fi
echo x - libprofile/write.c
sed -e 's/^X//' > libprofile/write.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)write.c 1.1 (TRW) 1/14/86";
X#include <stdio.h>
X#include <ctype.h>
X#include "profile.h"
X
Xprofile_write_stanza (f, s)
XFILE *f;
XPROFILE_STANZA *s;
X{
X write_markers(f, s->marker);
X fprintf(f, "{\n");
X write_bindings(f, s->binding);
X fprintf(f, "}\n");
X}
X
Xstatic write_markers (f, m)
XFILE *f;
XPROFILE_MARKER *m;
X{
X for (; m; m = m->next)
X fprintf(f, "%s\n", m->text);
X}
X
Xstatic write_bindings (f, b)
XFILE *f;
XPROFILE_BINDING *b;
X{
X while (b) {
X fprintf(f, "\t%s", b->name);
X write_values(f, b->value);
X fputc('\n', f);
X b = b->next;
X }
X}
X
Xstatic write_values (f, v)
XFILE *f;
XPROFILE_VALUE *v;
X{
X char scratch[PROFILE_MAX_TEXT+1];
X
X for (; v; v = v->next)
X switch (v->class) {
X case PROFILE_INTEGER:
X fprintf(f, " %D", v->value.i);
X continue;
X case PROFILE_FLOAT:
X fprintf(f, " %G", v->value.f);
X continue;
X case PROFILE_STRING:
X unparse_string(v->value.s, scratch);
X fprintf(f, " \"%s\"", scratch);
X continue;
X case PROFILE_CHARACTER:
X unparse_character(v->value.c, scratch);
X fprintf(f, " '%s'", scratch);
X continue;
X case PROFILE_OCTAL:
X fprintf(f, " 0o%O", v->value.i);
X continue;
X case PROFILE_HEX:
X fprintf(f, " 0x%X", v->value.i);
X continue;
X case PROFILE_OTHER:
X fprintf(f, " %s", v->value.s);
X continue;
X }
X}
X
Xstatic int unparse_string (from, to)
Xchar *from;
Xchar *to;
X{
X char *x = to;
X
X for (; *from; from++)
X switch (*from) {
X case '\b': /* backspace */
X *x++ = '\\';
X *x++ = 'b';
X continue;
X case '\f': /* formfeed */
X *x++ = '\\';
X *x++ = 'f';
X continue;
X case '\n': /* newline */
X *x++ = '\\';
X *x++ = 'n';
X continue;
X case '\r':
X *x++ = '\\';
X *x++ = 'r';
X continue;
X case '\t': /* horizontal tab */
X *x++ = '\\';
X *x++ = 't';
X continue;
X case '\\': /* backslash */
X *x++ = '\\';
X *x++ = '\\';
X continue;
X case '"': /* double quote */
X *x++ = '\\';
X *x++ = '"';
X continue;
X case '^':
X *x++ = '\\';
X *x++ = '^';
X continue;
X default:
X if (isascii(*from))
X if (iscntrl(*from)) {
X sprintf(x, "^%c", *from == '\177' ? '?' : *from + '@');
X x += 2;
X } else
X *x++ = *from;
X else {
X sprintf(x, "\\%03o", *from);
X x += 4;
X }
X continue;
X }
X *x = '\0';
X return(x - to);
X}
X
Xstatic int unparse_character (from, to)
Xchar from;
Xchar *to;
X{
X char *x = to;
X
X switch (from) {
X case '\b': /* backspace */
X *x++ = '\\';
X *x++ = 'b';
X break;
X case '\f': /* formfeed */
X *x++ = '\\';
X *x++ = 'f';
X break;
X case '\n': /* newline */
X *x++ = '\\';
X *x++ = 'n';
X break;
X case '\r':
X *x++ = '\\';
X *x++ = 'r';
X break;
X case '\t': /* horizontal tab */
X *x++ = '\\';
X *x++ = 't';
X break;
X case '\\': /* backslash */
X *x++ = '\\';
X *x++ = '\\';
X break;
X case '\'': /* single quote */
X *x++ = '\\';
X *x++ = '\'';
X break;
X case '^':
X *x++ = '\\';
X *x++ = '^';
X break;
X default:
X if (isascii(from))
X if (iscntrl(from)) {
X sprintf(x, "^%c", from == '\177' ? '?' : from + '@');
X x += 2;
X } else
X *x++ = from;
X else {
X sprintf(x, "\\%03o", from);
X x += 4;
X }
X break;
X }
X *x = '\0';
X return(x - to);
X}
X
X/*
X * write out a linked list of stanzas
X */
Xprofile_write_profile(f, s)
XFILE *f;
XPROFILE_STANZA *s;
X{
X PROFILE_STANZA *x;
X
X for (x = s; x != NULL; x = x->next) {
X profile_write_stanza(f, x);
X if (x->next == s)
X break;
X }
X}
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/Makefile
sed -e 's/^X//' > libtrw/Makefile << '!FaR!OuT!'
X# @(#)Makefile 1.1 (TRW) 1/14/86
XCFLAGS= -O
XDEST= /usr/local/lib
XINCLUDE=/usr/include/local
X
X.c.o:
X ${CC} ${CFLAGS} -c $*.c
X -ld -x -r $*.o
X mv a.out $*.o
X
Xall: libtrw.a
X
Xlibtrw.a: shift.o getopt.o getunent.o
X ar cr libtrw.a shift.o getopt.o getunent.o
X ranlib libtrw.a
X
Xclean:
X rm -f *.o
X
Xinstall: all
X mv libtrw.a $(DEST)
X ranlib $(DEST)/libtrw.a
X cp universe.h $(INCLUDE)
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/getopt.3
sed -e 's/^X//' > libtrw/getopt.3 << '!FaR!OuT!'
X.\" @(#)getopt.3 1.1 (TRW) 2/27/84
X.TH GETOPT 3C
X.SH NAME
Xgetopt \- get option letter from argument vector
X.SH SYNOPSIS
X.B int getopt (argc, argv, optstring)
X.br
X.B int argc;
X.br
X.B char \(**\(**argv;
X.br
X.B char \(**optstring;
X.PP
X.B extern char \(**optarg;
X.br
X.B extern int optind;
X.PP
Xcc ... -ltrw
X.SH DESCRIPTION
X.I Getopt\^
Xreturns the next option letter in
X.I argv\^
Xthat matches
Xa letter in
X.IR optstring .
X.I Optstring\^
Xis a string of recognized option letters;
Xif a letter is followed by a colon, the option
Xis expected to have an argument that may or
Xmay not be separated from it by white space.
X.I Optarg\^
Xis set to point to the start of the option argument
Xon return from
X.IR getopt .
X.PP
X.I Getopt\^
Xplaces in
X.I optind\^
Xthe
X.I argv\^
Xindex of the next argument to be processed.
XBecause
X.I optind\^
Xis external, it is normally initialized to zero
Xautomatically before the first call to
X.IR getopt .
X.PP
XWhen all options have been processed
X(i.e., up to the first non-option argument),
X.I getopt\^
Xreturns
X.SM
X.BR EOF .
XThe special option
X.B \-\-
Xmay be used to delimit the end of the options;
X.SM
X.B EOF
Xwill be returned, and
X.B \-\-
Xwill be skipped.
X.SH DIAGNOSTICS
X.I Getopt\^
Xprints an error message on
X.I stderr\^
Xand returns a
Xquestion mark
X.RB ( ? )
Xwhen it encounters an option letter not included in
X.IR optstring .
X.SH WARNING
XThe above routine uses \fB<stdio.h>\fP, which causes
Xit to increase the size of programs,
Xnot otherwise using standard I/O, more
Xthan might be expected.
X.SH EXAMPLE
XThe following code fragment shows how one might process the arguments
Xfor a command that can take the mutually exclusive options
X.B a
Xand
X.BR b ,
Xand the options
X.B f
Xand
X.BR o ,
Xboth of which require arguments:
X.PP
X.RS
X.nf
X.ss 18
Xmain (argc, argv)
Xint argc;
Xchar \(**\(**argv;
X{
X int c;
X extern int optind;
X extern char \(**optarg;
X \&\f3.\fP
X \&\f3.\fP
X \&\f3.\fP
X while ((c = getopt (argc, argv, "abf:o:")) != \s-1EOF\s+1)
X switch (c) {
X case \(fma\(fm:
X if (bflg)
X errflg++;
X else
X aflg++;
X break;
X case \(fmb\(fm:
X if (aflg)
X errflg++;
X else
X bproc( );
X break;
X case \(fmf\(fm:
X ifile = optarg;
X break;
X case \(fmo\(fm:
X ofile = optarg;
X bufsiza = 512;
X break;
X case \(fm?\(fm:
X errflg++;
X }
X if (errflg) {
X fprintf (stderr, "usage: . . . ");
X exit (2);
X }
X for ( ; optind < argc; optind++) {
X if (access (argv[optind], 4)) {
X \&\f3.\fP
X \&\f3.\fP
X \&\f3.\fP
X}
X.ss 12
X.fi
X.RE
X.\" @(#)getopt.3c 5.2 of 5/18/82
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/getopt.c
sed -e 's/^X//' > libtrw/getopt.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)getopt.c 1.1 (TRW) 1/14/86";
X/* This is the System V getopt(3), modified to use index(3) instead
X * of strchr(3).
X */
X
X/* @(#)getopt.c 1.2 */
X/* 3.0 SID # 1.2 */
X/*LINTLIBRARY*/
X#include <stdio.h>
X#define ERR(s, c) if(opterr){\
X (void) fputs(argv[0], stderr);\
X (void) fputs(s, stderr);\
X (void) fputc(c, stderr);\
X (void) fputc('\n', stderr);}
X
Xextern int strcmp();
Xextern char *index();
X
Xint opterr = 1;
Xint optind = 1;
Xint optopt;
Xchar *optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint argc;
Xchar **argv, *opts;
X{
X static int sp = 1;
X register int c;
X register char *cp;
X
X if(sp == 1)
X if(optind >= argc ||
X argv[optind][0] != '-' || argv[optind][1] == '\0')
X return(EOF);
X else if(strcmp(argv[optind], "--") == NULL) {
X optind++;
X return(EOF);
X }
X optopt = c = argv[optind][sp];
X if(c == ':' || (cp=index(opts, c)) == NULL) {
X ERR(": illegal option -- ", c);
X if(argv[optind][++sp] == '\0') {
X optind++;
X sp = 1;
X }
X return('?');
X }
X if(*++cp == ':') {
X if(argv[optind][sp+1] != '\0')
X optarg = &argv[optind++][sp+1];
X else if(++optind >= argc) {
X ERR(": option requires an argument -- ", c);
X sp = 1;
X return('?');
X } else
X optarg = argv[optind++];
X sp = 1;
X } else {
X if(argv[optind][++sp] == '\0') {
X sp = 1;
X optind++;
X }
X optarg = NULL;
X }
X return(c);
X}
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/getunent.3
sed -e 's/^X//' > libtrw/getunent.3 << '!FaR!OuT!'
X.TH GETUNENT 3-ucb
X.SH NAME
Xgetunent, getunnam, setunent, endunent \- get universe file entry
X.SH ORIGIN
X4.2BSD
X.SH SYNOPSIS
X.nf
X.B #include <local/universe.h>
X.PP
X.B struct universe *getunent()
X.PP
X.B struct universe *getunnam(name)
X.B char *name;
X.PP
X.B int setunent()
X.PP
X.B int endunent()
X.PP
Xcc ... -ltrw
X.fi
X.SH DESCRIPTION
X.I Getunent
Xand
X.I getunnam
Xeach return a pointer to an object with the
Xfollowing structure,
Xcontaining the broken-out
Xfields of a line in the universe file.
X.RS
X.PP
X.nf
X.so /usr/include/local/universe.h
X.ft R
X.ad
X.fi
X.RE
X.PP
X.I Getunent
Xreads the next
Xline (opening the file if necessary);
X.I setunent
Xrewinds the file;
X.I endunent
Xcloses it.
X.PP
X.I Getunnam
Xsearches from the beginning until a matching
X.I name
Xis found
X(or until EOF is encountered).
X.SH FILES
X/etc/u_universe
X.SH AUTHOR
XScott Simpson, TRW
X.SH "SEE ALSO"
Xu_universe(5)
X.SH DIAGNOSTICS
XNull pointer
X(0) returned on EOF or error.
X.SH BUGS
XAll information
Xis contained in a static area,
Xso it must be copied if it is
Xto be saved.
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/getunent.c
sed -e 's/^X//' > libtrw/getunent.c << '!FaR!OuT!'
X/* Scott Simpson, TRW */
X#include <stdio.h>
X#include <local/universe.h>
X
Xstatic char UNIVERSE[] = "/etc/u_universe";
Xstatic char EMPTY[] = "";
Xstatic FILE *uf = NULL;
Xstatic char line[BUFSIZ+1];
Xstatic char name[80];
Xstatic char univ[80];
Xstatic struct universe universe;
X
Xsetunent()
X{
X if( uf == NULL )
X uf = fopen(UNIVERSE, "r" );
X else
X rewind( uf );
X}
X
Xendunent()
X{
X if( uf != NULL ){
X fclose( uf );
X uf = NULL;
X }
X}
X
Xstruct universe *
Xgetunent()
X{
X register char *p;
X if (uf == NULL) {
X if( (uf = fopen( UNIVERSE, "r" )) == NULL )
X return(0);
X }
X while (1) {
X p = fgets(line, BUFSIZ, uf);
X if (p==NULL)
X return(0);
X if (line[strlen(line)-1]=='\n')line[strlen(line)-1]='\0';
X if (strlen(line) == 0 || line[0] == '#' || line[0] == ':')
X continue;
X if (sscanf(line, "%[^:]:%s", name, univ) != 2) {
X return(0);
X} else {
X universe.un_name = &name[0];
X universe.un_universe = &univ[0];
X break;
X }
X }
X return(&universe);
X}
X
Xgetunnam(name)
Xchar *name;
X{
X register struct universe *u;
X
X setunent();
X while ( (u = getunent()) && strcmp(name,u->un_name) );
X endpwent();
X return(u);
X}
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/shift.3
sed -e 's/^X//' > libtrw/shift.3 << '!FaR!OuT!'
X.\" @(#)shift.3 1.1 (TRW) 11/15/83
X.TH SHIFT 3 TRW
X.UC
X.SH NAME
Xstring_downshift, string_upshift \- shift case of strings
X.SH SYNOPSIS
X.nf
X.B char *string_downshift(s)
X.B char *s;
X
X.B char *string_upshift(s)
X.B char *s;
X
X.B cc ... -ltrw
X.fi
X.SH DESCRIPTION
X.I String_downshift
Xshifts
X.I s
Xin place to lowercase.
X.I String_upshift
Xshifts
X.I s
Xin place to uppercase.
XBoth routines return
X.I s.
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xctype(3), string(3)
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/shift.c
sed -e 's/^X//' > libtrw/shift.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)shift.c 1.1 (TRW) 1/14/86";
X#include <ctype.h>
X
X/*
X * Downshifts a string in place.
X */
Xchar *string_downshift(s)
Xchar *s;
X{
X
X register char *x = s;
X for (; *x; x++)
X if (isupper(*x))
X *x = tolower(*x);
X return(s);
X}
X
X/*
X * Upshifts a string in place.
X */
Xchar *string_upshift(s)
Xchar *s;
X{
X
X register char *x = s;
X for (; *x; x++)
X if (islower(*x))
X *x = toupper(*x);
X return(s);
X}
!FaR!OuT!
if [ ! -d libtrw ]
then
mkdir libtrw
echo mkdir libtrw
fi
echo x - libtrw/universe.h
sed -e 's/^X//' > libtrw/universe.h << '!FaR!OuT!'
Xstruct universe { /* see getunent(3) */
X char *un_name;
X char *un_universe;
X};
X
Xstruct universe *getunent(), *getunnam();
!FaR!OuT!
exit
--
Scott Simpson
TRW Electronics and Defense Sector
...{decvax,ihnp4,ucbvax}!trwrb!simpson