home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / par150o2.zip / charset.c < prev    next >
C/C++ Source or Header  |  1996-01-21  |  7KB  |  293 lines

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