home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1654 / spew.c < prev   
C/C++ Source or Header  |  1990-12-28  |  23KB  |  779 lines

  1. /*
  2.  * SPEW.C
  3.  */
  4.  
  5. /* #define DOS      Undef this if compiling under BSD UNIX */
  6. #define PRUNE    /* Undef this if /PRUNE pseudoclass not used or
  7.            setjmp/longjmp not available (WML) */
  8.  
  9.  
  10. #ifndef lint
  11. static char *cpr[]={
  12.    "  Copyright 1987 Greg Smith",
  13.    "  Permission is granted to freely use and distribute this software",
  14.    "provided this notice is left attached and no monetary gain is made."
  15. };
  16.  
  17. static char *mod_notice[] =  {
  18.    "  Modified for compilation under DOS with Borland Turbo C.",
  19.    "by Ti Kan 5-31-1988.",
  20.    "  Other modifications, additions, and improvements",
  21.    "by Wim Lewis (WML) August 1990."
  22. };
  23. #endif
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27.  
  28. #ifdef PRUNE
  29. #include <setjmp.h>
  30. #endif
  31.  
  32. #ifdef DOS
  33.  
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <alloc.h>
  37. #include <bios.h>
  38. #define index(s,c)      strchr(s,c)
  39. #define rindex(s,c)     strrchr(s,c)
  40.  
  41. #else
  42.  
  43. #include <strings.h>
  44. extern char *malloc();
  45. extern int atoi();
  46.  
  47. #endif
  48.  
  49. char *my_alloc();
  50. char *save();
  51. #define TRUE (1)
  52. #define FALSE (0)
  53. #define MAGIC 4         /* distinguish compressed file from normal */
  54.  
  55. void print(), printc();
  56.  
  57. /*--------------- system configuration ------------------*/
  58.  
  59. /* define some parameters */
  60.  
  61. #define MAXCLASS 300            /* max # of classes */
  62. #define MAXLINE 256             /* max size of input line */
  63. #define MAXDEF 1000             /* max # bytes in a definition */
  64.  
  65. /* Define the default rulesfile */
  66.  
  67. #ifndef DEFFILE
  68. #define DEFFILE "/b1/wiml/pub/headline"
  69. #endif
  70.  
  71. /* Define the environment variable which is to be interrogated for
  72.    name of rules file before DEFFILE is used. Delete this to
  73.    remove the code that calls getenv() */
  74.  
  75. #define ENVIRON "RULESFILE"
  76.  
  77. /* Define the output line width. Lines are word-broken to this width. */
  78.  
  79. #define LINE_WIDTH (75)
  80.  
  81. /* Define the random number generator */
  82.  
  83. #ifndef DOS
  84. extern long getpid();
  85. extern int rand(), srand();
  86. #endif
  87.  
  88.  
  89.         /* SETRAND must be a complete statement: note semicolon */
  90. #ifdef DOS
  91. #define SETRAND (void) srand((unsigned) biostime(0, 0L));
  92. #else
  93. #define SETRAND (void)srand((int) getpid());
  94. #endif
  95.  
  96.         /* ROLL(n) returns integer 0..n-1 */
  97. #define ROLL(n) ((((long)rand()&0x7ffffff)>>5)%(n))
  98.  
  99. /* Enable '-d' dump debug option by defining DUMP */
  100. #define DUMP
  101.  
  102. /*---------------------------------------------------*/
  103.  
  104. FILE *InFile;
  105.  
  106. typedef struct def_struct{
  107.         int cumul;                      /* cumulative weights */
  108.         char *string;                   /* string which defines it */
  109.         struct def_struct *next;        /* link to next */
  110. } defn;
  111. defn *process();
  112. /*
  113.  * within a definition, names of subdefinitions are bracketed in BSLASH
  114.  * and SLASH chars. The whole definition ends with a '\0'.
  115.  * The SLASH character is always follwed by a variant tag - default is ' '.
  116.  */
  117. #define BSLASH '\\'
  118. #define SLASH  '/'
  119. #define VBAR     '|'
  120.  
  121. typedef struct{
  122.         int weight;     /* total weight of definitions in class */
  123.         defn *list;     /* list of them */
  124.         char *name;     /* name of this class */
  125.         char *tags;     /* pointer to list of tags */
  126. } class;
  127.  
  128. class * Class;  /* pointer to array of class records */
  129. char *NullTags = " ";   /* default tags ( shared ) */
  130. int Classes;    /* number of them */
  131. int HowMany = 1;
  132. int CompIn = FALSE;     /* is input file in compressed format? */
  133. int CompMain;           /* class # of MAIN class when compressed */
  134. #ifdef PRUNE
  135. jmp_buf prunebuf;    /* where to longjmp when PRUNE encountered */
  136. int prune_ok;        /* Whether prunebuf is still valid */
  137. #endif
  138.  
  139. char InLine[MAXLINE];
  140.  
  141. main(argc, argv )
  142. int argc;
  143. char **argv;
  144. {
  145.         char *fname;
  146.         char main_class[20];
  147.         int i, c_flag = FALSE;
  148. #ifdef DUMP
  149.         int d_flag = FALSE;
  150. #endif DUMP
  151. #ifdef ENVIRON
  152.         extern char *getenv();
  153.         fname = getenv( ENVIRON );
  154. #else
  155.         fname = NULL;
  156. #endif ENVIRON
  157.  
  158.         while( argc > 1 ){
  159.                 if( isdigit(*argv[1]) ){
  160.                         HowMany = atoi(*++argv);
  161.                         --argc;
  162.                 }else if( strcmp( argv[1], "-c") == 0 ){
  163.                         c_flag = TRUE;  /* 'compress' option */
  164.                         --argc;
  165.                         ++argv;
  166. #ifdef DUMP
  167.                 }else if( strcmp( argv[1], "-d" )== 0 ){
  168.                         d_flag = TRUE;  /* 'dump' option */
  169.                         --argc;
  170.                         ++argv;
  171. #endif DUMP
  172.                 }else break;
  173.         }
  174.         if( argc > 1 ) fname = argv[1];
  175.         if (fname == NULL ) fname = DEFFILE;
  176.         InFile = fopen( fname, "r" );
  177.         if( InFile == NULL ){
  178.                 fprintf( stderr, "Can\'t open: %s\n", fname );
  179.                 exit(1);
  180.         }
  181.         init();
  182. #ifdef DUMP
  183.         if( d_flag ){
  184.                 dump();
  185.                 exit(0);
  186.         }
  187. #endif DUMP
  188.         if( c_flag ){
  189.                 compress();
  190.         }else{
  191.                 if( CompIn ) sprintf( main_class, "%d/ ", CompMain);
  192.                 else         strcpy( main_class, "MAIN/ ");
  193.                 for(i=0; i<HowMany; ++ i) 
  194.           {
  195. #ifdef PRUNE
  196.             if(setjmp(prunebuf) == 0)
  197.             {
  198.               prune_ok = 1;
  199. #endif
  200.               display(main_class,' ');
  201. #ifdef PRUNE
  202.             }
  203. #endif
  204.           }
  205.         }
  206.         exit(0);
  207. }
  208.  
  209. init(){
  210.         int c;
  211.  
  212.         SETRAND         /* spin random number gen */
  213.         c = getc( InFile );     /* is compressed? */
  214.         CompIn = ( c== MAGIC ); /* set flag */
  215.         if( CompIn ){
  216.                 readcomp();     /* read compressed version */
  217.         }else{
  218.                 ungetc(c, InFile );
  219.                 readtext();
  220.         }
  221. }
  222. readtext(){
  223.         register class *cp;
  224.         register defn *dp;
  225.         defn **update;
  226.         int clcomp();
  227.  
  228.         Class = (class *)my_alloc( (unsigned)(MAXCLASS * sizeof(class)) );
  229.         Classes = 0;
  230.  
  231.         cp = Class;
  232.         readline();
  233.         if( InLine[0]!='%'){
  234.                 fprintf( stderr,"Class definition expected at: %s\n", InLine);
  235.                 exit(1);
  236.         }
  237.         while( InLine[1] != '%' ){
  238.                 if( Classes == MAXCLASS ){
  239.                         fprintf(stderr,"Too many classes -- max = %d\n", MAXCLASS);
  240.                         exit(1);
  241.                 }
  242.                 setup( cp );            /* set up the class struct */
  243.                 readline();
  244.                 if( InLine[0] == '%' ){
  245.                         fprintf( stderr, "Expected class instance at: %s\n", InLine);
  246.                         exit(1);
  247.                 }
  248.                 update = &(cp->list);   /* update pointer */
  249.                 do{
  250.                         dp = process();
  251.                         *update = dp;
  252.                         cp->weight += dp->cumul;        /* add new stuff */
  253.                         dp->cumul = cp->weight;         /* set breakpoint */
  254.                         update = &(dp->next);
  255.                 }while( readline(), InLine[0]!= '%' );
  256.                 ++Classes;              /* count them */
  257.                 ++cp;
  258.                 *update = NULL;
  259.         }
  260.         qsort( (char*)Class, Classes, sizeof( class ), clcomp);
  261. }
  262. /*
  263.  * display is given a class name ( delimited by SLASH, not '\0' ),
  264.  * and will (1) find its class descriptor, by calling lookup
  265.  * (2) pick a definition  (3) output that definition, and
  266.  * recursively display any definitions in it, and convert any escapes.
  267.  * The variant tag after the SLASH is used to pick out the appropriate
  268.  * variants. If that variant tag is '&', the tag 'deftag' is used, which
  269.  * is the active variant of the containing activation.
  270.  */
  271. display(s,deftag)
  272. char *s;
  273. int deftag;
  274. {
  275.         register class *cp;
  276.         register defn *dp;
  277.         register char *p;
  278.         class *lookup();
  279.         int i,variant,incurly;
  280.         register int c,writing;
  281.     int weprune=0;  /* if we set the prune stop here */
  282.  
  283.         if( CompIn ){           /* input is compressed */
  284.                 cp = &Class[ atoi(s) ];         /* explicit class # */
  285.         }else{
  286. #ifdef PRUNE
  287.         if(!strncmp(s, "PRUNE/", 6))
  288.         {
  289.             if(!prune_ok)
  290.             {
  291.                 print("\n -- Prune too late, aborting.\n");
  292.                 exit(2);
  293.             }
  294.             else longjmp(prunebuf, 1);
  295.         }
  296.         if(index(s, '!') == (index(s, '/')-1))
  297.         {
  298.             if(setjmp(prunebuf))
  299.             {
  300.                 prune_ok = 0;
  301.                 return;
  302.             }
  303.             weprune=1;
  304.         }
  305. #endif
  306.                 cp = lookup(s);
  307.                 if( cp == NULL ) {              /* none found */
  308.                         print("???");
  309.                         while( *s != SLASH ) printc( *s++ );
  310.                         print("???");
  311. #ifdef PRUNE
  312.             if(weprune) prune_ok = 0;
  313. #endif
  314.                         return;
  315.                 }
  316.  
  317.         }
  318.         c = index(s,SLASH)[1];          /* get variant tag */
  319.         if( c != '&' ) deftag=c;        /* use given tag */
  320.         p = index(cp->tags, deftag);            /* look it up */
  321.         if(p == NULL ){
  322.                 variant = 0;
  323.                 print("??");
  324.                 printc(deftag);
  325.                 print("??");
  326.                 deftag = ' ';           /* for passing as deftag */
  327.         }else variant = p - cp->tags;
  328.  
  329.         i = ROLL( cp->weight );
  330.         dp = cp->list;
  331.         while(dp->cumul <= i){  /* pick one based on cumul. weights */
  332.                 dp = dp->next;
  333.         }
  334.  
  335.         incurly = 0;            /* not in curlies */
  336.         writing = 1;            /* writing */
  337.         p = dp->string;         /* this is the string */
  338.         for(;;)switch(c = *p++){
  339.                 case '\0': 
  340. #ifdef PRUNE
  341.                if(weprune) prune_ok = 0; 
  342. #endif
  343.                               return;
  344.                 case BSLASH:
  345.                         if(( c = *p++) == '\0' ) 
  346.             {
  347. #ifdef PRUNE
  348.                if(weprune) prune_ok = 0;
  349. #endif
  350.                return; /* ?? */
  351.             }
  352.                         else if( c == '!' ){
  353.                                  if(writing)printc('\n'); /* \! = newline */
  354.                         }else if( isalnum(c) ){ /* reference */
  355.                                 if(writing)display(p-1,deftag);  /* recurse */
  356.                                 while( *p!=SLASH )++p;
  357.                                 p += 2;         /* skip variant tag */
  358.                         }else{
  359.                                 if(writing) printc(c);
  360.                         }
  361.                         break;
  362.                 case '{':
  363.                         if( !incurly ){
  364.                                 incurly = 1;
  365.                                 writing = (variant == 0 );
  366.                         }else{
  367.                                 if( writing )printc('{');
  368.                         }
  369.                         break;
  370.                 case VBAR:
  371.                         if( incurly ){
  372.                                 writing = ( variant == incurly++ );
  373.                         }else{
  374.                                 printc(VBAR);
  375.                         }
  376.                         break;
  377.                 case '}':
  378.                         if( incurly ){
  379.                                 writing = 1;
  380.                                 incurly = 0;
  381.                         }else printc('}');
  382.                         break;
  383.                 default:
  384.                         if( writing) printc(c);
  385.         }
  386.    /*NOTREACHED*/
  387. }
  388. class *
  389. lookup( str )           /* delimited by SLASH, not '\0' */
  390. char *str;
  391. {
  392.         int first, last, try, comp;
  393.         int namecomp();
  394.  
  395.         first = 0;
  396.         last = Classes-1;
  397.         while( first <= last ){
  398.                 try = (first+last)>>1;
  399.                 comp = namecomp( str, Class[try].name );
  400.                 if( comp == 0 ) return &Class[try];
  401.                 if( comp > 0 ) first = try+1;
  402.                 else last = try-1;
  403.         }
  404.         return NULL;
  405. }
  406. int namecomp(a,b)       /* 'a' is delim. by SLASH, 'b' by NULL */
  407. register char *a,*b;
  408. {
  409.         register int ac;
  410.         for(;;){
  411.                 ac = *a++;
  412.                 if(ac == SLASH ) ac = '\0';
  413.                 if( ac < *b ) return -1;
  414.                 if( ac > *b++ ) return 1;
  415.                 if( ac == '\0' ) return 0;
  416.         }
  417. }
  418. readline(){
  419.         register char *p;
  420.         do{
  421.                 if( fgets( InLine, MAXLINE, InFile ) == NULL ){
  422.                         InLine[0] = InLine[1] = '%';
  423.                         InLine[2] = '\0';       /* create EOF */
  424.                 }else if( (p=rindex( InLine, '\n'))!= NULL ) *p = '\0';
  425.                 p = InLine;
  426.                 while( (p = index( p, BSLASH )) != NULL ){
  427.                         if(p[1] == '*' ){
  428.                                 *p = 0; /* kill comment */
  429.                                 break;
  430.                         }else ++p;
  431.                 }
  432.         }while( InLine[0] == '\0' );
  433. }
  434.  
  435. int clcomp(a,b)                 
  436. register class *a,*b;
  437. {
  438.         if( a==b) return 0;
  439.         return strcmp( a->name, b->name );
  440. }
  441. char *save(str)
  442. char *str;
  443. {
  444.         register char *p;
  445.         p = my_alloc( (unsigned)((strlen(str)+1)*sizeof(char)));
  446.         return strcpy(p,str);
  447. }
  448. /*
  449.  * setup a class record. The 'class' line is in InLine.
  450.  */
  451. setup(cp)
  452. register class *cp;
  453. {
  454.         char temp[100];
  455.         register char *p,*p2;
  456.  
  457.         p = &InLine[1];         /* point after the % */
  458.         while( *p == ' ' )++p;
  459.         if( !isalnum(*p) ) goto baddec;
  460.         p2 = temp;
  461.         do *p2++ = *p++; while( isalnum(*p) || (*p == '!'));
  462.         *p2 = '\0';
  463.         cp->weight = 0;         /* save the name of it */
  464.         cp->name = save( temp );
  465.         cp->list = NULL;
  466.         cp->tags = NullTags;    /* by default */
  467.         for(;;)switch(*p++){
  468.         case '\0':
  469.                 return; /* all done; */
  470.         case ' ':
  471.                 break;          /* allowed those */
  472.         case '{':               /* tags list */
  473.                 if( cp->tags  != NullTags ) goto baddec; /* already */
  474.                 p2 = temp;
  475.                 *p2++ = ' ';    /* provide null tag */
  476.                 while(*p!='}'){
  477.                         if( !isalnum(*p)) goto baddec;
  478.                         *p2++ = *p++;
  479.                 }
  480.                 ++p;    /* junk rh brace */
  481.                 *p2 = 0;
  482.                 cp->tags = save(temp);
  483.                 break;
  484.         default: goto baddec;
  485.         }
  486.   baddec:
  487.         fprintf(stderr,"Bad class header: %s\n", InLine );
  488.         exit(1);
  489. }
  490. /*
  491.  * create a 'processed' version of the InLine, and return a pointer to
  492.  * the definition. The 'cumul' field is temporarily used to hold the
  493.  * assigned weight of the line.
  494.  */
  495. defn *process(){
  496.         static char stuff[ MAXDEF ];
  497.         register char *p,*pout;
  498.         register defn *dp;
  499.         register int c;
  500.  
  501.         dp = (defn *) my_alloc( (unsigned) sizeof( defn ));
  502.  
  503.         p = InLine;
  504.         pout = stuff;
  505.         if( *p == '(' ){                /* get a weight */
  506.                 while(*++p ==' ');      /* scan */
  507.                 if(!isdigit(*p)) goto badweight;
  508.                 c = *p - '0';
  509.                 while(isdigit(*++p)) c = c*10 + (*p - '0' );
  510.                 while( *p == ' ')++p;
  511.                 if( *p != ')') goto badweight;
  512.                 ++p;
  513.                 dp->cumul = c;
  514.         }else{
  515.                 dp->cumul = 1;  /* default weight */
  516.         }
  517.         while((c = *p++)!='\0')switch(c){
  518.         case BSLASH:
  519.                 *pout++ = BSLASH;
  520.                 if( isalnum(*p)){       /* is a ref */
  521.                         do{ *pout++ = *p++;
  522.                         }while( isalnum(*p) || (*p == '!'));
  523.                         *pout++ = SLASH;                /* delimit */
  524.                         if( *p == SLASH ){      /* get variant char */
  525.                                 ++p;
  526.                                 if( !isalnum(*p)&& *p!= ' ' && *p!= '&' ){
  527.                                         *pout++ = ' ';
  528.                                 }else *pout++ = *p++;
  529.                         }else *pout++ = ' ';
  530.                 }else{
  531.                         *pout++ = *p;
  532.                         if( *p!= '\0'){
  533.                                  ++p;
  534.                         }else{
  535.                                 --pout; /* delete spurious '\' */
  536.                                 readline();     /* get new line */
  537.                                 p = InLine;     /* point to it */
  538.                         }
  539.                 }
  540.                 break;
  541.         default:
  542.                 *pout++ = c;
  543.         }
  544.         *pout = '\0';
  545.         dp->string = save( stuff );
  546.         return dp;
  547.  
  548.   badweight:
  549.         fprintf(stderr, "Bad line weight: %s\n", InLine );
  550.         exit(1);
  551.         /*NOTREACHED*/
  552. }
  553. #ifdef DUMP
  554. dump(){
  555.         register class *cp;
  556.         register defn *dp;
  557.         register int i;
  558.         for( i=0, cp=Class; i<Classes; ++cp,++i ){
  559.                 if( CompIn)
  560.                         printf("%d, {%s} %d:\n",i ,cp->tags, cp->weight );
  561.                 else
  562.                         printf("%s, {%s} %d:\n", cp->name,cp->tags, cp->weight );
  563.                 for( dp = cp->list; dp!=NULL; dp=dp->next ){
  564.                         printf("(%d)%s\n",dp->cumul, dp->string );
  565.                 }
  566.         }
  567. }
  568. #endif DUMP
  569.  
  570. char *my_alloc(n)
  571. unsigned n;
  572. {
  573.         register char *p;
  574.         p = malloc( n );
  575.         if( p==NULL ){
  576.                 fprintf(stderr, "Out Of Memory\n");
  577.                 exit(1);
  578.         }
  579.         return p;
  580. }
  581.  
  582. /*
  583.  * write the file to the standard output in compressed form, prepending
  584.  * the MAGIC byte for identification.
  585.  */
  586. compress(){
  587.         register class *cp;
  588.         register int i;
  589.  
  590.         putchar( MAGIC );
  591.         putw( Classes, stdout );        /* write the number of classes */
  592.         putw( -Classes, stdout );       /* write this to make sure */
  593.  
  594.         if( !CompIn ){
  595.                 cp = lookup("MAIN/ ");          /* get main */
  596.                 if( cp == NULL ){
  597.                         fprintf(stderr, "MAIN undefined\n");
  598.                         exit(1);
  599.                 }
  600.                 CompMain = cp - Class;
  601.         }
  602.         putw( CompMain, stdout );
  603.         cp = Class;
  604.         i  = Classes;
  605.         while(i--) comp1(cp++);
  606. }
  607. /*
  608.  * write a 'class' record in compressed format
  609.  */
  610. comp1(cp)
  611. register class *cp;
  612. {
  613.         register char *p;
  614.         register defn *dp;
  615.         register int n;
  616.  
  617.         putw( cp->weight, stdout );     /* write total weight */
  618.         p = cp->tags;
  619.         if( strcmp(p,NullTags) != 0 )   /* special case " " -> "" */
  620.                 fputs( p, stdout );             /* write tags */
  621.         putchar(0);                     /* delimiter */
  622.         n = 0;
  623.         dp = cp->list;
  624.         while( dp!= NULL ){
  625.                 ++n;            /* count the defs */
  626.                 dp = dp->next;
  627.         }
  628.         putw( n, stdout );      /* write the count of them */
  629.         dp = cp->list;
  630.         while( dp != NULL ){
  631.                 compdef(dp);
  632.                 dp = dp->next;  /* compress them */
  633.         }
  634. }
  635. compdef(dp)
  636. register defn *dp;
  637. {
  638.         register char *p;
  639.         register int c;
  640.         putw( dp-> cumul , stdout );    /* write its cumul weight */
  641.         p = dp->string;
  642.         while( (c = *p++) != '\0' ){
  643.                 if( c==BSLASH){
  644.                         if(!CompIn && isalnum(*p) ){    /* a ref */
  645.                                 class *cp;
  646.                                 cp = lookup(p);         /* find it */
  647.                                 if( cp == NULL ){
  648.                                         fprintf( stderr, "Undefined class: ");
  649.                                         while( *p != SLASH ) fputc( *p++, stderr);
  650.                                         fputc('\n', stderr );
  651.                                         exit(1);
  652.                                 }else{
  653.                                         printf("%c%d", BSLASH, cp-Class );
  654.                                         while( *p != SLASH ) ++p;
  655.                                 }
  656.                         }else{          /* is escape seq */
  657.                                 putchar( BSLASH );
  658.                                 putchar( *p++ );
  659.                         }
  660.                 }else{
  661.                         putchar(c);
  662.                 }
  663.         }
  664.         putchar(0);
  665. }
  666.  
  667. /*
  668.  * readcomp reads the compressed format of the file into core.
  669.  * the MAGIC char has been read already.
  670.  */
  671. readcomp(){
  672.         register class *cp;
  673.         register int i;
  674.         Classes = getw( InFile );
  675.         if( Classes <= 0 || getw( InFile ) + Classes != 0 )
  676.                 badfile();      /* format check */
  677.         CompMain = getw( InFile );              /* read that next */
  678.         Class = (class*) my_alloc( (unsigned)(Classes*sizeof(class)) );
  679.         for( i= Classes, cp = Class; i--; ++cp)readcclass(cp);
  680. }
  681.  
  682. readcclass(cp)
  683. register class *cp;
  684. {
  685.         register int n;
  686.         register defn *dp;
  687.         defn **dput;
  688.  
  689.         char store[MAXDEF];     /* for tags */
  690.         cp->weight = getw( InFile );
  691.         instring(store,MAXDEF);
  692.         cp->tags = ( store[0] == '\0' )? NullTags: save( store );
  693.         n = getw( InFile );
  694.         if( n<=0 ) badfile();
  695.         dput = &(cp->list);     /* link on here */
  696.         while(n--){
  697.                 dp = (defn *)my_alloc( (unsigned) sizeof( defn));
  698.                 *dput = dp;
  699.                 dp->cumul = getw( InFile );
  700.                 instring(store, MAXDEF );
  701.                 dp->string = save( store );
  702.                 dput = &(dp->next);
  703.         }
  704.         *dput = NULL;           /* last one */
  705. }
  706.  
  707.  
  708.  
  709. void print(line) char *line;  /* output text, breaking on word bounds */
  710. {
  711.  for( ; *line ; line++)
  712.    printc(*line);
  713. }
  714.  
  715. static char linebuf [LINE_WIDTH+1];  /* text awaiting output */
  716. static int col = 0;   /* column position */
  717. void printc(ch) char ch;  
  718. {
  719.   if(isspace(ch)) /* think about flushing */
  720.   {
  721.     if((ch == '\n') || (ch == '\r'))
  722.     {
  723.      puts(linebuf);
  724.      linebuf[0] = 0;
  725.      col = 0;
  726.      return;
  727.     }
  728.     if((col + strlen(linebuf) > LINE_WIDTH) && col)
  729.     {
  730.      putchar('\n');
  731.      fputs(linebuf, stdout);
  732.      putchar(ch);
  733.      col = strlen(linebuf) + 1;
  734.      linebuf[0] = 0;     
  735.      return;
  736.     }
  737.     if(col + strlen(linebuf) > LINE_WIDTH)
  738.     {
  739.      puts(linebuf);
  740.      linebuf[0] = 0;
  741.      return;
  742.     }
  743.     fputs(linebuf, stdout);
  744.     col += strlen(linebuf);
  745.     *linebuf = 0;
  746.     if(col < LINE_WIDTH)
  747.     {
  748.      col++;
  749.      putchar(' ');
  750.     }
  751.   }
  752.   else
  753.   {
  754.    char *cp;
  755.    cp = linebuf + strlen(linebuf);
  756.    *cp++ = ch;
  757.    *cp = (char)0;
  758.   }
  759.  return;
  760. }
  761.  
  762. instring( where, how_many )
  763. register char *where;
  764. register int how_many;
  765. {
  766.         register int c;
  767.         do{
  768.                 c = getc( InFile );
  769.                 if( c == EOF ) badfile();
  770.                 *where++ = c;
  771.                 if( c== '\0' ) return;
  772.         }while(--how_many);
  773.         badfile();
  774. }
  775. badfile(){
  776.         fprintf(stderr,"Bad file format\n");
  777.         exit(1);
  778. }
  779.