home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / libcnews / string.c < prev    next >
C/C++ Source or Header  |  1993-09-11  |  6KB  |  291 lines

  1. /*
  2.  * string operations
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <sys/types.h>
  8. #include <string.h>
  9. #include "libc.h"
  10. #include "news.h"
  11.  
  12. int
  13. spacein(s)
  14. register char *s;
  15. {
  16.     return strchr(s, ' ') != NULL || strchr(s, '\t') != NULL;
  17. }
  18.  
  19. stranslit(s, from, to)        /* simple tr: change `from' to `to' in `s' */
  20. register char *s;
  21. register char from, to;
  22. {
  23.     for (; *s != '\0'; s++)
  24.         if (*s == from)
  25.             *s = to;
  26. }
  27.  
  28. /*
  29.  * Return strsave() of the first word in "tokens".
  30.  * Words are delimited by spaces.
  31.  */
  32. char *
  33. first(tokens)
  34. char *tokens;
  35. {
  36.     return strsvto(tokens, ' ');
  37. }
  38.  
  39. /*
  40.  * Turn a newsgroup name into a file name, in place.
  41.  */
  42. void
  43. mkfilenm(ng)
  44. register char *ng;
  45. {
  46.     stranslit(ng, NGDELIM, FNDELIM);
  47. }
  48.  
  49. char *
  50. trim(s)                    /* trim trailing newline */
  51. char *s;
  52. {
  53.     register char *nl;
  54.  
  55. /*    STRRCHR(s, '\n', nl);    */
  56.     nl = strrchr(s, '\n');
  57.     if (nl != NULL)
  58.         *nl = '\0';
  59.     return s;
  60. }
  61.  
  62. char *
  63. skipsp(s)                /* skip any whitespace at *s */
  64. register char *s;
  65. {
  66.     while (iswhite(*s))
  67.         s++;
  68.     return s;
  69. }
  70.  
  71. char *
  72. strsvto(s, c)                /* save s up to (but excluding) c */
  73. char *s;
  74. int c;
  75. {
  76.     register char *endp, *copy;
  77.  
  78.     STRCHR(s, c, endp);        /* find interesting part's end of s */
  79.     if (endp != NULL)
  80.         *endp = '\0';        /* restored below */
  81.     copy = strsave(s);        /* copy interesting substring of s */
  82.         if (endp != NULL)
  83.             *endp = c;
  84.     return copy;
  85. }
  86.  
  87. int
  88. charcount(s, c)            /* how many c's in s? */
  89. register char *s;
  90. register int c;
  91. {
  92.     register int count = 0;
  93.  
  94.     /*
  95.      * this is arguably cleaner, but slower:
  96.      * for (; (s = strchr(s, c)) != NULL; s = (s == NULL? NULL: s+1))
  97.      *    ++count;
  98.      */
  99.     while (*s != '\0')
  100.         if (*s++ == c)
  101.             ++count;
  102.     return count;
  103. }
  104.  
  105. char *
  106. nullify(s)                /* return s or "" if NULL */
  107. register char *s;
  108. {
  109.     return (s == NULL? "": s);
  110. }
  111.  
  112.  
  113. /* hostname and path routines follow */
  114.  
  115.  
  116. #define CHARSETWIDTH 8            /* bits per character */
  117. #define CHARSETSIZE  (1<<CHARSETWIDTH)    /* 2^CHARSETWIDTH */
  118.  
  119. #define initishostchar() (setishostchar? 0: doinitishostchar())
  120. /* These macros are both (currently) safe. */
  121. /* If c is NUL, hostchar will be false, so don't test (optimisation: ==). */
  122. #define nothostchar(c) (!hostchar(c) /* || (c) == '\0' */ )
  123. /* True if c can be part of a hostname.  False may mean c is NUL. */
  124. #define hostchar(c) ishostchar[(c) & (CHARSETSIZE-1)]
  125.  
  126. static char ishostchar[CHARSETSIZE];    /* char. sets > Latin-1 are out of luck */
  127. static int setishostchar = NO;
  128.  
  129. /*
  130.  * RFC 850 allows letters, digits, periods, and hyphens and specifically
  131.  * disallows blanks in hostnames.
  132.  */
  133. STATIC
  134. doinitishostchar()
  135. {
  136.     if (!setishostchar) {
  137.         register char *p;
  138.         register int c;
  139.  
  140.         setishostchar = YES;
  141.         for (c = 0, p = ishostchar; c < sizeof ishostchar; c++)
  142.             *p++ = isascii(c) && isalnum(c);
  143.         ishostchar['.'] = ishostchar['-'] = YES;
  144.     }
  145. }
  146.  
  147. /*
  148.  * Return true iff any host in hosts appears in s, as per hostin().
  149.  * hosts are separated by non-hostname characters.
  150.  */
  151. boolean
  152. anyhostin(hosts, s)
  153. char *hosts, *s;
  154. {
  155.     register char *host = hosts;
  156.  
  157.     while (*host != '\0') {
  158.         register char *delimp;
  159.         register int delim;
  160.         register boolean hostisin;
  161.  
  162.         initishostchar();
  163.         while (nothostchar(*host) && *host != '\0')
  164.             ++host;            /* skip leading delims */
  165.         if (*host == '\0')        /* no more hosts */
  166.             break;
  167.         for (delimp = host; hostchar(*delimp); delimp++)
  168.             ;            /* skip to next delim */
  169.         delim = *delimp;        /* may be NUL */
  170.         *delimp = '\0';            /* terminate host */
  171.         hostisin = hostin(host, s);
  172.         *delimp = delim;        /* restore hosts delimiter */
  173.         if (hostisin)
  174.             return YES;
  175.         host = delimp;            /* advance to next host */
  176.     }
  177.     return NO;
  178. }
  179.  
  180. /*
  181.  * Return pointer to the first byte after host in path, if any,
  182.  * with no characters from the alphabet of legal hostname characters
  183.  * immediately adjacent.
  184.  * This function is a profiling hot spot, so it has been optimised.
  185.  */
  186. STATIC char *
  187. findhost(host, path)
  188. register char *host, *path;
  189. {
  190.     register char *pathp, *nxpathp;
  191.     register int hostlen = strlen(host);
  192.  
  193.     initishostchar();
  194.     for (pathp = path; ; pathp = nxpathp + 1) {
  195.         STRCHR(pathp, host[0], nxpathp);    /* find plausible start */
  196.         if (nxpathp == NULL)
  197.             return NULL;        /* path exhausted */
  198.         pathp = nxpathp;
  199.         if (STREQN(pathp, host, hostlen) &&
  200.             (pathp == path || nothostchar(pathp[-1])) &&
  201.             nothostchar(pathp[hostlen]))
  202.             return &pathp[hostlen];
  203.     }
  204. }
  205.  
  206. /*
  207.  * Return true iff host appears in s, with no characters from the alphabet
  208.  * of legal hostname characters immediately adjacent.
  209.  */
  210. boolean
  211. hostin(host, s)
  212. register char *host, *s;
  213. {
  214.     return findhost(host, s) != NULL;
  215. }
  216.  
  217. /*
  218.  * Return the number of machines appearing in path,
  219.  * by counting transitions from delimiters.
  220.  * See anyhostin() for the rules, and the macros.
  221.  */
  222. int
  223. hopcount(path)
  224. register char *path;
  225. {
  226.     register int count = 0;
  227.  
  228.     initishostchar();
  229.     for (; *path != '\0'; path++)
  230.         if (nothostchar(path[0]) &&
  231.             (hostchar(path[1]) || path[1] == '\0'))
  232.             ++count;    /* trailing edge of delimiters */
  233.     return count;
  234. }
  235.  
  236. char *
  237. sendersite(path)
  238. register char *path;
  239. {
  240.     register char *p;
  241.     static char *sender = NULL;
  242.  
  243.     initishostchar();
  244.     nnfree(&sender);        /* free the last answer */
  245.     for (p = path; hostchar(*p); p++)
  246.         ;
  247.     if (*p == '\0')            /* only a user name */
  248.         return "(local)";    /* a local posting */
  249.     else {
  250.         register int delim = *p;
  251.  
  252.         *p = '\0';
  253.         sender = strsave(path);    /* copy the first machine name */
  254.         *p = delim;
  255.         return sender;
  256.     }
  257. }
  258.  
  259. /*
  260.  * Canonicalise rawpath: NULL -> "", chop last site (actually user name) but not
  261.  * its leading delimiter, and if Approved:, chop everything after the site,
  262.  * and its trailing delimiter, from Approved: (or Sender:) (user@host).
  263.  * Result is malloced memory.
  264.  * This is also a profiling hot spot.
  265.  */
  266. char *
  267. canonpath(rawpath, approved, sender)
  268. char *rawpath, *approved, *sender;
  269. {
  270.     register char *newpath = strsave(nullify(rawpath));    /* costly */
  271.     register char *p, *lastdelim = newpath, *site = NULL;
  272.  
  273.     initishostchar();
  274.     for (p = newpath; *p != '\0'; ++p)
  275.         if (nothostchar(*p))
  276.             lastdelim = p + 1;    /* just past delim */
  277.     *lastdelim = '\0';            /* omit user's name */
  278.  
  279.     if (approved != NULL) {            /* moderated article */
  280.         STRCHR(approved, '@', site);
  281.         if (site == NULL)
  282.             STRCHR(nullify(sender), '@', site);
  283.     }
  284.     if (site != NULL) {
  285.         p = findhost(site+1, newpath);
  286.         if (p != NULL && *p++ != '\0')    /* delim after site? */
  287.             *p = '\0';        /* terminate newpath after site */
  288.     }
  289.     return newpath;
  290. }
  291.