home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume39 / par131 / part02 / Par131 / charset.c next >
C/C++ Source or Header  |  1993-09-11  |  7KB  |  290 lines

  1. /*********************/
  2. /* charset.c         */
  3. /* for Par 1.31      */
  4. /* Copyright 1993 by */
  5. /* Adam M. Costello  */
  6. /*********************/
  7.  
  8. /* This is ANSI C code. */
  9.  
  10.  
  11. /* Because this is ANSI C code, we can't assume that there are only 256 */
  12. /* characters.  Therefore, we can't use bit vectors to represent sets   */
  13. /* without the risk of consuming large amounts of memory.  Therefore,   */
  14. /* this code is much more complicated than might be expected.           */
  15.  
  16.  
  17. #include "charset.h"  /* Makes sure we're consistent with the.  */
  18.                       /* prototypes.  Also includes "errmsg.h". */
  19. #include "buffer.h"   /* Also includes <stddef.h>.              */
  20.  
  21. #include <ctype.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25.  
  26.  
  27. #undef NULL
  28. #define NULL ((void *) 0)
  29.  
  30. #ifdef DONTFREE
  31. #define free(ptr)
  32. #endif
  33.  
  34.  
  35. struct charset {
  36.   char *inlist;   /* Characters in inlist are in the set.                */
  37.   char *outlist;  /* Characters in outlist are not in the set.           */
  38.                   /* inlist and outlist must have no common characters.  */
  39.                   /* inlist and outlist may be NULL, which acts like "". */
  40.   short flags;    /* Characters in neither list are in the set if they   */
  41.                   /* belong to any of the classes indicated by flags.    */
  42. };
  43.  
  44. /* The following may be bitwise-OR'd together */
  45. /* to set the flags field of a charset:       */
  46.  
  47. static const short CS_UCASE = 1,  /* Includes all upper case letters. */
  48.                    CS_LCASE = 2,  /* Includes all lower case letters. */
  49.                    CS_DIGIT = 4,  /* Includes all decimal digits.     */
  50.                    CS_NUL   = 8;  /* Includes the NUL character.      */
  51.  
  52.  
  53. static int appearsin(char c, const char *str)
  54.  
  55. /* Returns 0 if c is '\0' or str is NULL or c     */
  56. /* does not appear in *str.  Otherwise returns 1. */
  57. {
  58.   return c && str && strchr(str,c);
  59. }
  60.  
  61.  
  62. static int hexdigtoint(char c)
  63.  
  64. /* Returns the value represented by the hexadecimal */
  65. /* digit c, or -1 if c is not a hexadecimal digit.  */
  66. {
  67.   const char *p, * const hexdigits = "0123456789ABCDEF";
  68.  
  69.   if (!c) return -1;
  70.   p = strchr(hexdigits, toupper(c));
  71.   return p ? p - hexdigits : -1;
  72.  
  73.   /* We can't do things like c - '0' or c - 'A' because we can't depend     */
  74.   /* on the order of the characters in ANSI C.  Nor can we do things like   */
  75.   /* hexdigtoint[c] because we don't know how large such an array might be. */
  76. }
  77.  
  78.  
  79. charset *parsecharset(const char *str, errmsg_t errmsg)
  80. {
  81.   charset *cset = NULL;
  82.   struct buffer *cbuf = NULL;
  83.   const char *p, * const singleescapes = "_sbqQx";
  84.   int hex1, hex2;
  85.   char ch;
  86.  
  87.   cset = malloc(sizeof (charset));
  88.   if (!cset) {
  89.     strcpy(errmsg,outofmem);
  90.     goto pcserror;
  91.   }
  92.   cset->inlist = cset->outlist = NULL;
  93.   cset->flags = 0;
  94.  
  95.   cbuf = newbuffer(sizeof (char), errmsg);
  96.   if (*errmsg) goto pcserror;
  97.  
  98.   for (p = str;  *p;  ++p)
  99.     if (*p == '_') {
  100.       ++p;
  101.       if (appearsin(*p, singleescapes)) {
  102.         if      (*p == '_') ch = '_' ;
  103.         else if (*p == 's') ch = ' ' ;
  104.         else if (*p == 'b') ch = '\\';
  105.         else if (*p == 'q') ch = '\'';
  106.         else if (*p == 'Q') ch = '\"';
  107.         else /*  *p == 'x'  */ {
  108.           hex1 = hexdigtoint(p[1]);
  109.           hex2 = hexdigtoint(p[2]);
  110.           if (hex1 < 0  ||  hex2 < 0) goto pcsbadstr;
  111.           ch = 16 * hex1 + hex2;
  112.           p += 2;
  113.         }
  114.         if (!ch)
  115.           cset->flags |= CS_NUL;
  116.         else {
  117.           additem(cbuf, &ch, errmsg);
  118.           if (*errmsg) goto pcserror;
  119.         }
  120.       }
  121.       else {
  122.         if      (*p == 'A') cset->flags |= CS_UCASE;
  123.         else if (*p == 'a') cset->flags |= CS_LCASE;
  124.         else if (*p == '0') cset->flags |= CS_DIGIT;
  125.         else goto pcsbadstr;
  126.       }
  127.     }
  128.     else {
  129.       additem(cbuf,p,errmsg);
  130.       if (*errmsg) goto pcserror;
  131.     }
  132.   ch = '\0';
  133.   additem(cbuf, &ch, errmsg);
  134.   if (*errmsg) goto pcserror;
  135.   cset->inlist = copyitems(cbuf,errmsg);
  136.   if (*errmsg) goto pcserror;
  137.  
  138. pcscleanup:
  139.  
  140.   if (cbuf) freebuffer(cbuf);
  141.   return cset;
  142.  
  143. pcsbadstr:
  144.  
  145.   sprintf(errmsg, "Bad charset syntax: %.*s\n", errmsg_size - 22, str);
  146.  
  147. pcserror:
  148.  
  149.   if (cset) freecharset(cset);
  150.   cset = NULL;
  151.   goto pcscleanup;
  152. }
  153.  
  154.  
  155. void freecharset(charset *cset)
  156. {
  157.   if (cset->inlist) free(cset->inlist);
  158.   if (cset->outlist) free(cset->outlist);
  159.   free(cset);
  160. }
  161.  
  162.  
  163. int csmember(char c, const charset *cset)
  164. {
  165.   return    appearsin(c, cset->inlist)
  166.          ||    !appearsin(c, cset->outlist)
  167.             && (    cset->flags & CS_LCASE && islower(c)
  168.                 ||  cset->flags & CS_UCASE && isupper(c)
  169.                 ||  cset->flags & CS_DIGIT && isdigit(c)
  170.                 ||  cset->flags & CS_NUL   && !c         );
  171. }
  172.  
  173.  
  174. static charset *csud(int u, const charset *cset1,
  175.                      const charset *cset2, errmsg_t errmsg)
  176.  
  177. /* Returns the union of cset1 and cset2 if u is 1, or the set    */
  178. /* difference cset1 - cset2 if u is 0.  Returns NULL on failure. */
  179. {
  180.   charset *csu;
  181.   buffer *inbuf = NULL, *outbuf = NULL;
  182.   char *lists[4], **list, *p, nullchar = '\0';
  183.  
  184.   csu = malloc(sizeof (charset));
  185.   if (!csu) {
  186.     strcpy(errmsg,outofmem);
  187.     goto csuderror;
  188.   }
  189.   inbuf = newbuffer(sizeof (char), errmsg);
  190.   if (*errmsg) goto csuderror;
  191.   outbuf = newbuffer(sizeof (char), errmsg);
  192.   if (*errmsg) goto csuderror;
  193.   csu->inlist = csu->outlist = NULL;
  194.   csu->flags =  u  ?  cset1->flags |  cset2->flags
  195.                    :  cset1->flags & ~cset2->flags;
  196.  
  197.   lists[0] = cset1->inlist;
  198.   lists[1] = cset1->outlist;
  199.   lists[2] = cset2->inlist;
  200.   lists[3] = cset2->outlist;
  201.  
  202.   for (list = lists;  list < lists + 4;  ++list)
  203.     for (p = *list;  *p;  ++p)
  204.       if (u  ?  csmember(*p, cset1) ||  csmember(*p, cset2)
  205.              :  csmember(*p, cset1) && !csmember(*p, cset2)) {
  206.         if (!csmember(*p, csu)) {
  207.           additem(inbuf,p,errmsg);
  208.           if (*errmsg) goto csuderror;
  209.         }
  210.       }
  211.       else
  212.         if (csmember(*p, csu)) {
  213.           additem(outbuf,p,errmsg);
  214.           if (*errmsg) goto csuderror;
  215.         }
  216.  
  217.   additem(inbuf, &nullchar, errmsg);
  218.   if (*errmsg) goto csuderror;
  219.   additem(outbuf, &nullchar, errmsg);
  220.   if (*errmsg) goto csuderror;
  221.   csu->inlist = copyitems(inbuf,errmsg);
  222.   if (*errmsg) goto csuderror;
  223.   csu->outlist = copyitems(outbuf,errmsg);
  224.   if (*errmsg) goto csuderror;
  225.  
  226. csudcleanup:
  227.  
  228.   if (inbuf) freebuffer(inbuf);
  229.   if (outbuf) freebuffer(outbuf);
  230.   return csu;
  231.  
  232. csuderror:
  233.  
  234.   if (csu) freecharset(csu);
  235.   csu = NULL;
  236.   goto csudcleanup;
  237. }
  238.  
  239.  
  240. charset *csunion(const charset *cset1, const charset *cset2, errmsg_t errmsg)
  241. {
  242.   return csud(1,cset1,cset2,errmsg);
  243. }
  244.  
  245.  
  246. charset *csdiff(const charset *cset1, const charset *cset2, errmsg_t errmsg)
  247. {
  248.   return csud(0,cset1,cset2,errmsg);
  249. }
  250.  
  251.  
  252. void csadd(charset *cset1, const charset *cset2, errmsg_t errmsg)
  253. {
  254.   charset *csu;
  255.  
  256.   csu = csunion(cset1,cset2,errmsg);
  257.   if (*errmsg) return;
  258.   csswap(csu,cset1);
  259.   freecharset(csu);
  260. }
  261.  
  262.  
  263. void csremove(charset *cset1, const charset *cset2, errmsg_t errmsg)
  264. {
  265.   charset *csu;
  266.  
  267.   csu = csdiff(cset1,cset2,errmsg);
  268.   if (*errmsg) return;
  269.   csswap(csu,cset1);
  270.   freecharset(csu);
  271. }
  272.  
  273.  
  274. charset *cscopy(const charset *cset, errmsg_t errmsg)
  275. {
  276.   charset emptycharset = { NULL, NULL, 0 };
  277.  
  278.   return csunion(cset, &emptycharset, errmsg);
  279. }
  280.  
  281.  
  282. void csswap(charset *cset1, charset *cset2)
  283. {
  284.   charset tmp;
  285.  
  286.   tmp = *cset1;
  287.   *cset1 = *cset2;
  288.   *cset2 = tmp;
  289. }
  290.