home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume3 / texchk / part2 / ctools.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  18.6 KB  |  923 lines

  1. /* -*- Mode: C; Package: (CTOOLS C) -*- */
  2.  
  3. #include <ctype.h>
  4. #include <stdio.h>
  5.  
  6. /* if your system doesn't have either string.h or strings.h you may have to */
  7. /* declare the string functions yourself */
  8. #ifdef BSD42
  9. #include <strings.h>
  10. #else
  11. #include <string.h>
  12. #endif
  13.  
  14. #ifdef TMC
  15. #include "newctools.h"
  16. #else
  17. #include "ctools.h"
  18. #endif
  19.  
  20. /* miscellaneous fairly primitive routines that deal with characters, */
  21. /* strings, memory, simple input and pathnames. */
  22.  
  23.  
  24. /* Author:  JP Massar */
  25. /* Thinking Machines Corporation */
  26.  
  27. /* Included routines:
  28.  
  29.    emalloc
  30.    anewstr
  31.    
  32.    copy
  33.    fill
  34.    
  35.    to_upper_if_lower
  36.    to_lower_if_upper
  37.    
  38.    buffconcat
  39.    nbuffconcat
  40.    
  41.    slcompare
  42.    slge_compare
  43.    nocase_compare
  44.    
  45.    strfind
  46.    strncfind
  47.    strsearch
  48.    strncsearch
  49.    
  50.    yes_or_no_check
  51.    
  52.    remove_excess_blanks
  53.    
  54.    all_digits
  55.    all_whitespace
  56.    all_uppercase
  57.    all_lowercase
  58.    all_alphabetic
  59.    all_alphanumeric
  60.    all_ascii
  61.    
  62.    str_to_pos_int
  63.    
  64.    sreverse
  65.    ip_sreverse
  66.         
  67.    temp_path
  68.    perm_path
  69.    make_path_numeric_extension
  70.    make_path
  71.    just_filename
  72.    
  73.    read_yes_or_no
  74.    getline
  75.    getlines
  76.    ngetlines
  77.    getfile
  78.    ngetfile
  79.    read_file_into_buffer
  80.    efopen
  81.  
  82.    check_int
  83.    check_string
  84.    
  85. */
  86.    
  87.  
  88. extern char *malloc();
  89.  
  90.  
  91. char *emalloc (space) int space;
  92.  
  93. /* allocate 'space' bytes, die if we have run out of memory. */
  94.  
  95. {
  96.   char *rval;        
  97.   if (space < 0) {
  98.      fprintf(stderr,"Fatal error: argument to emalloc < 0\n");
  99.      exit(-1);
  100.   }
  101.   if (0 == (rval = malloc((unsigned) space))) {
  102.      fprintf(stderr,"Fatal error:  No more memory\n");
  103.      exit(-1);
  104.   }
  105.   return(rval);
  106. }  
  107.  
  108.  
  109. char *anewstr (astring) char *astring;
  110.  
  111. /* allocate space for and then copy a string.  Returns pointer to */
  112. /* new string. */
  113.  
  114. {        
  115.   char *newstr;
  116.   newstr = emalloc(strlen(astring)+1);
  117.   strcpy(newstr,astring);
  118.   return(newstr);
  119. }
  120.  
  121.  
  122. copy (dest,src,n)
  123.  
  124.   /* copy n bytes */
  125.  
  126.   register char *dest,*src;
  127.   register int n;
  128.  
  129.   { register int j = 0;
  130.     while (j++ < n) *dest++ = *src++; 
  131.   }
  132.  
  133.  
  134. fill (addr,ch,n)
  135.  
  136.   /* fill n sequential bytes with 'ch' */
  137.  
  138.   register char *addr;
  139.   register char ch;
  140.   register int n;
  141.   
  142.   { register int j = 0;
  143.     while (j++ < n) *addr++ = ch;
  144.   }
  145.  
  146.  
  147. to_upper_if_lower (ch)
  148.  
  149.   char ch;
  150.  
  151.   { return(islower(ch) ? toupper(ch) : ch); }
  152.  
  153.  
  154. to_lower_if_upper (ch)
  155.  
  156.   char ch;
  157.  
  158.   { return(isupper(ch) ? tolower(ch) : ch); }
  159.  
  160.  
  161. buffconcat (buffer,s1,s2) 
  162.  
  163.   /* concatenate two null terminated strings into a buffer. */
  164.  
  165.   char *buffer, *s1, *s2;
  166.   
  167.   { while (*s1 != '\0') *buffer++ = *s1++;
  168.     while (*s2 != '\0') *buffer++ = *s2++;
  169.     *buffer = '\0';
  170.   }
  171.  
  172.  
  173. nbuffconcat (buffer,n,s1,s2,s3,s4,s5,s6)
  174.  
  175.   /* concatenates up to 6 strings into a buffer.  Returns -1 if n */
  176.   /* is not reasonable, otherwise returns 0. */
  177.  
  178.   char *buffer;
  179.   int n;
  180.   char *s1,*s2,*s3,*s4,*s5,*s6;
  181.  
  182. {
  183.   register char *b;
  184.   register char *s;
  185.   int i;
  186.   b = buffer;
  187.   if (n < 1 || n > 6) return(-1);
  188.   for (i = 1; i <= 6; i++) {
  189.       if (i > n) break;
  190.       switch (i) {
  191.         case 1 : s = s1; break;
  192.         case 2 : s = s2; break;
  193.         case 3 : s = s3; break;
  194.         case 4 : s = s4; break;
  195.         case 5 : s = s5; break;
  196.         case 6 : s = s6; break;
  197.       }
  198.       while (*s != '\0') *b++ = *s++;
  199.   }
  200.   *b = '\0';
  201.   return(0);
  202. }
  203.  
  204.  
  205. slcompare (s1,l1,s2,l2)
  206.  
  207.   /* compare strings with possible nulls in them given their lengths */
  208.   /* only returns EQUAL (0) or NOT EQUAL (-1) */
  209.  
  210.   char *s1;
  211.   int l1;
  212.   char *s2;
  213.   int l2;
  214.  
  215.   { int j;
  216.     if (l1 != l2) return(-1);
  217.     j = 0;
  218.     while (j++ < l1) 
  219.       if (*s1++ != *s2++) return(-1);
  220.     return(0);
  221.   }
  222.  
  223.   
  224. slge_compare (s1,l1,s2,l2)
  225.  
  226.   /* returns -1 if s1 < s2; 1 if s2 < s1; 0 if s1 = s2 */
  227.   /* ignores nulls in the strings */
  228.  
  229.   char *s1;
  230.   int l1;
  231.   char *s2;
  232.   int l2;
  233.  
  234.   { int j,len;
  235.     j = 0;
  236.     len = l2 > l1 ? l1 : l2;
  237.     while (j++ < len) {
  238.       if (*s1 != *s2) 
  239.          return((*s1 < *s2) ? -1 : 1);
  240.       s1++;   
  241.       s2++;
  242.     }  
  243.     return((l2 == l1) ? 0 : ((l1 < l2) ? -1 : 1));
  244.   }
  245.  
  246. nocase_compare (s1,l1,s2,l2)
  247.  
  248.   /* treats nulls as normal characters.  Returns same as slge_compare */
  249.  
  250.   char *s1;
  251.   int l1;
  252.   char *s2;
  253.   int l2;
  254.  
  255.   { int j,len,ch1,ch2;
  256.     j = 0;
  257.     len = l2 > l1 ? l1 : l2;
  258.     while (j++ < len) {
  259.       ch1 = to_upper_if_lower(*s1++);
  260.       ch2 = to_upper_if_lower(*s2++);
  261.       if (ch1 != ch2) {
  262.          return((ch1 < ch2) ? -1 : 1);
  263.       }
  264.     }  
  265.     return((l2 == l1) ? 0 : ((l1 < l2) ? -1 : 1));
  266.   }
  267.  
  268.  
  269. char *strfind(s1,s2,fast)  
  270.   
  271.   register char *s1;
  272.   char *s2;
  273.   Bool fast;
  274.   
  275. {  
  276.   register int len1,len2;
  277.   len2 = strlen(s2);
  278.   if (fast) {
  279.      while (*s1 != '\0')
  280.        if (0 == strncmp(s1++,s2,len2)) return(s1-1);
  281.   }  
  282.   else {
  283.      len1 = strlen(s1);
  284.      while (len1 >= len2) {
  285.        if (0 == strncmp(s1++,s2,len2)) return(s1-1);
  286.        len1--;
  287.      }
  288.   }
  289.   return(0);
  290. }     
  291.  
  292.  
  293. char *strncfind(s1,s2,fast)
  294.  
  295.   register char *s1;
  296.   char *s2;
  297.   Bool fast;
  298.   
  299. {  
  300.   register int len1,len2;
  301.   len2 = strlen(s2);
  302.   if (fast) {
  303.      while (*s1 != '\0')
  304.        if (0 == nocase_compare(s1++,len2,s2,len2)) return(s1-1);
  305.   }
  306.   else {
  307.      len1 = strlen(s1);
  308.      while (len1 >= len2) {
  309.        if (0 == nocase_compare(s1++,len2,s2,len2)) return(s1-1);
  310.        len1--;
  311.      }
  312.   }
  313.   return(0);
  314. }  
  315.  
  316.   
  317. char *strsearch(s1,s1len,s2,s2len)
  318.  
  319.   /* do a substring search without noticing nulls */
  320.   /* finds s2 in s1, returns pointer into s1 or 0 */
  321.  
  322.   register char *s1, *s2;
  323.   register int s1len,s2len;
  324.   
  325.   {  register char *pc;
  326.      register char *bound;
  327.      register char *pctemp;
  328.      register char *s2temp;
  329.      register int j;
  330.  
  331.      bound = s1 + s1len - s2len;
  332.      for (pc = s1; pc <= bound; pc++) {
  333.          pctemp = pc;
  334.          s2temp = s2;
  335.          for (j = 0; j < s2len; j++)
  336.              if (*pctemp++ != *s2temp++) goto not_here;
  337.          return(pc);       
  338.          not_here :
  339.          continue;
  340.      }    
  341.      return(0);
  342. }
  343.  
  344.  
  345. char *strncsearch(s1,s1len,s2,s2len)
  346.  
  347.   /* do a substring search without noticing nulls */
  348.   /* finds s2 in s1, returns pointer into s1 or 0 */
  349.   /* case independent */
  350.  
  351.   register char *s1, *s2;
  352.   register int s1len,s2len;
  353.   
  354.   {  register char *pc;
  355.      register char *bound;
  356.      register char *pctemp;
  357.      register char *s2temp;
  358.      register int j;
  359.      char ch1, ch2;
  360.  
  361.      bound = s1 + s1len - s2len;
  362.      for (pc = s1; pc <= bound; pc++) {
  363.          pctemp = pc;
  364.          s2temp = s2;
  365.          for (j = 0; j < s2len; j++) {
  366.              ch1 = *pctemp++;
  367.              ch2 = *s2temp++;
  368.              if (to_upper_if_lower(ch1) != to_upper_if_lower(ch2))
  369.                 goto not_here;
  370.          }
  371.          return(pc);       
  372.          not_here :
  373.          continue;
  374.      }    
  375.      return(0);
  376. }
  377.  
  378.  
  379. int remove_excess_blanks (newstring,oldstring) 
  380.  
  381.   /* it is assumed that newstring is as long as oldstring if necessary */
  382.  
  383.   char *newstring,*oldstring;
  384.  
  385. {
  386.   int count = 0;
  387.   int space_found = 0;
  388.  
  389.   /* skip over all blanks at beginning */
  390.   
  391.   if (*oldstring == ' ') {
  392.      while (*oldstring == ' ') oldstring++;
  393.   }
  394.  
  395.   while (*oldstring != '\0') {
  396.         if (space_found && *oldstring == ' ') {
  397.            oldstring++;
  398.            continue;
  399.         }
  400.         space_found = (*oldstring == ' ');
  401.         *newstring++ = *oldstring++;
  402.         count++;
  403.   }
  404.  
  405.   *newstring = '\0';
  406.   if (count > 0 && *(newstring - 1) == ' ') {
  407.      count--;
  408.      *(newstring - 1) = '\0';
  409.   }
  410.  
  411.   return(count);
  412.  
  413. }
  414.  
  415.  
  416. yes_or_no_check (astring) char *astring;
  417.  
  418. /* returns 1 if yes, 0 if no, -1 if neither */
  419. /* works for 'Y' 'YES' 'NO' 'N' in any capitalization */
  420.  
  421. {  
  422.   int len;
  423.   len = strlen(astring);
  424.   if (len == 0 || len > 3) return(-1);
  425.   if (0 == nocase_compare(astring,len,"YES",3) || 
  426.       0 == nocase_compare(astring,len,"Y",1))
  427.      return(1);
  428.   if (0 == nocase_compare(astring,len,"NO",2) || 
  429.       0 == nocase_compare(astring,len,"N",1))
  430.      return(0);
  431.   return(-1);
  432. }
  433.  
  434.  
  435. Bool all_digits (astring) char *astring;
  436.  
  437. /* test whether every character is a digit (0-9) */
  438.  
  439. {
  440.   while (*astring != '\0') 
  441.     if (!isdigit(*astring++)) return(F);
  442.   return(T);
  443. }
  444.  
  445.  
  446. Bool all_whitespace (astring) char *astring;
  447.  
  448. /* test whether every character is a blank or a tab */
  449.  
  450. {
  451.   register char ch;
  452.   while ((ch = *astring++) != '\0') {
  453.     if (ch == ' ' || ch == '\t') continue;
  454.     return(F);
  455.   }
  456.   return(T);
  457. }
  458.  
  459. Bool all_uppercase(astring) char *astring;
  460. {
  461.   register char ch;
  462.   while ((ch = *astring++) != '\0') {
  463.     if (!isupper(ch)) return(F);
  464.   }
  465.   return(T);
  466. }
  467.  
  468. Bool all_lowercase(astring) char *astring;
  469. {
  470.   register char ch;
  471.   while ((ch = *astring++) != '\0') {
  472.     if (!islower(ch)) return(F);
  473.   }
  474.   return(T);
  475. }
  476.  
  477. Bool all_alphabetic(astring) char *astring;
  478. {
  479.   register char ch;
  480.   while ((ch = *astring++) != '\0') {
  481.     if (!isalpha(ch)) return(F);
  482.   }
  483.   return(T);
  484. }
  485.  
  486. Bool all_ascii(astring) char *astring;
  487. {
  488.   register char ch;
  489.   while ((ch = *astring++) != '\0') {
  490.     if (!isascii(ch)) return(F);
  491.   }
  492.   return(T);
  493. }
  494.  
  495. Bool all_alphanumeric(astring) char *astring;
  496. {
  497.   register char ch;
  498.   while ((ch = *astring++) != '\0') {
  499.     if (!isalnum(ch)) return(F);
  500.   }
  501.   return(T);
  502. }
  503.  
  504. int str_to_pos_int (astring,low,high) char *astring; int low,high;
  505.  
  506.   /* returns -1 if *astring is not composed of digits. */
  507.   /* returns -2 if the integer is out of range. */
  508.   /* treats all digit strings as decimal. */
  509.  
  510. {
  511.   int value,len,maxlen,j;
  512.   maxlen = strlen(MAXINTSTR);
  513.   len = strlen(astring);
  514.   if (!all_digits(astring)) return(-1);
  515.   if (len > maxlen) return(-2);
  516.   if (len == maxlen) {
  517.      if (1 == strcmp(astring,MAXINTSTR)) return(-2);
  518.   }
  519.   for (j = 0; j < len-1; j++) {
  520.       if (*astring != '0') break;
  521.       astring++;
  522.   }
  523.   sscanf(astring,"%d",&value);
  524.   if (value < low || value > high) return(-2);
  525.   return(value);
  526. }
  527.  
  528.  
  529. int sreverse (buffer,astring) char *buffer, *astring;
  530. {
  531.   register int last = strlen(astring);
  532.   buffer[last--] = '\0';
  533.   while (last >= 0) buffer[last--] = *astring++;
  534. }
  535.  
  536. char * ip_sreverse (astring) char *astring;
  537. {
  538.   register int last = strlen(astring) - 1;
  539.   register int first = 0;
  540.   register char ch;
  541.   while (first < last) {
  542.     ch = astring[first];
  543.     astring[first++] = astring[last];
  544.     astring[last--] = ch;
  545.   }
  546.   return(astring);
  547. }
  548.  
  549.  
  550.  
  551. static char pathbuffer[PATH_MAXPATHLEN];
  552.  
  553.  
  554. char *temp_path (dir,filename) char *dir; char *filename;
  555.  
  556. {
  557.   return(make_path(dir,filename,"",F));
  558. }
  559.  
  560.  
  561. char *perm_path (dir,filename) char *dir; char *filename;
  562.  
  563. {
  564.   return(make_path(dir,filename,"",T));
  565. }
  566.  
  567.  
  568. char *make_path_numeric_extension (dir,filename,extension,perm)
  569.  
  570.   char *dir, *filename;
  571.   int extension;
  572.   Bool perm;
  573.  
  574. {
  575.   char buffer[20];
  576.   sprintf(buffer,"%d",extension);
  577.   return(make_path(dir,filename,buffer,perm));
  578. }
  579.  
  580.  
  581. char *make_path (dir,filename,extension,perm)
  582.  
  583.   char *dir, *filename, *extension;
  584.   Bool perm;
  585.  
  586. {
  587.   char *rval;
  588.   if (!perm && (strlen(dir) + 1 + strlen(filename) + strlen(extension) + 1 >=
  589.                 PATH_MAXPATHLEN)) {
  590.      return((char *) 0);
  591.   }
  592.   nbuffconcat(pathbuffer,4,dir,"/",filename,extension);
  593.   if (!perm) return(pathbuffer);
  594.   rval = emalloc(strlen(pathbuffer) + 1);  
  595.   strcpy(rval,pathbuffer);
  596.   return(rval);
  597. }
  598.  
  599.  
  600. char *just_filename (path,new,perm) char *path; Bool new,perm;
  601.  
  602. {
  603.   char *fnp,*rval;
  604.   fnp = (0 == (fnp = rindex(path,'/'))) ? path : fnp + 1;
  605.   if (!new) return(fnp);
  606.   if (!perm) {
  607.      strcpy(pathbuffer,fnp);
  608.      return(pathbuffer);
  609.   }
  610.   else {
  611.      rval = emalloc(strlen(fnp) + 1);
  612.      strcpy(rval,fnp);
  613.      return(rval);
  614.   }
  615. }
  616.  
  617.  
  618.  
  619. read_yes_or_no (iport,oport,prompt,helpstring,quitstring)
  620.  
  621.   /* prints prompt, then reads from port until it gets 'Y', 'N', 'YES' or */
  622.   /* 'NO' (case independently).  If helpstring and/or quitstring are not */
  623.   /* "" or (char *) 0 then if the user types in one of those ANSWER_HELP */
  624.   /* or ANSWER_QUIT are returned, otherwise ANSWER_NO or ANSWER_YES are */
  625.   /* eventually returned. */
  626.  
  627.   FILE *iport, *oport;
  628.   char *prompt, *helpstring, *quitstring;
  629.  
  630. {
  631.   char buffer[20],buffer2[20];
  632.   int bl,hl,ql,len;
  633.   
  634.   buffer[19] = '\0';
  635.   
  636.   while (T) {
  637.         
  638.     fprintf(oport,"%s",prompt);
  639.     switch (len = getline(iport,buffer,20)) {
  640.       case (AT_EOF) :
  641.         return(ANSWER_EOF);
  642.         break;
  643.       case (TOO_MANY_CHARS) :
  644.         break;
  645.       default :
  646.         if (0 == (bl = remove_excess_blanks(buffer2,buffer))) break;
  647.         switch (yes_or_no_check(buffer2)) {
  648.           case (0) :
  649.             return(ANSWER_NO);
  650.           case (1) :
  651.             return(ANSWER_YES);
  652.           case (-1) :
  653.             if (helpstring != (char *) 0 && (hl = strlen(helpstring)) > 0) {
  654.                if (0 == nocase_compare(buffer2,bl,helpstring,hl)) {
  655.                   return(ANSWER_HELP);
  656.                }
  657.             }
  658.             if (quitstring != (char *) 0 && (ql = strlen(quitstring)) > 0) {
  659.                if (0 == nocase_compare(buffer2,bl,quitstring,ql)) {
  660.                   return(ANSWER_QUIT);
  661.                }
  662.             }
  663.             break;
  664.         }   
  665.         break;
  666.     }
  667.    
  668.     fprintf(oport,"Please answer 'YES' or 'NO'\n");
  669.     continue;
  670.    
  671.   }
  672.     
  673. }
  674.  
  675.  
  676. int getline (iport,buffer,buflen) FILE *iport; char *buffer; int buflen;
  677.  
  678.   /* reads a line into buffer.  Does not put the '\n' into buffer. */
  679.   /* Returns AT_EOF if at end of file when called.  If it encounters */
  680.   /* end of file after reading at least one character, the eof is treated */
  681.   /* as if it were a newline.   Returns TOO_MANY_CHARS if more than */
  682.   /* buflen - 1 characters are read before encountering a newline. */        
  683.   /* In this case exactly buflen - 1 characters are read. */
  684.   /* The last character read is always follwed by a '\0'. */
  685.   /* if successful getline returns the number of characters read exclusive */
  686.   /* of a terminating newline or eof. */
  687.  
  688. {
  689.   int ch;
  690.   char *bptr = buffer;
  691.   int nchars = 0;
  692.   
  693.   if (buflen <= 0) return(TOO_MANY_CHARS);
  694.   
  695.   while (T) {
  696.     switch (ch = getc(iport)) {
  697.       case (EOF) :
  698.       case ('\n') :
  699.         if (ch == EOF && nchars == 0) return(AT_EOF);
  700.         *bptr = '\0';
  701.         return(nchars);
  702.       default :
  703.         if (++nchars == buflen) { 
  704.            *bptr = '\0';
  705.            ungetc(ch,iport);
  706.            return(TOO_MANY_CHARS);
  707.         }
  708.         *bptr++ = ch;
  709.     }
  710.     
  711.   }
  712.     
  713. }
  714.  
  715.  
  716. int getlines (fp,n,ptr_lines,linebuf,maxlinelen)
  717.  
  718.   /* See documentation for getfile below */
  719.  
  720.   FILE *fp;
  721.   int n;
  722.   char ***ptr_lines;
  723.   char *linebuf;
  724.   int maxlinelen;
  725.  
  726. {
  727.   int len;
  728.   char *line;
  729.   if (0 > (len = getline(fp,linebuf,maxlinelen))) {
  730.      if (len == AT_EOF) {
  731.         *ptr_lines = (char **) emalloc(n * sizeof(char **));
  732.         return(n);
  733.      }
  734.      else {
  735.         return(TOO_MANY_CHARS);
  736.      }
  737.   }
  738.   else {
  739.      line = emalloc(len+1);
  740.      strcpy(line,linebuf);
  741.      len = getlines(fp,n+1,ptr_lines,linebuf,maxlinelen);
  742.      if (len == TOO_MANY_CHARS) return(TOO_MANY_CHARS);
  743.      (*ptr_lines)[n] = line;
  744.      return(len);
  745.   }
  746. }
  747.  
  748.  
  749. int getfile (filename,ptr_lines,linebuf,maxlinelen)
  750.  
  751.   /* read in a file as an array of character strings */
  752.   /* 'maxlinelen+1' is the maximum length a line of the file is allowed */
  753.   /* to be.  'linebuf' must be at least 'maxlinelen+1' characters long. */
  754.   /* Returns the number of lines in the file (and therefore the number */
  755.   /* of entries in *ptr_lines) if successful.  Returns IOERROR if it */
  756.   /* could not open the file to read from. Returns TOO_MANY_CHARS if */
  757.   /* it encounters a line longer than 'maxlinelen' characters. */
  758.  
  759.   /* Space for each line is malloc'ed as it is read in and the text for */
  760.   /* the jth line is stored in (*ptr_lines)[j] */
  761.  
  762.   char *filename;
  763.   char ***ptr_lines;
  764.   char *linebuf;
  765.   int maxlinelen;
  766.  
  767. {
  768.   FILE *fp;
  769.   int nlines;
  770.   if (NULL == (fp = fopen(filename,"r"))) return(IOERROR);
  771.   nlines = getlines(fp,0,ptr_lines,linebuf,maxlinelen);
  772.   fclose(fp);
  773.   return(nlines);
  774. }
  775.  
  776.  
  777. int ngetlines (fp,n,ptr_lines,linebuf,maxlinelen)
  778.  
  779.   /* See documentation for ngetfile below */
  780.  
  781.   FILE *fp;
  782.   int n;
  783.   char ***ptr_lines;
  784.   char *linebuf;
  785.   int maxlinelen;
  786.  
  787. {
  788.   int len;
  789.   int nlines = 0;
  790.   *ptr_lines = (char **) emalloc(n * sizeof(char **));
  791.   while (T) {
  792.     if (0 > (len = getline(fp,linebuf,maxlinelen))) {
  793.        if (len == AT_EOF) {
  794.           return(nlines);
  795.        }
  796.        else {
  797.           return(TOO_MANY_CHARS);
  798.        }
  799.     }
  800.     else {
  801.        if (++nlines > n) {
  802.           return(TOO_MANY_LINES);
  803.        }
  804.        (*ptr_lines)[nlines-1] = anewstr(linebuf);
  805.     }
  806.   }
  807. }
  808.  
  809.  
  810.  
  811. int ngetfile (n,filename,ptr_lines,linebuf,maxlinelen)
  812.  
  813.   /* Same as getfile except that at most n lines will be read. */
  814.   /* If it attempts to read more than n lines, TOO_MANY_LINES will */
  815.   /* be returned. */
  816.  
  817.   int n;
  818.   char *filename;
  819.   char ***ptr_lines;
  820.   char *linebuf;
  821.   int maxlinelen;
  822.  
  823. {
  824.   FILE *fp;
  825.   int nlines;
  826.   if (NULL == (fp = fopen(filename,"r"))) return(IOERROR);
  827.   nlines = ngetlines(fp,n,ptr_lines,linebuf,maxlinelen);
  828.   fclose(fp);
  829.   return(nlines);
  830. }
  831.  
  832.  
  833. extern int read_file_into_buffer (
  834.  
  835.        filename,ptr_lines,maxlines,buffer,buflen,linebuffer,linebuflen
  836.  
  837.     )
  838.        
  839.   char *filename; 
  840.   char ***ptr_lines;
  841.   int maxlines;
  842.   char *buffer;
  843.   int buflen;
  844.   char *linebuffer;
  845.   int linebuflen;
  846.  
  847.   /* *ptr_lines should be an array of character string pointers maxlines */
  848.   /* big.  buffer should be an array of characters buflen long.  The routine */
  849.   /* reads lines using getline and stores them into buffer, terminating each */
  850.   /* with a null.  A pointer to the nth line read is stored in *ptr_lines[n] */
  851.   /* Returns IOERROR if it cannot open the file for reading, TOO_MANY_LINES */
  852.   /* if more than maxlines were read in, TOO_MANY_CHARS if buffer is */
  853.   /* filled before end of file is reached, and LINE_TOO_LONG is any line is */
  854.   /* longer than linebuflen.  Returns number of lines read in if successful. */
  855.   
  856. {  
  857.   FILE *fp;
  858.   int linecount,charcount,len;
  859.   char *bp;
  860.   char **lines;
  861.   
  862.   if (NULL == (fp = fopen(filename,"r"))) return(IOERROR);
  863.   linecount = 0;
  864.   charcount = 0;
  865.   bp = buffer;
  866.   lines = *ptr_lines;
  867.   
  868.   while (T) {
  869.         
  870.     if (0 > (len = getline(fp,linebuffer,linebuflen))) {
  871.        fclose(fp);
  872.        if (len == AT_EOF) {
  873.           return(linecount);
  874.        }
  875.        else {
  876.           return(LINE_TOO_LONG);
  877.        }
  878.     }
  879.     
  880.     if (linecount >= maxlines) {
  881.        fclose(fp);
  882.        return(TOO_MANY_LINES);
  883.     }
  884.     
  885.     charcount += len;
  886.     if (charcount >= buflen) {
  887.        fclose(fp);
  888.        return(TOO_MANY_CHARS);
  889.     }
  890.     
  891.     strcpy(bp,linebuffer);
  892.     lines[linecount++] = bp;
  893.     bp += (len + 1);
  894.   
  895.   }
  896.   
  897. }
  898.   
  899. extern char *efopen (filename,mode) char *filename; char *mode;
  900.  
  901.   /* The routine simply calls fopen with the same arguments, but prints a */
  902.   /* reasonable error message and calls exit if the call to fopen fails. */
  903.  
  904. {
  905.   FILE *fp;
  906.   if (NULL == (fp = fopen(filename,mode))) {
  907.      fprintf(stderr,"Could not open %s, mode: %s\n",filename,mode);
  908.      perror("Reason: ");
  909.      exit(1);
  910.   }
  911.   return((char *) fp);
  912. }
  913.  
  914.  
  915. Bool check_string (s,minlen,maxlen) char *s; long minlen,maxlen;
  916. {
  917.   long len;
  918.   if (s == 0) return(F);
  919.   len = strlen(s);
  920.   return (len >= minlen && len <= maxlen);
  921. }
  922.  
  923.