home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / yapp / part03 / lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-29  |  19.8 KB  |  614 lines

  1. /* LIB.C */
  2. static    char sccsid[] = "@(#)lib.c 1.34 93/06/09 Copyright (c)1993 thalerd";
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/types.h> 
  6. #include <sys/file.h> 
  7. #include <sys/stat.h> 
  8. #include <time.h> 
  9. #include <errno.h>
  10. #include <fcntl.h> /* to get O_CREAT, etc */
  11. #include <ctype.h>
  12. #include <signal.h> /* to get sigvec stuff */
  13. #ifndef linux
  14. extern char *sys_errlist[]; /* standard error messages, usu. in errno.h */
  15. #endif
  16. #include "config.h"
  17. #include "struct.h"
  18. #include "xalloc.h"
  19. #include "globals.h"
  20. #include "lib.h"
  21. #include "macro.h"
  22. #include "system.h"
  23. #include "main.h"
  24. #include "files.h"
  25.  
  26. /******************************************************************************/
  27. /* FIND INDEX OF ELT IN ARR AT OR AFTER START, -1 IF NOT FOUND                */
  28. /******************************************************************************/
  29. short                  /* RETURNS: index of elt or -1  */
  30. searcha(elt,arr,start) /* ARGUMENTS:                   */
  31. char  *elt;            /*    String to search for      */
  32. char **arr;            /*    String array to search    */
  33. short  start;          /*    Index to start looking at */
  34. {
  35.    short i,l;
  36.    l=xsizeof(arr);
  37.    for (i=start; i<l; i++)
  38.       if (!strcmp(arr[i],elt)) return i;
  39.    return -1;
  40. }
  41.  
  42. /******************************************************************************/
  43. /* CHECK FOR A PARTIAL STRING MATCH (required_optional)                       */
  44. /******************************************************************************/
  45. char           /* RETURNS: 1 if match, 0 else        */
  46. match(ent,und) /* ARGUMENTS:                         */
  47. char *ent,     /*    String entered by user          */
  48.      *und;     /*    String with underlines to match */
  49. {
  50.    char *q;
  51.    short n;
  52.  
  53.    q=strchr(und,'_');          /* "_optional" */
  54.    n=(q)? q-und : strlen(und); /* number of required chars */
  55.    if (!n) return !strlen(ent);     /* dont match "" with anything but "" */
  56.    if (strnicmp(ent,und,n))                    return 0; /* match before _ */
  57.    if (q && strnicmp(ent+n,q+1,strlen(ent)-n)) return 0; /* match after  _ */
  58.    if (strlen(ent) > strlen(und)-(q!=0)) return 0; /* no extra chars */
  59.    return 1;
  60. }
  61.             
  62. /******************************************************************************/
  63. /* READ A FILE INTO AN ARRAY OF STRINGS (1 ELT PER LINE)                      */
  64. /******************************************************************************
  65. Function:    char **grab_file(char *dir,char *filename, char flags)
  66. Called by:   main
  67. Arguments:   Filename to grab
  68. Returns:     Array of char *'s with lines of file
  69. Calls:
  70. Description: This function will read in an entire file of text into
  71.              memory, dynamically allocating enough space to hold it.
  72. *******************************************************************************/
  73. #define MAX_LINES 5000
  74. #define HEADER_LINES 6
  75. char **                     /* RETURNS: (nothing)                  */
  76. grab_file(dir,filename,fl)  /* ARGUMENTS:                          */
  77. char *dir;                  /*    Directory containing file        */
  78. char *filename;             /*    Filename to read into memory     */
  79. char fl;                    /*    Flags (see lib.h)                */
  80. {
  81.    char **mem;
  82.    FILE *fp;
  83.    char buff[MAX_LINE_LENGTH],buff2[MAX_LINE_LENGTH];
  84.    short lines, max;
  85.  
  86.    if (filename)
  87.       sprintf(buff,"%s/%s",dir,filename);
  88.    else
  89.       strcpy(buff,dir);
  90.    if ((fp=mopen(buff,(fl & GF_SILENT)? O_R|O_SILENT : O_R))==NULL)
  91.       return 0;
  92.    max=(fl & GF_HEADER)? HEADER_LINES : MAX_LINES;
  93.    mem=xalloc(max,sizeof(char *));
  94.    if (flags & O_DEBUG)
  95.       printf("MEM: %x size=%d  want %d  eltsize=%d\n", mem, sizeof(mem), 
  96.        max, sizeof(char *));
  97.    if (fl & GF_WORD) /* count each word as a line */
  98.       for (lines=0; lines<max && fscanf(fp,"%s",buff2)==1; ) {
  99.          if (buff2[0]=='#' && (fl & GF_IGNCMT))
  100.             fgets(buff2, MAX_LINE_LENGTH, fp);
  101.          else
  102.             mem[lines++]=xstrdup(buff2);
  103.       }
  104.    else {
  105. /* for (lines=0; lines<max && ngets(buff2,fp) && !(status & S_INT); lines++) */
  106.       for (lines=0; lines<max && ngets(buff2,fp); ) {
  107.          if (buff2[0]!='#' || !(fl & GF_IGNCMT))
  108.             mem[lines++]=xstrdup(buff2);
  109.       }
  110.    }
  111.    mclose(fp);
  112.    if (lines<max) mem=xrealloc(mem,lines);
  113.    else if (lines==MAX_LINES) {
  114.       printf("Error: %s too long\n",buff);
  115.       mem=xrealloc(mem,(short)0);
  116.    }
  117.    return mem;
  118. }
  119.  
  120. /******************************************************************************/
  121. /* GRAB SOME MORE OF A FILE UNTIL WE FIND SOME STRING                         */
  122. /******************************************************************************/
  123. char **              /* RETURNS: (nothing)                  */
  124. grab_more(fp,end,fl) /* ARGUMENTS:                          */
  125. FILE *fp;            /*    Input file pointer               */
  126. char *end;           /*    String to stop after             */
  127. char  fl;            /*    Flags (see lib.h)                */
  128. {
  129.    char **mem;
  130.    char buff[MAX_LINE_LENGTH];
  131.    short lines,max;
  132.  
  133.    max=(fl & GF_HEADER)? HEADER_LINES : MAX_LINES;
  134.    mem=xalloc(max,sizeof(char *));
  135.    if (flags & O_DEBUG)
  136.       printf("MEM: %x size=%d  want %d  eltsize=%d\n", mem, sizeof(mem), 
  137.        max, sizeof(char *));
  138.    if (fl & GF_WORD) /* count each word as a line */
  139.       for (lines=0; lines<max && fscanf(fp,"%s",buff)==1; lines++) {
  140.          mem[lines]=xstrdup(buff);
  141.          if (end && !strcmp(buff,end)) break;
  142.       }
  143.    else 
  144.       for (lines=0; lines<max && ngets(buff,fp); lines++) {
  145.          if (end && buff[0]==end[0] && buff[1]==end[0])
  146.             mem[lines]=xstrdup(buff+2);
  147.          else
  148.             mem[lines]=xstrdup(buff);
  149.          if (end && (!strcmp(buff,end) || !strncmp(buff,",R",2))) break;
  150.       }
  151.    if (lines<max) mem=xrealloc(mem,lines);
  152.    return mem;
  153. }
  154.  
  155. /* return static string of fields */
  156. void
  157. implode(buff,arr,sep,start)
  158. char *buff;
  159. char **arr;
  160. char *sep;
  161. short start;
  162. {
  163.    short i,s;
  164.  
  165.    buff[0]='\0';
  166.    s = xsizeof(arr);
  167.    if (s>start) strcpy(buff,arr[start]);
  168.    for (i=start+1; i<s; i++) {
  169.       strcat(buff,sep);
  170.       strcat(buff,arr[i]);
  171.    }
  172. }
  173.  
  174. /******************************************************************************/
  175. /* SPLIT A STRING INTO AN ARRAY OF FIELDS                                     */
  176. /******************************************************************************/
  177. char **                     /* RETURNS: (nothing)                  */
  178. explode(str,sep)            /* ARGUMENTS:                          */
  179. char *str;                  /*    Filename to read into memory     */
  180. char *sep;                  /*    Field separator string           */
  181. {
  182.    char **mem,*ln,*nstr;
  183.    short lines;
  184.  
  185.    mem=xalloc(MAX_LINES,sizeof(char *));
  186.    nstr=xstrdup(str);
  187.  
  188.    if (sep) {
  189.       ln=strtok(nstr,sep);
  190.       for (lines=0; ln && lines<MAX_LINES; lines++) {
  191.          while (*ln == ' ') ln++; /* skip leading spaces */
  192.          mem[lines]=xstrdup(ln);
  193.          while (strlen(mem[lines]) && mem[lines][ strlen(mem[lines])-1 ] == ' ')
  194.             mem[lines][ strlen(mem[lines])-1 ] = 0; /* trash trailing spaces */
  195.          ln = strtok(NIL,sep);
  196.       }
  197.    } else {
  198.       mem[0]=xstrdup(str);
  199.       lines=1;
  200.    }
  201.  
  202.    mem=xrealloc(mem,lines);
  203.    xfree(nstr);
  204.    return mem;
  205. }
  206.  
  207. /******************************************************************************/
  208. /* APPEND A LINE TO A FILE                                                    */
  209. /******************************************************************************
  210. Function:    char write_file(char *filename, char *string)
  211. Called by:  
  212. Arguments:   filename to put stuff in, string to put there
  213. Returns:     1 on success, 0 if error
  214. Calls:
  215. Description: Appends a block of text to a file with a single operation.
  216.              Locks & unlocks file to be safe.
  217. *******************************************************************************/
  218. char                        /* RETURNS: 1 on success, 0 if error   */
  219. write_file(filename,str)    /* ARGUMENTS:                          */
  220. char *filename;             /*    Filename to append to            */
  221. char *str;                  /*    Block of text to write           */
  222. {
  223.    FILE *fp;
  224.    long mod=O_A;
  225.  
  226.    if (st_glob.c_status & CT_BASIC) mod |= O_PRIVATE;
  227.    if ((fp=mopen(filename,mod))==NULL) return 0;
  228.    fwrite(str,strlen(str),1,fp);
  229.    mclose(fp);
  230.    return 1;
  231. }
  232.             
  233. /******************************************************************************/
  234. /* DUMP A FILE TO THE OUTPUT                                                  */
  235. /******************************************************************************
  236. Function:    char cat(char *dir, char *filename)
  237. Called by:   
  238. Arguments:   filename to display
  239. Returns:     1 on success, 0 on failure
  240. Calls:
  241. Description: Copies a file to the screen (not grab_file)
  242. *******************************************************************************/
  243. char                        /* RETURNS: (nothing)                  */
  244. cat(dir,filename)           /* ARGUMENTS:                          */
  245. char *dir;                  /*    Directory containing file        */
  246. char *filename;             /*    Filename to display              */
  247. {
  248.    FILE *fp;
  249.    int c;
  250.    char buff[MAX_LINE_LENGTH];
  251.  
  252.    if (filename)
  253.       sprintf(buff,"%s/%s",dir,filename);
  254.    else
  255.        strcpy(buff,dir);
  256.    if (flags & O_DEBUG) printf("cat: %s\n",buff);
  257.    if ((fp=mopen(buff,O_R))==NULL) return 0;
  258.    while ((c=fgetc(fp))!=EOF && !(status & S_INT)) wputchar(c);
  259.    mclose(fp);
  260.    return 1;
  261. }
  262. extern char pipebuf[MAX_LINE_LENGTH];
  263. /******************************************************************************/
  264. /* DUMP A FILE TO THE OUTPUT THROUGH A PAGER                                  */
  265. /******************************************************************************
  266. char                        /* RETURNS: (nothing)                  */
  267. more(dir,filename)          /* ARGUMENTS:                          */
  268. char *dir;                  /*    Directory containing file        */
  269. char *filename;             /*    Filename to display              */
  270. {
  271.    FILE *fp,*pp;
  272.    char buff[MAX_LINE_LENGTH];
  273.    int c;
  274.  
  275.    /* Need to check if pager exists */
  276.    if (!pipebuf[0]) strcpy(pipebuf,expand("pager",DM_VAR));
  277.    if (!(flags & O_BUFFER) || !pipebuf[0])
  278.       return cat(dir,filename);
  279.  
  280.    if (filename)
  281.       sprintf(buff,"%s/%s",dir,filename);
  282.    else
  283.        strcpy(buff,dir);
  284.    if (flags & O_DEBUG) printf("CAT: %s\n",buff);
  285.    if ((fp=mopen(buff,O_R))==NULL) return 0;
  286.    open_pipe();
  287.    while ((c=fgetc(fp))!=EOF) 
  288.       if (fputc(c,st_glob.outp)==EOF) break;
  289.    spclose(st_glob.outp);
  290.    mclose(fp);
  291.    status &= ~S_INT;
  292.    return 1;
  293. }
  294.  
  295. /******************************************************************************/
  296. /* GET INPUT WITHOUT ECHOING IT                                               */
  297. /******************************************************************************/
  298. char *         /* RETURNS: text entered */
  299. get_password() /* ARGUMENTS: (none)     */
  300. {
  301.    static char buff[MAX_LINE_LENGTH];
  302.    short i=0,c;
  303.  
  304.    unix_cmd("/bin/stty -echo");
  305.    while ((c=getchar())!=10 && c!=13 && c!= -1 && i<MAX_LINE_LENGTH) 
  306.       buff[i++]=c;
  307.    buff[i]=0;
  308.    putchar('\n');
  309.    unix_cmd("/bin/stty echo");
  310.    return buff;
  311. }
  312.  
  313. /******************************************************************************/
  314. /* GET INPUT WITHOUT OVERFLOWING BUFFER                                       */
  315. /******************************************************************************/
  316. char *        /* RETURNS: text entered */
  317. ngets(str,fp) /* ARGUMENTS:            */
  318. char *str;    /*    Input buffer       */
  319. FILE *fp;     /*    Input stream       */
  320. {
  321.    char *ok;
  322.    int i,j,strip=0;
  323.    char buff[MAX_LINE_LENGTH];
  324.    struct sigvec vec;
  325.  
  326.    if (fp==st_glob.inp) {
  327.       if (status & S_REDIRECT)
  328.          spclose(st_glob.outp); 
  329.  
  330.       /* Make INT abort fgets() */
  331.       sigvec(SIGINT,  NULL, &vec);
  332.       vec.sv_flags |= SV_INTERRUPT;
  333.       sigvec(SIGINT,  &vec, NULL);
  334.    }
  335.  
  336.    ok=fgets(str,MAX_LINE_LENGTH,fp);
  337.    
  338.    if (fp==st_glob.inp) {
  339.  
  340.       /* Stop INT from aborting fgets() */
  341.       sigvec(SIGINT,  NULL, &vec);
  342.       vec.sv_flags &= ~SV_INTERRUPT;
  343.       sigvec(SIGINT,  &vec, NULL);
  344.  
  345.       if (!ok) { 
  346.      if (fp==stdin) {
  347.             clearerr(fp); 
  348.             printf("\n"); 
  349.      } else {
  350.         mclose(fp);
  351.         st_glob.inp = stdin;
  352.         return ngets(str, st_glob.inp);
  353.      }
  354.       }
  355.    }
  356.    if (ok)
  357.       str[ strlen(str)-1 ] =0; /* trash newline */
  358.    else if ((status & S_INT) && (fp==st_glob.inp)) {
  359.       /* for systems where interrupts abort fgets */
  360.       str[0]='\0';
  361.       return str;
  362.    }
  363.  
  364.    if ((fp==st_glob.inp) && (flags & O_STRIP)) {
  365.       for (i=j=0; i<strlen(str); i++) {
  366.          if (isprint(str[i]) || isspace(str[i])) buff[j++]=str[i];
  367.          else {
  368.             printf("%s ^%c",(strip++)? "" : "Stripping bad input:", str[i]+64);
  369.          }
  370.       }
  371.       if (strip) printf("\n");
  372.       buff[j]='\0';
  373.       strcpy(str,buff);
  374.    }
  375.    return ok;
  376. }
  377.  
  378. /******************************************************************************/
  379. /* GET INPUT UNTIL USER SAYS YES OR NO                                        */
  380. /******************************************************************************/
  381. char        /* RETURNS: 1 for yes, 0 no */
  382. get_yes(pr) /* ARGUMENTS:               */
  383. char *pr;   /*    Prompt                */
  384. {
  385.    char buff[MAX_LINE_LENGTH];
  386.    
  387.    for(;;) {
  388.       if (status & S_MOTIF)
  389.          wgets(buff,pr);
  390.       else {
  391.          wputs(pr);
  392.          if (!ngets(buff,st_glob.inp)) return 0;
  393.       }
  394.       if (match(buff,"n_on") || match(buff,"nop_e")) return 0;
  395.       if (match(buff,"y_es") || match(buff,"ok")) return 1;
  396.       printf("Try yes or no.\n");
  397.    } 
  398. }
  399.  
  400. #ifdef NOSTRNICMP
  401. /******************************************************************************/
  402. /* STANDARD strnicmp() CODE FOR THOSE OS'S WHICH DON'T HAVE IT                */
  403. /******************************************************************************/
  404. int 
  405. strnicmp(a,b,n)
  406. char *a,*b;
  407. int  n;
  408. {
  409.    char *s;
  410.    for (s=a; (tolower(*s) == tolower(*b)) && (s-a < n); s++, b++)
  411.       if (*s == '\0')
  412.          return 0;
  413.    if (s-a >= n) return 0;
  414.    return tolower(*s) - tolower(*b);
  415. }
  416. #endif
  417.  
  418. /******************************************************************************/
  419. /* READ IN ASSOCIATIVE LIST                                                   */
  420. /* ! and # begin comments and are not part of the list                        */
  421. /* =filename chains to another file                                           */
  422. /******************************************************************************/
  423. char                              /* RETURNS: 1 on success, 0 error */
  424. grab_list(dir,filename,list,size) /* ARGUMENTS:                     */
  425. char   *dir;                      /*    Directory containing file   */
  426. char   *filename;                 /*    Filename to read from       */
  427. assoc_t list[];                   /*    Array to fill in            */
  428. short  *size;                     /*    Size of array               */
  429. {
  430.    FILE *fp;
  431.    char buff[MAX_LINE_LENGTH],name[MAX_LINE_LENGTH],*loc;
  432.  
  433.    if (filename && dir) sprintf(name,"%s/%s",dir,filename);
  434.    else if (dir)        strcpy(name,dir);
  435.    else if (filename)   strcpy(name,filename);
  436.    else return 0;
  437.  
  438.    if ((fp=mopen(name,O_R|O_SILENT))==NULL) {
  439.       error("grabbing list ",name);
  440.       return 0;
  441.    }
  442.  
  443.    do {
  444.       loc=ngets(buff,fp);
  445.    } while(loc && (buff[0]=='#' || buff[0]=='!'));
  446.    if (!loc) {
  447.       (void)fprintf(stderr,"Error: %s is empty.\n",name);
  448.       return 0;
  449.    }
  450.    list[0].name     = xstrdup("");
  451.    list[0].location = xstrdup(buff);
  452.    if (flags & O_DEBUG) printf("Default: '%s'\n",buff);
  453.    if (strchr(buff,':')) 
  454.       (void)fprintf(stderr,"Warning: %s may be missing default.\n",name);
  455.    
  456.    for (*size =1; ngets(buff,fp) && (*size)<MAX_LIST_LENGTH; ) {
  457.       if (flags & O_DEBUG) printf("Buff: '%s'\n",buff);
  458.       if (buff[0]=='#' || buff[0]=='\0') continue;
  459.       if (loc = strchr(buff,':')) {
  460.          strncpy(name,buff,loc-buff);
  461.          name[loc-buff]=0;
  462.          loc++;
  463.  
  464.          list[*size].name     = xstrdup(name);
  465.          list[*size].location = xstrdup(loc);
  466.          if (flags & O_DEBUG)
  467.             printf("Name: '%s' Dir: '%s'\n",list[*size].name, 
  468.              list[*size].location);
  469.          (*size)++;
  470.  
  471.       /* Chain to another file */
  472.       } else if (buff[0]=='=' && strlen(buff)>1) {
  473.          mclose(fp);
  474.  
  475.          if (buff[1]=='%') sprintf(name,"%s/%s",bbsdir,buff+2);
  476.          else if (dir)     sprintf(name,"%s/%s",dir,buff+1);
  477.          else              strcpy(name,buff+1);
  478.  
  479.          if ((fp=mopen(name,O_R|O_SILENT))==NULL) {
  480.             error("grabbing list ",name);
  481.             return 1;
  482.          }
  483.          ngets(buff,fp); /* read magic line */
  484.          if (flags & O_DEBUG) printf("grab_list: magic %s\n",buff);
  485.  
  486.       } else {
  487.          (void)fprintf(stderr,"UNK Bad line read: %s\n",buff);
  488.       }
  489.    }
  490.    mclose(fp);
  491.    if (*size == MAX_LIST_LENGTH) 
  492.       printf("Warning: list length exceeded.\n");
  493.    return 1;
  494. }
  495.  
  496. /******************************************************************************/
  497. /* CONVERT TIMESTAMP INTO A STRING IN VARIOUS FORMATS                         */
  498. /******************************************************************************/
  499. char *          /* RETURNS: Date string */
  500. get_date(t,sty) /* ARGUMENTS:           */
  501. time_t t;       /*    Timestamp         */
  502. char sty;       /*    Output style      */
  503. {
  504.    static char buff[MAX_LINE_LENGTH];
  505.    struct tm *tms;
  506.    static char *fmt[]={
  507. #ifdef NOEDATE
  508.    /*  0 */ "%a %b %d %H:%M:%S %Y",         /* dates must be in 05 format */
  509.    /*  1 */ "%a, %b %d, %Y (%H:%M)",  
  510. #else
  511.    /*  0 */ "%a %b %e %H:%M:%S %Y",         /* dates need not have leading 0 */
  512.    /*  1 */ "%a, %b %e, %Y (%H:%M)", 
  513. #endif
  514.    /*  2 */ "%a", 
  515.    /*  3 */ "%b",
  516.    /*  4 */ "%e",
  517.    /*  5 */ "%y",
  518.    /*  6 */ "%Y",
  519.    /*  7 */ "%H",
  520.    /*  8 */ "%M",
  521.    /*  9 */ "%S",
  522.    /* 10 */ "%I",
  523.    /* 11 */ "%p",
  524.    /* 12 */ "%p",
  525. #ifdef NOEDATE
  526.    /* 13 */ "(%H:%M:%S) %B %d, %Y"
  527. #else
  528.    /* 13 */ "(%H:%M:%S) %B %e, %Y"
  529. #endif
  530.    };
  531.  
  532.    tms = localtime(&t);
  533.    if (sty<0 || sty>13) sty=0;
  534.    strftime(buff,MAX_LINE_LENGTH,fmt[sty],tms);
  535.    return buff;
  536. }
  537.  
  538. /******************************************************************************/
  539. /* GENERATE STRING WITHOUT ANY "'_s IN IT                                     */
  540. /******************************************************************************/
  541. char *       /* RETURNS: New string */
  542. noquote(s,x) /* ARGUMENTS:          */
  543. char *s;     /*    Original string  */
  544. int x;       /*    Remove _'s too?  */
  545. {
  546.    static char buff[MAX_LINE_LENGTH];
  547.    char *p,*q,qu=0;
  548.  
  549.    q=s;
  550.    if (*q=='"' || *q=='\'') { qu= *q; q++; }
  551.    for (p=buff; *q; q++)
  552.       if (x==0 || *q != '_')
  553.          *p++ = *q;
  554.    *p=0;
  555.    p--;
  556.    if (p>=buff && *p==qu) *p=0;
  557.    return buff;
  558. }
  559.  
  560. /******************************************************************************/
  561. /* GENERATE STRING WITHOUT ANY _'s IN IT                                      */
  562. /******************************************************************************/
  563. char *      /* RETURNS: New string */
  564. compress(s) /* ARGUMENTS:          */
  565. char *s;    /*    Original string  */
  566. {
  567.    static char buff[MAX_LINE_LENGTH];
  568.    char *p,*q;
  569.  
  570.    for (p=buff,q=s; *q; q++)
  571.       if (*q != '_') 
  572.          *p++ = *q;
  573.    *p=0;
  574.    return buff;
  575. }
  576.  
  577. void
  578. error(str1,str2)
  579. char *str1,*str2;
  580. {
  581.    FILE *fp;
  582.    char errorlog[MAX_LINE_LENGTH];
  583.    char timestamp[MAX_LINE_LENGTH];
  584.    time_t t;
  585.  
  586.    if (errno)
  587.       fprintf(stderr,"Got error %d (%s) in %s%s\n",errno,sys_errlist[errno],
  588.        str1,str2);
  589.    sprintf(errorlog,"%s/errorlog",bbsdir);
  590.    if (fp=fopen(errorlog,"a")) {
  591.       time(&t);
  592.       strcpy(timestamp,ctime(&t)+4);
  593.       timestamp[20]='\0';
  594.       if (errno)
  595.          fprintf(fp,"%-8s %s Got error %d (%s) in %s%s\n",
  596.           login, timestamp, errno,sys_errlist[errno],str1,str2);
  597.       else
  598.          fprintf(fp,"%-8s %s WARNING: %s%s\n", login, timestamp, str1,str2);
  599.       fclose(fp);
  600.    }
  601. }
  602.  
  603. char *
  604. lower_case(arg)
  605. char *arg;
  606. {
  607.    char lwr[MAX_LINE_LENGTH];
  608.    int  i;
  609.  
  610.    for (i=0; i<=strlen(arg); i++)
  611.      lwr[i] = tolower(arg[i]);
  612.    return lwr;
  613. }
  614.