This is spew.c in view mode; [Download] [Up]
/* * SPEW.C */ #ifndef lint static char *cpr[]={ " Copyright 1987 Greg Smith", " Permission is granted to freely use and distribute this software", "provided this notice is left attached and no monetary gain is made." }; #endif #include <stdio.h> #include <ctype.h> #ifdef unix #include <strings.h> #else extern char *strcpy (); #define index strchr #define rindex strrchr extern char *index (); extern char *rindex (); #endif extern char *malloc(); char *my_alloc(); extern int atoi(); char *save(); #define TRUE 1 #define FALSE 0 #define MAGIC 4 /* distinguish compressed file from normal */ /*--------------- system configuration ------------------*/ /* define some parameters */ #define MAXCLASS 300 /* max # of classes */ #define MAXLINE 256 /* max size of input line */ #define MAXDEF 1000 /* max # bytes in a definition */ /* Define the default rulesfile */ #ifndef DEFFILE # define DEFFILE "headline" #endif /* Define the environment variable which is to be interrogated for name of rules file before DEFFILE is used. Delete this to remove the code that calls getenv() */ #define ENVIRON "RULESFILE" /* Define the random number generator */ extern long getpid(); extern int rand(), srand(); /* SETRAND must be complete statement: note semicolon */ #define SETRAND (void)srand((int) time((long *)0) ); /* ROLL(n) returns integer 0..n-1 */ #define ROLL(n) ((((long)rand()&0x7ffffff)>>5)%(n)) /* Enable '-d' dump debug option by defining DUMP */ #define DUMP /*---------------------------------------------------*/ FILE *InFile; typedef struct def_struct{ int cumul; /* cumulative weights */ char *string; /* string which defines it */ struct def_struct *next; /* link to next */ } defn; defn *process(); /* * within a definition, names of subdefinitions are bracketed in BSLASH * and SLASH chars. The whole definition ends with a '\0'. * The SLASH character is always follwed by a variant tag - default is ' '. */ #define BSLASH '\\' #define SLASH '/' #define VBAR '|' typedef struct{ int weight; /* total weight of definitions in class */ defn *list; /* list of them */ char *name; /* name of this class */ char *tags; /* pointer to list of tags */ } class; class * Class; /* pointer to array of class records */ char *NullTags = " "; /* default tags ( shared ) */ int Classes; /* number of them */ int HowMany = 1; int CompIn = FALSE; /* is input file in compressed format? */ int CompMain; /* class # of MAIN class when compressed */ char InLine[MAXLINE]; main(argc, argv ) int argc; char **argv; { char *fname; char main_class[20]; int i, c_flag = FALSE; #ifdef DUMP int d_flag = FALSE; #endif DUMP #ifdef ENVIRON extern char *getenv(); fname = getenv( ENVIRON ); #else fname = NULL; #endif ENVIRON while( argc > 1 ){ if( isdigit(*argv[1]) ){ HowMany = atoi(*++argv); --argc; }else if( strcmp( argv[1], "-c") == 0 ){ c_flag = TRUE; /* 'compress' option */ --argc; ++argv; #ifdef DUMP }else if( strcmp( argv[1], "-d" )== 0 ){ d_flag = TRUE; /* 'dump' option */ --argc; ++argv; #endif DUMP }else break; } if( argc > 1 ) fname = argv[1]; if (fname == NULL ) fname = DEFFILE; InFile = fopen( fname, "r" ); if( InFile == NULL ){ fprintf( stderr, "Can\'t open: %s\n", fname ); exit(1); } init(); #ifdef DUMP if( d_flag ){ dump(); exit(0); } #endif DUMP if( c_flag ){ compress(); }else{ if( CompIn ) sprintf( main_class, "%d/ ", CompMain); else strcpy( main_class, "MAIN/ "); for(i=0; i<HowMany; ++i) display(main_class,' '); } exit(0); } init(){ int c; SETRAND /* spin random number gen */ c = getc( InFile ); /* is compressed? */ CompIn = ( c== MAGIC ); /* set flag */ if( CompIn ){ readcomp(); /* read compressed version */ }else{ ungetc(c, InFile ); readtext(); } } readtext(){ register class *cp; register defn *dp; defn **update; int clcomp(); Class = (class *)my_alloc( (unsigned)(MAXCLASS * sizeof(class)) ); Classes = 0; cp = Class; readline(); if( InLine[0]!='%'){ fprintf( stderr,"Class definition expected at: %s\n", InLine); exit(1); } while( InLine[1] != '%' ){ if( Classes == MAXCLASS ){ fprintf(stderr,"Too many classes -- max = %d\n", MAXCLASS); exit(1); } setup( cp ); /* set up the class struct */ readline(); if( InLine[0] == '%' ){ fprintf( stderr, "Expected class instance at: %s\n", InLine); exit(1); } update = &(cp->list); /* update pointer */ do{ dp = process(); *update = dp; cp->weight += dp->cumul; /* add new stuff */ dp->cumul = cp->weight; /* set breakpoint */ update = &(dp->next); }while( readline(), InLine[0]!= '%' ); ++Classes; /* count them */ ++cp; *update = NULL; } qsort( (char*)Class, Classes, sizeof( class ), clcomp); } /* * display is given a class name ( delimited by SLASH, not '\0' ), * and will (1) find its class descriptor, by calling lookup * (2) pick a definition (3) output that definition, and * recursively display any definitions in it, and convert any escapes. * The variant tag after the SLASH is used to pick out the appropriate * variants. If that variant tag is '&', the tag 'deftag' is used, which * is the active variant of the containing activation. */ display(s,deftag) char *s; int deftag; { register class *cp; register defn *dp; register char *p; class *lookup(); int i,variant,incurly; register int c,writing; if( CompIn ){ /* input is compressed */ cp = &Class[ atoi(s) ]; /* explicit class # */ }else{ cp = lookup(s); if( cp == NULL ) { /* none found */ printf("???"); while( *s != SLASH ) putchar( *s++ ); printf("???"); return; } } c = index(s,SLASH)[1]; /* get variant tag */ if( c != '&' ) deftag=c; /* use given tag */ p = index(cp->tags, deftag); /* look it up */ if(p == NULL ){ variant = 0; printf("??/%c??", deftag ); deftag = ' '; /* for passing as deftag */ }else variant = p - cp->tags; i = ROLL( cp->weight ); dp = cp->list; while(dp->cumul <= i){ /* pick one based on cumul. weights */ dp = dp->next; } incurly = 0; /* not in curlies */ writing = 1; /* writing */ p = dp->string; /* this is the string */ for(;;)switch(c = *p++){ case '\0': return; case BSLASH: if(( c = *p++) == '\0' ) return; /* ?? */ else if( c == '!' ){ if(writing)putchar('\n'); /* \! = newline */ }else if( isalnum(c) ){ /* reference */ if(writing)display(p-1,deftag); /* recurse */ while( *p!=SLASH )++p; p += 2; /* skip variant tag */ }else{ if(writing) putchar(c); } break; case '{': if( !incurly ){ incurly = 1; writing = (variant == 0 ); }else{ if( writing )putchar('{'); } break; case VBAR: if( incurly ){ writing = ( variant == incurly++ ); }else{ putchar(VBAR); } break; case '}': if( incurly ){ writing = 1; incurly = 0; }else putchar('}'); break; default: if( writing) putchar(c); } } class * lookup( str ) /* delimited by SLASH, not '\0' */ char *str; { int first, last, try, comp; int namecomp(); first = 0; last = Classes-1; while( first <= last ){ try = (first+last)>>1; comp = namecomp( str, Class[try].name ); if( comp == 0 ) return &Class[try]; if( comp > 0 ) first = try+1; else last = try-1; } return NULL; } int namecomp(a,b) /* 'a' is delim. by SLASH, 'b' by NULL */ register char *a,*b; { register int ac; for(;;){ ac = *a++; if(ac == SLASH ) ac = '\0'; if( ac < *b ) return -1; if( ac > *b++ ) return 1; if( ac == '\0' ) return 0; } } readline(){ register char *p; do{ if( fgets( InLine, MAXLINE, InFile ) == NULL ){ InLine[0] = InLine[1] = '%'; InLine[2] = '\0'; /* create EOF */ }else if( (p=rindex( InLine, '\n'))!= NULL ) *p = '\0'; p = InLine; while( (p = index( p, BSLASH )) != NULL ){ if(p[1] == '*' ){ *p = 0; /* kill comment */ break; }else ++p; } }while( InLine[0] == '\0' ); } int clcomp(a,b) register class *a,*b; { if( a==b) return 0; return strcmp( a->name, b->name ); } char *save(str) char *str; { register char *p; p = my_alloc( (unsigned)((strlen(str)+1)*sizeof(char))); return strcpy(p,str); } /* * setup a class record. The 'class' line is in InLine. */ setup(cp) register class *cp; { char temp[100]; register char *p,*p2; p = &InLine[1]; /* point after the % */ while( *p == ' ' )++p; if( !isalnum(*p) ) goto baddec; p2 = temp; do *p2++ = *p++; while( isalnum(*p)); *p2 = '\0'; cp->weight = 0; /* save the name of it */ cp->name = save( temp ); cp->list = NULL; cp->tags = NullTags; /* by default */ for(;;)switch(*p++){ case '\0': return; /* all done; */ case ' ': break; /* allowed those */ case '{': /* tags list */ if( cp->tags != NullTags ) goto baddec; /* already */ p2 = temp; *p2++ = ' '; /* provide null tag */ while(*p!='}'){ if( !isalnum(*p)) goto baddec; *p2++ = *p++; } ++p; /* junk rh brace */ *p2 = 0; cp->tags = save(temp); break; default: goto baddec; } baddec: fprintf(stderr,"Bad class header: %s\n", InLine ); exit(1); } /* * create a 'processed' version of the InLine, and return a pointer to * the definition. The 'cumul' field is temporarily used to hold the * assigned weight of the line. */ defn *process(){ static char stuff[ MAXDEF ]; register char *p,*pout; register defn *dp; register int c; dp = (defn *) my_alloc( (unsigned) sizeof( defn )); p = InLine; pout = stuff; if( *p == '(' ){ /* get a weight */ while(*++p ==' '); /* scan */ if(!isdigit(*p)) goto badweight; c = *p - '0'; while(isdigit(*++p)) c = c*10 + (*p - '0' ); while( *p == ' ')++p; if( *p != ')') goto badweight; ++p; dp->cumul = c; }else{ dp->cumul = 1; /* default weight */ } while((c = *p++)!='\0')switch(c){ case BSLASH: *pout++ = BSLASH; if( isalnum(*p)){ /* is a ref */ do{ *pout++ = *p++; }while( isalnum(*p)); *pout++ = SLASH; /* delimit */ if( *p == SLASH ){ /* get variant char */ ++p; if( !isalnum(*p)&& *p!= ' ' && *p!= '&' ){ *pout++ = ' '; }else *pout++ = *p++; }else *pout++ = ' '; }else{ *pout++ = *p; if( *p!= '\0'){ ++p; }else{ --pout; /* delete spurious '\' */ readline(); /* get new line */ p = InLine; /* point to it */ } } break; default: *pout++ = c; } *pout = '\0'; dp->string = save( stuff ); return dp; badweight: fprintf(stderr, "Bad line weight: %s\n", InLine ); exit(1); /*NOTREACHED*/ } #ifdef DUMP dump(){ register class *cp; register defn *dp; register int i; for( i=0, cp=Class; i<Classes; ++cp,++i ){ if( CompIn) printf("%d, {%s} %d:\n",i ,cp->tags, cp->weight ); else printf("%s, {%s} %d:\n", cp->name,cp->tags, cp->weight ); for( dp = cp->list; dp!=NULL; dp=dp->next ){ printf("(%d)%s\n",dp->cumul, dp->string ); } } } #endif DUMP char *my_alloc(n) unsigned n; { register char *p; p = malloc( n ); if( p==NULL ){ fprintf(stderr, "Out Of Memory\n"); exit(1); } return p; } /* * write the file to the standard output in compressed form, prepending * the MAGIC byte for identification. */ compress(){ register class *cp; register int i; putchar( MAGIC ); putw( Classes, stdout ); /* write the number of classes */ putw( -Classes, stdout ); /* write this to make sure */ if( !CompIn ){ cp = lookup("MAIN/ "); /* get main */ if( cp == NULL ){ fprintf(stderr, "MAIN undefined\n"); exit(1); } CompMain = cp - Class; } putw( CompMain, stdout ); cp = Class; i = Classes; while(i--) comp1(cp++); } /* * write a 'class' record in compressed format */ comp1(cp) register class *cp; { register char *p; register defn *dp; register int n; putw( cp->weight, stdout ); /* write total weight */ p = cp->tags; if( strcmp(p,NullTags) != 0 ) /* special case " " -> "" */ fputs( p, stdout ); /* write tags */ putchar(0); /* delimiter */ n = 0; dp = cp->list; while( dp!= NULL ){ ++n; /* count the defs */ dp = dp->next; } putw( n, stdout ); /* write the count of them */ dp = cp->list; while( dp != NULL ){ compdef(dp); dp = dp->next; /* compress them */ } } compdef(dp) register defn *dp; { register char *p; register int c; putw( dp-> cumul , stdout ); /* write its cumul weight */ p = dp->string; while( (c = *p++) != '\0' ){ if( c==BSLASH){ if(!CompIn && isalnum(*p) ){ /* a ref */ class *cp; cp = lookup(p); /* find it */ if( cp == NULL ){ fprintf( stderr, "Undefined class: "); while( *p != SLASH ) fputc( *p++, stderr); fputc('\n', stderr ); exit(1); }else{ printf("%c%d", BSLASH, cp-Class ); while( *p != SLASH ) ++p; } }else{ /* is escape seq */ putchar( BSLASH ); putchar( *p++ ); } }else{ putchar(c); } } putchar(0); } /* * readcomp reads the compressed format of the file into core. * the MAGIC char has been read already. */ readcomp(){ register class *cp; register int i; Classes = getw( InFile ); if( Classes <= 0 || getw( InFile ) + Classes != 0 ) badfile(); /* format check */ CompMain = getw( InFile ); /* read that next */ Class = (class*) my_alloc( (unsigned)(Classes*sizeof(class)) ); for( i= Classes, cp = Class; i--; ++cp)readcclass(cp); } readcclass(cp) register class *cp; { register int n; register defn *dp; defn **dput; char store[MAXDEF]; /* for tags */ cp->weight = getw( InFile ); instring(store,MAXDEF); cp->tags = ( store[0] == '\0' )? NullTags: save( store ); n = getw( InFile ); if( n<=0 ) badfile(); dput = &(cp->list); /* link on here */ while(n--){ dp = (defn *)my_alloc( (unsigned) sizeof( defn)); *dput = dp; dp->cumul = getw( InFile ); instring(store, MAXDEF ); dp->string = save( store ); dput = &(dp->next); } *dput = NULL; /* last one */ } instring( where, how_many ) register char *where; register int how_many; { register int c; do{ c = getc( InFile ); if( c == EOF ) badfile(); *where++ = c; if( c== '\0' ) return; }while(--how_many); badfile(); } badfile(){ fprintf(stderr,"Bad file format\n"); exit(1); } #ifndef unix putw (word, stream) int word; FILE *stream; { fwrite ((char *) &word, sizeof(int), 1, stream); return (0); /* we don't use it */ } getw (stream) FILE *stream; { int word; fread ((char *) &word, sizeof(int), 1, stream); return (word); } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.