home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / gopher1.12 / object / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-12  |  10.3 KB  |  511 lines

  1. /********************************************************************
  2.  * $Author: lindner $
  3.  * $Revision: 2.4 $
  4.  * $Date: 1993/01/12 21:12:23 $
  5.  * $Source: /home/mudhoney/GopherSrc/gopher1.11a/object/RCS/util.c,v $
  6.  * $State: Rel $
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: util.c
  14.  * Various useful utilities for gopher clients and servers
  15.  *********************************************************************
  16.  * Revision History:
  17.  * $Log: util.c,v $
  18.  * Revision 2.4  1993/01/12  21:12:23  lindner
  19.  * Reverted to old readfield behavior()  \n is now ignored again.
  20.  *
  21.  * Revision 2.3  1993/01/08  23:29:21  lindner
  22.  * More mods from jqj.
  23.  *
  24.  * Revision 2.2  1992/12/31  04:58:41  lindner
  25.  * merged 1.1.1.1 and 2.1
  26.  *
  27.  * Revision 2.1  1992/12/21  19:41:14  lindner
  28.  * Added check for null in writestring
  29.  * Added function skip_whitespace
  30.  *
  31.  * Revision 1.1.1.1  1992/12/31  04:52:01  lindner
  32.  * Changes for VMS
  33.  *
  34.  * Revision 1.1  1992/12/10  23:27:52  lindner
  35.  * gopher 1.1 release
  36.  *
  37.  *
  38.  *********************************************************************/
  39.  
  40. #include "Malloc.h"
  41. #include "String.h"
  42. #include <ctype.h>
  43. #include "boolean.h"
  44. #include "util.h"
  45.  
  46. #if defined(VMS) && defined(UCX)
  47. #include <errno.h>
  48. #endif
  49.  
  50. #if defined(VMS) && (defined(WOLLONGONG) || defined(MULTINET))
  51. /* Multinet and Wollongong (non UCX-emulation) use channel numbers */
  52. /* for sockets, which are small multiples of 16.  The first 5 */
  53. /* channels can be assumed to be already used, so we assume that */
  54. /* sockets start at 64, and that only 64 VAXC fds are simultaneously */
  55. /* open in the program.  Actually, the first socket is likely to be */
  56. /* more like 176! */
  57. #define IS_SOCKET(s) ((s)>=64)
  58.  
  59. /* Close a socket.  
  60.  * Note that in old Wollongong and Multinet implementations close()
  61.  * works only on fds, not sockets.
  62.  * For UCX and Unix, closenet() is #defined to be close()
  63.  */
  64. int closenet(s)
  65. int s;
  66. {
  67.     if (IS_SOCKET(s)) {
  68. #ifdef MULTINET
  69.     return (socket_close(s));
  70. #else /* WOLLONGONG */
  71.     return (netclose(s));
  72. #endif
  73.     }
  74.     else
  75.     close(s); /* shouldn't be calling this routine */
  76. }
  77. #endif /* WOLLANGONG or MULTINET */
  78.  
  79.  
  80. /* Read "n" bytes from a descriptor.
  81.  * Use in place of read() when fd is a stream socket
  82.  *
  83.  * Returns the number of total bytes read.
  84.  */
  85.  
  86. int readn(fd, ptr, nbytes)
  87.   int fd;
  88.   char *ptr;
  89.   int nbytes;
  90. {
  91.      int nleft, nread;
  92.      
  93.      nleft = nbytes;
  94.      while (nleft > 0) {
  95. #if defined(VMS) && defined(WOLLONGONG)
  96.       nread = IS_SOCKET(fd) ? netread(fd, ptr, nleft) : read(fd, ptr, nleft);
  97. #else
  98. #if defined(VMS) && defined(MULTINET)
  99.       nread = IS_SOCKET(fd) ? socket_read(fd, ptr, nleft) : read(fd, ptr, nleft);
  100. #else
  101.       nread = read(fd, ptr, nleft);
  102. #endif
  103. #endif
  104. #if defined(VMS) && defined(UCX)
  105.           if (nread < 0 && errno == EPIPE)
  106.            break;
  107. #endif
  108.       if (nread < 0)
  109.            return(nread);    /* error, return <0 */
  110.       else if (nread == 0)    /* EOF */
  111.            break;
  112.       
  113.       nleft     -= nread;
  114.       ptr     += nread;
  115.      }
  116.      return(nbytes - nleft);    /* return >= 0) */
  117. }
  118.  
  119.  
  120.  
  121. /*
  122.  * Write "n" bytes to a descriptor.
  123.  * Use in place of write() when fd is a stream socket
  124.  *
  125.  * We return the number of bytes written
  126.  */
  127.  
  128. int 
  129. writen(fd, ptr, nbytes)
  130.   int    fd;
  131.   char    *ptr;
  132.   int    nbytes;
  133. {
  134.      int nleft, nwritten;
  135.      
  136.      nleft = nbytes;
  137.      while(nleft > 0) {
  138. #if defined(VMS) && defined(WOLLONGONG)
  139.       nwritten = IS_SOCKET(fd) ? netwrite(fd, ptr, nleft) : write(fd, ptr, nleft);
  140. #else
  141. #if defined(VMS) && defined(MULTINET)
  142.       nwritten = IS_SOCKET(fd) ? socket_write(fd, ptr, nleft) : write(fd, ptr, nleft);
  143. #else
  144.       nwritten = write(fd, ptr, nleft);
  145. #endif
  146. #endif
  147.       if (nwritten <= 0)
  148.            return(nwritten);    /* error */
  149.       
  150.       nleft    -= nwritten;
  151.       ptr    += nwritten;
  152.      }
  153.      return(nbytes - nleft);
  154. }
  155.  
  156.  
  157. /*
  158.  * Writestring uses the writen and strlen calls to write a
  159.  * string to the file descriptor fd.  If the write fails
  160.  * a -1 is returned. Otherwise zero is returned.
  161.  */
  162.  
  163. int writestring(fd, stringptr)
  164.   int    fd;
  165.   char    *stringptr;
  166. {
  167.      int length;
  168.  
  169.      if (stringptr == NULL)
  170.       return(0);
  171.  
  172.      length = strlen(stringptr);
  173.      if (writen(fd, stringptr, length) != length) {
  174.       return(-1);
  175.      }
  176.      else
  177.       return(0);
  178. }
  179.  
  180. /*
  181.  * Read from the socket into a buffer.  Mucho more efficent in terms of
  182.  * system calls..
  183.  */
  184.  
  185. #define RECVSIZE 4096
  186.  
  187. static int readrecvbuf(sockfd, buf, len)
  188.   int sockfd;
  189.   char *buf;
  190.   int len;
  191. {
  192.      static char recvbuf[RECVSIZE];
  193.      static int  recvbufptr  = 0;
  194.      static int  recvbufsize = 0;
  195.      static int Oldsockfd = 0;
  196.      int bytesread = 0;
  197.  
  198.      if (recvbufptr == 0 || Oldsockfd != sockfd) {
  199. #if defined(VMS) && defined(WOLLONGONG)
  200.       recvbufsize = IS_SOCKET(sockfd) ?
  201.         netread(sockfd, recvbuf, RECVSIZE) : read(sockfd, recvbuf, RECVSIZE);
  202. #else
  203. #if defined(VMS) && defined(MULTINET)
  204.       recvbufsize = IS_SOCKET(sockfd) ?
  205.         socket_read(sockfd, recvbuf, RECVSIZE) : read(sockfd, recvbuf, RECVSIZE);
  206. #else
  207.       recvbufsize = read(sockfd, recvbuf, RECVSIZE);
  208. #endif
  209. #endif
  210.       Oldsockfd = sockfd;
  211.       recvbufptr = 0;
  212.       if (recvbufsize == 0)
  213.            return(0);
  214. #if defined(VMS) && defined(UCX)
  215.       if (recvbufsize < 0 && errno == EPIPE)
  216.            return(0);
  217. #endif
  218.  
  219.      }
  220.      
  221.      while (len--) {
  222.       *buf++ = recvbuf[recvbufptr++];
  223.       bytesread++;
  224.  
  225.       if (recvbufptr == recvbufsize && len != 0) {
  226.            recvbufsize = readn(sockfd, recvbuf, RECVSIZE);
  227.            recvbufptr = 0;
  228.            if (recvbufsize == 0)
  229.             return(bytesread);
  230.            if (recvbufsize < 0)
  231.             return(recvbufsize);
  232.  
  233.       } else if (recvbufptr >= recvbufsize)
  234.            recvbufptr = 0;
  235.      }
  236.      return(bytesread);
  237. }     
  238.  
  239.  
  240. /*
  241.  * Read a line from a descriptor.  Read the line one byte at a time,
  242.  * looking for the newline.  We store the newline in the buffer,
  243.  * then follow it with a null (the same as fgets(3)).
  244.  * We return the number of characters up to, but not including,
  245.  * the null (the same as strlen(3))
  246.  */
  247.  
  248. int readline(fd, ptr, maxlen)
  249.   int    fd;
  250.   char    *ptr;
  251.   int     maxlen;
  252. {
  253.      int n;
  254.      int rc;
  255.      char c;
  256.  
  257.      
  258.      for (n=1; n < maxlen; n++) {
  259.       if ( (rc = readrecvbuf(fd, &c, 1)) == 1) {
  260.            *ptr++ = c;
  261.            if (c == '\n')
  262.             break;
  263.       }
  264.       else if (rc == 0) {
  265.            if (n == 1)
  266.             return(0);    /* EOF, no data read */
  267.            else
  268.             break;        /* EOF, some data was read */
  269.       }
  270.       else
  271.            return(-1);        /* error */
  272.      }
  273.      
  274.      *ptr = 0;                 /* Tack a NULL on the end */
  275.      return(n);
  276. }
  277.  
  278. /*
  279.  * Readfield reads data up to a tab, (like readline above)
  280.  */
  281.  
  282. int 
  283. readfield(fd, ptr, maxlen)
  284.   int    fd;
  285.   char    *ptr;
  286.   int     maxlen;
  287. {
  288.      int n;
  289.      int rc;
  290.      char c;
  291.      
  292.      for (n=1; n < maxlen; n++) {
  293.       if ( (rc = readrecvbuf(fd, &c, 1)) == 1) {
  294.            *ptr++ = c;
  295.            if (c == '\t') {
  296.             *(ptr - 1) = '\0';
  297.             break;
  298.            }
  299.       }
  300.       else if (rc == 0) {
  301.            if (n == 1)
  302.             return(0);    /* EOF, no data read */
  303.            else
  304.             break;        /* EOF, some data was read */
  305.       }
  306.       else
  307.            return(-1);        /* error */
  308.      }
  309.      
  310.      *ptr = 0;                 /* Tack a NULL on the end */
  311.      return(n);
  312. }
  313.  
  314.  
  315. int
  316. sreadword(input, output, maxlen)
  317.   char *input;
  318.   char *output;
  319.   int maxlen;
  320. {
  321.      int n;
  322.      char c;
  323.      
  324.      for (n=0; n < maxlen; n++) {
  325.       c = *input++;
  326.       *output++ = c;
  327.       if (isspace(c)) {
  328.            *(output - 1) = '\0';
  329.            break;
  330.       }
  331.       
  332.       if (c == '\0') {
  333.            break;
  334.       }
  335.      }
  336.      
  337.      *output = '\0';                 /* Tack a NULL on the end */
  338.      return(n);
  339. }
  340.  
  341.  
  342. /*
  343.  * ZapCRLF removes all carriage returns and linefeeds from a C-string.
  344.  */
  345.  
  346. void
  347. ZapCRLF(inputline)
  348.   char *inputline;
  349. {
  350.      char *cp;
  351.  
  352.      cp = strchr(inputline, '\r');    /* Zap CR-LF */
  353.      if (cp != NULL)
  354.       *cp = '\0';
  355.      else {
  356.       cp = strchr(inputline, '\n');
  357.       if (cp != NULL)
  358.            *cp = '\0';
  359.      }
  360. }
  361.  
  362. /*
  363.  *  Utilities for dealing with HTML junk
  364.  */
  365.  
  366. static boolean acceptable[256];
  367. static boolean acceptable_inited = FALSE;
  368.  
  369. void init_acceptable()
  370. {
  371.     unsigned int i;
  372.     char * good = 
  373.       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
  374.     for(i=0; i<256; i++) acceptable[i] = FALSE;
  375.     for(;*good; good++) acceptable[(unsigned int)*good] = TRUE;
  376.     acceptable_inited = TRUE;
  377. }
  378.  
  379. static char hex[17] = "0123456789abcdef";
  380.  
  381. char from_hex(c)
  382.   char c;
  383. {
  384.      return (c>='0')&&(c<='9') ? c-'0'
  385.       : (c>='A')&&(c<='F') ? c-'A'+10
  386.            : (c>='a')&&(c<='f') ? c-'a'+10
  387.             :                      0;
  388. }
  389.  
  390.  
  391. /*
  392.  * Finds out if a character is printable & non white space.
  393.  * if it is, then return a hex encoding of the char,
  394.  * otherwise, just return a reference to the character
  395.  */
  396.  
  397. char *to_hex(c)
  398.   char c;
  399. {
  400.      static char out[4];
  401.  
  402.      if (acceptable_inited == FALSE)
  403.       init_acceptable();
  404.  
  405.      out[0] = '\0';
  406.  
  407.      if (acceptable[(int)c] == TRUE) {
  408.       out[0] = c;
  409.       out[1] = '\0';
  410.      }
  411.      else {
  412.       out[0]='%';
  413.       out[1]=hex[c >> 4];
  414.       out[2]=hex[c & 15];
  415.       out[3]='\0';
  416.      }
  417.  
  418.      return(out);
  419. }
  420.      
  421. /*
  422.  * Replace hex escape sequences with the proper codes...
  423.  *
  424.  * input and output can be the same if you want
  425.  */
  426.  
  427. void
  428. Fromhexstr(input, output)
  429.   char *input, *output;
  430. {
  431.      char c;
  432.      unsigned int b;
  433.  
  434.      while (*input) {
  435.       if (*input == '%') {
  436.            input++;
  437.            c = *input++;
  438.            b = from_hex(c);
  439.            c = *input++;
  440.            if (!c) break;
  441.            *output++ = (b<<4) + from_hex(c);
  442.       }
  443.       else 
  444.            *output++ = *input++;
  445.      }
  446.      *output = '\0';
  447. }
  448.       
  449. void
  450. Tohexstr(input, output)
  451.   char *input, *output;
  452. {
  453.  
  454.      if (acceptable_inited == FALSE)
  455.       init_acceptable();
  456.      
  457.      while (*input) {
  458.  
  459.       if (acceptable[(int)*input] == TRUE) {
  460.            *output++ = *input++;
  461.       }
  462.       else {
  463.            *output++ = '%';
  464.            *output++ = hex[*input >> 4];
  465.            *output++ = hex[*input & 15];
  466.            input++;
  467.       }
  468.      }
  469.  
  470.      *output = '\0';
  471. }
  472.  
  473. /*
  474.  * String insensitive strstr
  475.  */
  476.  
  477. char *
  478. strcasestr(inputline, match)
  479.   char *inputline;
  480.   char *match;
  481. {
  482.      int matchlen=0;
  483.      int i, inlen;
  484.  
  485.      matchlen = strlen(match);
  486.      inlen = strlen(inputline);
  487.  
  488.      for(i=0; i<inlen; i++) {
  489.       if (strncasecmp(inputline+i, match, matchlen)==0)
  490.            return(inputline+i);
  491.      }
  492.  
  493.      return(NULL);
  494. }
  495.  
  496.  
  497. /*
  498.  * Iterate over a string, return a pointer to the next character
  499.  * that isn't whitespace.
  500.  */
  501.  
  502. char *
  503. skip_whitespace(str)
  504.   char *str;
  505. {
  506.      while (isspace(*str) && *str!='\0')
  507.       str++;
  508.  
  509.      return(str);
  510. }
  511.