ftp.nice.ch/pub/next/tools/screen/backspace/Spew.NIHS.bs.tar.gz#/SpewView.BackModule/spew.c

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.