home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3.4.17 [SPARC, PA-RISC] / nextstep33_risc.iso / NextLibrary / TeX / tex / src / texview / dospecial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-27  |  18.0 KB  |  710 lines

  1. /*
  2.  *   This is dvips, a freely redistributable PostScript driver
  3.  *   for dvi files.  It is (C) Copyright 1987 by Tomas Rokicki.
  4.  *   You may modify and use this program to your heart's content,
  5.  *   so long as you send modifications to Tomas Rokicki.  It can
  6.  *   be included in any distribution, commercial or otherwise, so
  7.  *   long as the banner string defined in structures.h is not
  8.  *   modified (except for the version number) and this banner is
  9.  *   printed on program invocation, or can be printed on program
  10.  *   invocation with the -? option.
  11.  */
  12. #define COLOR
  13. /*
  14.  *   dospecial of dvisw package.  (C) 1986 Radical Eye Software.
  15.  *   This routine handles special commands.  Currently the only
  16.  *   special command handled is the landscape special.
  17.  */
  18. #include "structures.h"
  19. #include <dpsclient/dpsclient.h>
  20. #include "paths.h"
  21. #include <string.h>
  22. /*
  23.  *   These are the external routines called:
  24.  */
  25. #ifdef TPIC
  26. extern void setPenSize();
  27. extern void flushPath();
  28. extern void flushDashed();
  29. extern void flushDashed();
  30. extern void addPath();
  31. extern void arc();
  32. extern void flushSpline();
  33. extern void shadeLast();
  34. extern void whitenLast();
  35. extern void blackenLast();
  36. #endif
  37. #ifdef COLOR
  38. extern void pushcolor() ;
  39. extern void popcolor() ;
  40. extern void resetcolorstack() ;
  41. extern void background() ;
  42. static Boolean usescolor ;
  43. #endif
  44. extern void pswrite(), error(), tolandscape(), add_header(), hvpos() ;
  45. extern void copyfile(), figcopyfile() ;
  46. extern void handlepapersize(), newpapersize() ;
  47. extern int dvibyte() ;
  48. extern char *malloc(), *newstring() ;
  49. int GetKeyVal(), IsSame() ;
  50. extern FILE *search() ;
  51. extern void texflush() ;
  52. extern char *inputspath ;
  53. extern Boolean prescan;
  54. extern void writeconsole() ;
  55. extern Boolean firstpage ;
  56. extern Boolean mocked ;
  57. extern Boolean landscape, orientationset ;
  58. extern int debugon ;
  59. extern char *configpath, *headerpath ;
  60. extern void TPSbop(), TPSeop() ;
  61. char nextstring[8192] ;
  62. extern char temperrorbuf[] ;
  63. char *maxstring = nextstring + 8100 ;
  64. static integer hpapersize, vpapersize ;
  65. /*
  66.  *   These definitions are used by the \special command.
  67.  */
  68. typedef enum {None, String, Integer, Number, Dimension} ValTyp;
  69. typedef struct {
  70.    char    *Key;           /* the keyword string */
  71.    char    *Val;           /* the value string */
  72.    ValTyp  vt;             /* the value type */
  73.    union {                 /* the decoded value */
  74.       long i;
  75.       float n;
  76.    } v;
  77. } KeyWord;
  78. typedef struct {
  79.    char    *Entry;
  80.    ValTyp  Type;
  81. } KeyDesc;
  82. /*
  83.  *   Now our routine.  We get the number of bytes specified and place them
  84.  *   into the string buffer, and then parse it for alpha.  Interpret a 
  85.  *   \special command, made up of keyword=value pairs.
  86.  */
  87.  
  88. #define NKEYS    (sizeof(KeyTab)/sizeof(KeyTab[0]))
  89.  
  90. KeyDesc KeyTab[] = {{"psfile",  String},
  91.                     {"ifffile", String},
  92.                     {"tekfile", String},
  93.                     {"hsize",   Number},
  94.                     {"vsize",   Number},
  95.                     {"hoffset", Number},
  96.                     {"voffset", Number},
  97.                     {"hscale",  Number},
  98.                     {"vscale",  Number},
  99.                     {"angle",   Number},
  100.                     {"llx", Number},
  101.                     {"lly", Number},
  102.                     {"urx", Number},
  103.                     {"ury", Number},
  104.                     {"rwi", Number},
  105.                     {"rhi", Number},
  106.                     {"clip", None}};
  107.  
  108. char  *GetKeyStr();
  109. void  fil2ps();
  110. char  task[7] = "\0";
  111.  
  112. struct bangspecial {
  113.    struct bangspecial *next ;
  114.    char actualstuff[4] ;
  115. } *bangspecials = NULL ;
  116.  
  117. static void trytobreakout(p)
  118. register char *p ;
  119. {
  120.    pswrite(" ") ;
  121.    pswrite(p) ;
  122.    pswrite(" ") ;
  123. }
  124.  
  125. static void dobs(q)
  126. register struct bangspecial *q ;
  127. {
  128.    if (q) {
  129.       dobs(q->next) ;
  130.       trytobreakout(q->actualstuff) ;
  131.    }
  132. }
  133.  
  134. void special_header() {
  135.    static int sent = 0 ;
  136.  
  137.    if (! sent) {
  138.       texflush() ;
  139. #ifdef POPRESTORE
  140.       TPSeop() ;
  141. #endif
  142.       add_header("special.pro") ;
  143. #ifdef POPRESTORE
  144.       TPSbop() ;
  145. #endif
  146.       hvpos() ;
  147.       sent = 1 ;
  148.    }
  149. }
  150.  
  151. void outbangspecials() {
  152.    if (bangspecials) {
  153.       special_header() ;
  154.       pswrite(" @defspecial ") ;
  155.       dobs(bangspecials) ;
  156.       pswrite(" @fedspecial ") ;
  157.    }
  158. }
  159.  
  160. #define TRUE (1)
  161. #define FALSE (0)
  162.  
  163. void dospecial(numbytes)
  164. integer numbytes ;
  165. {
  166.    register char *p = nextstring ;
  167.    register int i = 0 ;
  168.    int j ;
  169.    Boolean ps = TRUE ;
  170.    char spbuf[100] ; 
  171.    char fbuf[100] ; 
  172.    char *sf = NULL ;
  173.    char *f = NULL ;
  174.    KeyWord k ;
  175.  
  176.    temperrorbuf[0] = 0 ;
  177.    if (nextstring + i > maxstring)
  178.       error("! out of string space in dospecial") ;
  179.    for (i=numbytes; i>0; i--)
  180.       *p++ = dvibyte() ;
  181.    *p = 0 ;
  182.    p = nextstring ;
  183. #ifdef DEBUG
  184.    if (debugon > 3) {
  185.       printf("{%s}", p) ;
  186.       fflush(stdout) ;
  187.    }
  188. #endif
  189.    while (*p <= ' ' && *p)
  190.       p++ ;
  191.  
  192.    if (strncmp(p, "landscape", 9)==0) {
  193.       if (prescan && firstpage)
  194.          tolandscape() ;
  195.       return ;
  196.    } else if (strncmp(p, "papersize", 9)==0) {
  197.       p += 9 ;
  198.       while (*p == '=' || *p == ' ')
  199.          p++ ;
  200.       handlepapersize(p, &hpapersize, &vpapersize) ;
  201.       if (prescan && firstpage)
  202.          newpapersize(hpapersize, vpapersize) ;
  203.       return ;
  204.    }
  205. /* ignore this special for now */
  206.    if (strncmp(p, "hp:", 3)==0)
  207.       return ;
  208.    if (! prescan)
  209.       special_header() ;
  210.    if (strncmp(p, "header", 6)==0) {
  211.       if (prescan) {
  212.          char *q ;
  213.          p += 6 ;
  214.          while ((*p <= ' ' || *p == '=' || *p == ')') && *p != 0)
  215.             p++ ;
  216.          q = p ;
  217.          p = p + strlen(p) - 1 ;
  218.          if (*p == ')') {
  219.             p-- ;
  220.             while (*p <= ' ')
  221.                p-- ;
  222.             p[1] = 0 ;
  223.          }
  224.          add_header(q) ;
  225.        }
  226.        return ;
  227. #ifdef COLOR
  228.    }
  229.    if (strncmp(p, "background", 10) == 0) {
  230.       if (usescolor == 0) {
  231.          add_header("color.pro") ;
  232.          usescolor = 1 ;
  233.       }
  234.       p +=11 ;
  235.       while ( *p <= ' ' ) p++ ;
  236.       background(p) ;
  237.       return ;
  238.    }
  239.    if (strncmp(p, "color", 5) == 0) {
  240.       if (usescolor == 0) {
  241.          add_header("color.pro") ;
  242.          usescolor = 1 ;
  243.       }
  244.       p += 6 ;
  245.       while ( *p <= ' ' ) p++ ;
  246.       if (strncmp(p, "push", 4) == 0 ) {
  247.          p += 4 ;
  248.       while (*p && *p <= ' ' ) p++ ;
  249.          pushcolor(p,!prescan) ;
  250.       } else if (strncmp(p, "pop", 3) == 0 ) {
  251.          popcolor(!prescan) ;
  252.       } else {
  253.          resetcolorstack(p,!prescan) ;
  254.       }
  255.       return ;
  256. #endif
  257.    } else if (strncmp(p, "ps:", 3)==0) {
  258.       if (! prescan) {
  259.         hvpos() ;
  260.         texflush() ;
  261.     if (strncmp(p, "ps::[begin]", 11) == 0)
  262.        pswrite(&p[11]);
  263.     else if (strncmp(p, "ps::[end]", 9) == 0)
  264.        pswrite(&p[9]);
  265.     else if (strncmp(p, "ps: plotfile ", 13) == 0) {
  266.            char *sfp ;
  267.        p += 13;
  268.            while (*p == ' ') p++ ;
  269.            if (*p == '"') {
  270.               p++ ;
  271.               for (sfp = p; *sfp && *sfp != '"'; sfp++) ;
  272.            } else {
  273.               for (sfp = p; *sfp && *sfp != ' '; sfp++) ;
  274.            }
  275.            *sfp = 0 ;
  276.            if (*p == '`')
  277.               figcopyfile (p+1, 1);
  278.            else
  279.               figcopyfile (p, 0);
  280.     } else if (strncmp(p, "ps::", 4) == 0)
  281.        pswrite(&p[4]);
  282.     else
  283.        pswrite(&p[3]);
  284.     return;
  285.       }
  286.    }
  287. #ifdef TPIC
  288.    else if (strncmp(p, "pn ", 3) == 0) {if (!prescan) setPenSize(p+2);}
  289.    else if (strncmp(p, "fp",2) == 0) {if (!prescan) flushPath();}
  290.    else if (strncmp(p, "da ", 3) == 0) {if (!prescan) flushDashed(p+2, 0);}
  291.    else if (strncmp(p, "dt ", 3) == 0) {if (!prescan) flushDashed(p+2, 1);}
  292.    else if (strncmp(p, "pa ", 3) == 0) {if (!prescan) addPath(p+2);}
  293.    else if (strncmp(p, "ar ", 3) == 0) {if (!prescan) arc(p+2);}
  294.    else if (strncmp(p, "sp", 2) == 0) {if (!prescan) flushSpline();}
  295.    else if (strncmp(p, "sh", 2) == 0) {if (!prescan) shadeLast();}
  296.    else if (strncmp(p, "wh", 2) == 0) {if (!prescan) whitenLast();}
  297.    else if (strncmp(p, "bk", 2) == 0) {if (!prescan) blackenLast();}
  298.    else if (strncmp(p, "tx ", 3) == 0)
  299.       {error("\\special texture command -- ignored");}
  300. #endif
  301.    else {
  302.       if (prescan && *p == '!' && firstpage) {
  303.          struct bangspecial *q ;
  304.          void *mymalloc() ;
  305.    
  306.          p++ ;
  307.          q = (struct bangspecial *)mymalloc(sizeof(struct bangspecial) + strlen(p)) ;
  308.          strcpy(q->actualstuff, p) ;
  309.          q->next = bangspecials ;
  310.          bangspecials = q ;
  311.          return ;
  312.       }
  313.    
  314.       if (! prescan) {
  315.          if (*p == '"') {
  316.             hvpos();
  317.             pswrite(" @beginspecial @setspecial ") ;
  318.             trytobreakout(p+1) ;
  319.             pswrite(" @endspecial ") ;
  320.             return ;
  321.          } else if (*p == '!')
  322.             return ;
  323.       
  324.          spbuf[0] = '\0';
  325.    
  326.          hvpos();
  327.    
  328.          pswrite(" @beginspecial ");
  329.    
  330.          /* get all keyword-value pairs; for compatibility, 
  331.          single words are taken as file names */
  332.  
  333.       while( (p=GetKeyStr(p,&k)) != NULL ) {
  334.             if( GetKeyVal( &k, KeyTab, NKEYS, &j ) && j != -1 ) {
  335.                if( j >= 0 && j <= 2 ) {
  336.                   if( sf ) {
  337.                      fprintf(stderr, " more than one \\special file name given: %s ignored.", sf );
  338.                   }
  339.                   strcpy(fbuf, k.Key);
  340.                   strcpy(spbuf, k.Val);
  341.                   f = fbuf;
  342.                   sf = spbuf;
  343.                   if( j == 1 || j == 2)
  344.                      ps = FALSE;
  345.                } else { /* keywords are output as PS procedure calls */
  346.                   if(k.vt == Integer)
  347.                      sprintf(temperrorbuf, "%ld @%s ", k.v.i, KeyTab[j].Entry);
  348.                   else if (k.vt == None)
  349.                      sprintf(temperrorbuf, " @%s ", KeyTab[j].Entry);
  350.                   else
  351.                      sprintf(temperrorbuf, "%f @%s ", k.v.n, KeyTab[j].Entry);
  352.                   pswrite(temperrorbuf) ;
  353.                }
  354.             } else {
  355.                fprintf(stderr, " invalid  keyword or value in \\special: \"%s\" ignored.", k.Key );
  356.             }
  357.       }
  358.  
  359.       pswrite(" @setspecial ");
  360.  
  361.       if( sf ) {
  362.             if (*sf == '`')
  363.                figcopyfile(sf+1, 1);
  364.             else
  365.                figcopyfile(sf, 0);
  366.       } else
  367.          fprintf(stderr, " no special file name provided.");
  368.       pswrite(" @endspecial ");
  369.       }
  370.    }
  371. }
  372.  
  373. /*
  374.  * extract first keyword-value pair from string (value part may be null)
  375.  * return pointer to remainder of string return NULL if none found
  376.  */
  377.  
  378. char    KeyStr[200];
  379. char    ValStr[200];
  380.  
  381. char *GetKeyStr( str, kw )
  382. char    *str;
  383. KeyWord *kw;
  384. {
  385.    char *s, *k, *v, t;
  386.  
  387.    if( !str ) 
  388.       return( NULL );
  389.  
  390.    for( s=str; *s == ' '; s++ )            /* skip over blanks */
  391.       ;
  392.    if( *s == '\0' ) 
  393.       return( NULL );
  394.  
  395.    /* extract keyword portion */
  396.  
  397.    for( k=KeyStr; *s != ' ' && *s != '\0' && *s != '='; *k++ = *s++ )
  398.       ;
  399.    *k = '\0';
  400.    kw->Key = KeyStr;
  401.    kw->Val = v = NULL;
  402.    kw->vt = None;
  403.  
  404.    for( ; *s && *s == ' '; s++ )                 /* skip over blanks */
  405.       ;
  406.    if( *s != '=' )                         /* look for "=" */
  407.       return( s );
  408.  
  409.    for( s++ ; *s && *s == ' '; s++ )             /* skip over blanks */
  410.       ;
  411.    if( *s == '\'' || *s == '\"' )          /* get string delimiter */
  412.       t = *s++;
  413.    else
  414.       t = ' ';
  415.  
  416.    /* copy value portion up to delimiter */
  417.  
  418.    for( v=ValStr; *s != t && *s != '\0'; *v++ = *s++ )
  419.       ;
  420.    if( t != ' ' && *s == t )
  421.       s++;
  422.    *v = '\0';
  423.    kw->Val = ValStr;
  424.    kw->vt = String;
  425.  
  426.    return( s );
  427. }
  428.  
  429. /*
  430.  * get next keyword-value pair decode value according to table entry
  431.  */
  432.  
  433. int GetKeyVal( kw, tab, nt, tno)
  434. KeyWord *kw; 
  435. KeyDesc tab[];
  436. int     nt;
  437. int     *tno;
  438. {
  439.    int i;
  440.    char c = '\0';
  441.  
  442.    *tno = -1;
  443.  
  444.    for(i=0; i<nt; i++)
  445.       if( IsSame(kw->Key, tab[i].Entry) ) {
  446.          *tno = i;
  447.          switch( tab[i].Type ) {
  448.             case None: 
  449.                if( kw->vt != None ) 
  450.                   return( 0 );
  451.                break;
  452.             case String:
  453.                if( kw->vt != String ) 
  454.                   return( 0 );
  455.                break;
  456.             case Integer:
  457.                if( kw->vt != String ) 
  458.                   return( 0 );
  459.                if( sscanf(kw->Val,"%ld%c", &(kw->v.i), &c) != 1 || c != '\0' ) 
  460.                   return( 0 );
  461.                break;
  462.             case Number:
  463.             case Dimension:
  464.                if( kw->vt != String ) 
  465.                   return( 0 );
  466.                if( sscanf(kw->Val,"%f%c", &(kw->v.n), &c) != 1 || c != '\0' ) 
  467.                   return( 0 );
  468.                break;
  469.          }
  470.          kw->vt = tab[i].Type;
  471.          return( 1 );
  472.       }
  473.  
  474.       return( 1 );
  475. }
  476.  
  477. /*
  478.  * compare strings, ignore case
  479.  */
  480. int Tolower(c)
  481. register int c ;
  482. {
  483.    if ('A' <= c && c <= 'Z')
  484.       return(c+32) ;
  485.    else
  486.       return(c) ;
  487. }
  488. int IsSame(a, b)
  489. char *a, *b;
  490. {
  491.    for( ; *a != '\0'; )
  492.       if( Tolower(*a++) != Tolower(*b++) ) 
  493.          return( 0 );
  494.       return( *a == *b ? 1 : 0 );
  495. }
  496.  
  497. void pswrite(s)
  498. char *s ;
  499. {
  500.    DPSWritePostScript(DPSGetCurrentContext(), s, strlen(s)) ;
  501. }
  502.  
  503. void qstatus() ;
  504.  
  505. /*
  506.  *   This routine copies a file down the pipe.  Search path uses the
  507.  *   header path.
  508.  *
  509.  *   We add code to handle the case of MS-DOS font files.
  510.  *
  511.  *   Format:  80 {01,02} four byte length in littleendian order data
  512.  *   repeated possibly multiple times.
  513.  */
  514. static char *hxdata = "0123456789ABCDEF" ;
  515. static int infigure ;
  516. void
  517. copyfile(s)
  518.         char *s ;
  519. {
  520.    FILE *f = NULL ;
  521.    int c, prevc = '\n' ;
  522.    long len ;
  523.    char nextstring[2000] ;
  524.  
  525.    switch (infigure) {
  526.    case 1:
  527.       f = search(inputspath, s, "r") ;
  528.       (void)sprintf(temperrorbuf, "Couldn't open figure file %s", s) ;
  529.       break ;
  530.    default:
  531.       f = search(headerpath, s, "r") ;
  532.       (void)sprintf(temperrorbuf, "Couldn't open header file %s", s) ;
  533.       break ;
  534.    case 2:
  535. #ifdef SECURE
  536.       (void)sprintf(temperrorbuf, "<%s>: Tick filename execution disabled", s) ;
  537. #else
  538.       writeconsole(s) ;
  539.       f = popen(s, "r") ;
  540.       (void)sprintf(temperrorbuf, "Failure to execute %s; continuing", s) ;
  541. #endif
  542.       break;
  543.    }
  544.    if (f==NULL) {
  545.       pswrite(" MockPic ") ;
  546. /*    error(temperrorbuf) ; can't do this; will crash window server to run
  547.                             an alert here; no idea why. */
  548.    } else {
  549.       sprintf(temperrorbuf, "Inserting %s", s) ;
  550.       qstatus(temperrorbuf) ;
  551.       c = getc(f) ;
  552.       if (c == 0x80) {
  553.          while (1) {
  554.             char *p = nextstring ;
  555.  
  556.             c = getc(f) ;
  557.             switch(c) {
  558. case 1:
  559. case 2:
  560.                len = getc(f) ;
  561.                len += getc(f) * 256L ;
  562.                len += getc(f) * 65536L ;
  563.                len += getc(f) * 256L * 65536 ;
  564.                if (c == 1) {
  565.                   while (len > 0) {
  566.                      c = getc(f) ;
  567.                      if (c == EOF) {
  568.                         error("premature EOF in MS-DOS font file") ;
  569.                         len = 0 ;
  570.                      } else if (c == 10 || c == 13) {
  571.                         *p++ = 10 ;
  572.                         *p++ = 0 ;
  573.                         pswrite(nextstring) ;
  574.                         p = nextstring ;
  575.                         len-- ;
  576.                      } else {
  577.                         *p++ = c ;
  578.                         len-- ;
  579.                      }
  580.                   }
  581.                } else {
  582.                   if (p > nextstring) {
  583.                      *p++ = 10 ;
  584.                      *p++ = 0 ;
  585.                      pswrite(nextstring) ;
  586.                      p = nextstring ;
  587.                   }
  588.                   prevc = 0 ;
  589.                   while (len > 0) {
  590.                      c = getc(f) ;
  591.                      if (c == EOF) {
  592.                         error("premature EOF in MS-DOS font file") ;
  593.                         len = 0 ;
  594.                      } else {
  595.                         *p++ = hxdata[c >> 4] ;
  596.                         *p++ = hxdata[c & 15] ;
  597.                         len-- ;
  598.                         prevc += 2 ;
  599.                         if (prevc >= 76) {
  600.                            *p++ = 10 ;
  601.                            *p = 0 ;
  602.                            pswrite(nextstring) ;
  603.                            p = nextstring ;
  604.                            prevc = 0 ;
  605.                         }
  606.                      }
  607.                   }
  608.                   if (prevc) {
  609.                      *p++ = 10 ;
  610.                      *p = 0 ;
  611.                      pswrite(nextstring) ;
  612.                      p = nextstring ;
  613.                      prevc = 0 ;
  614.                   }
  615.                }
  616.                break ;
  617. case 3:
  618.                goto msdosdone ;
  619. default:
  620.                error("saw type other than 1, 2, or 3 in MS-DOS font file") ;
  621.                break ;
  622.             }
  623.             c = getc(f) ;
  624.             if (c == EOF)
  625.                break ;
  626.             if (c != 0x80) {
  627.                error("saw non-MSDOS header in MSDOS font file") ;
  628.                break ;
  629.             }
  630.          }
  631. msdosdone: ;
  632.       } else {
  633.          ungetc(c, f) ;
  634.          while (fgets(nextstring, 2000, f))
  635.             pswrite(nextstring) ;
  636.       }
  637.       if (infigure == 2)
  638.          (void)pclose(f) ;
  639.       else
  640.          (void)fclose(f) ;
  641.    }
  642. }
  643.  
  644. /*
  645.  *   For included PostScript graphics, we use the above routine, but
  646.  *   with no fatal error message.
  647.  */
  648. void figcopyfile(s, systemtype)
  649. char *s ;
  650. int systemtype ;
  651. {
  652.    infigure = (systemtype ? 2 : 1) ;
  653.    if (mocked)
  654.       pswrite(" MockPic ");
  655.    else
  656.       copyfile(s) ;
  657.    infigure = 0 ;
  658. }
  659.  
  660. void cleartheair() {
  661.    outbangspecials() ;
  662. }
  663. struct header_list {
  664.    char *name ;
  665.    struct header_list *next ;
  666. } *header_head ;
  667. /*
  668.  *   The external routines we use.
  669.  */
  670. extern void copyfile() ;
  671. #ifdef DEBUG
  672. extern integer debug_flag ;
  673. #endif
  674. /*
  675.  *   This more general routine adds a name to a list of unique
  676.  *   names.
  677.  */
  678. int
  679. add_name(s, what)
  680.    char *s ;
  681.    struct header_list **what ;
  682. {
  683.    struct header_list *p, *q ;
  684.  
  685.    for (p = *what ; p != NULL; p = p->next)
  686.       if (strcmp(p->name, s)==0)
  687.          return 0 ;
  688.    q = (struct header_list *)malloc((unsigned)sizeof(struct header_list)) ;
  689.    if (q==NULL)
  690.       error("! out of memory") ;
  691.    q->next = NULL ;
  692.    q->name = newstring(s) ;
  693.    if (*what == NULL)
  694.       *what = q ;
  695.    else {
  696.       for (p = *what; p->next != NULL; p = p->next) ;
  697.       p->next = q ;
  698.    }
  699.    return 1 ;
  700. }
  701. /*
  702.  *   This routine is responsible for adding a header file.
  703.  */
  704. void add_header(s)
  705. char *s ;
  706. {
  707.    if (add_name(s, &header_head))
  708.       copyfile(s) ;
  709. }
  710.