home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / pack_name.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  11KB  |  523 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Pack sender's name into something sensible, return in packed:
  5.  *     pack_name(packed, name, length)
  6.  *
  7.  */
  8.  
  9. #include "config.h"
  10.  
  11. /* #define NAME_TEST */    /* Never define this ! */
  12.  
  13. #define    SEP_DOT        0    /* . */
  14. #define    SEP_PERCENT    1    /* % */
  15. #define    SEP_SCORE    2    /* _ */
  16. #define    SEP_AMPERSAND    3    /* @ */
  17. #define    SEP_BANG    4    /* ! */
  18. #define    SEP_MAXIMUM    5
  19.  
  20.  
  21. #define CL_OK        0x0100        /* letter or digit */
  22. #define CL_SPACE    0x0200        /* cvt to space */
  23. #define CL_IGNORE    0x0400        /* ignore */
  24. #define CL_RANGE(c)    0x0800+c    /* space range, end with c */
  25. #define CL_HYPHEN    0x1000        /* convert to - */
  26. #define CL_STOP        0x2000        /* discard rest of name */
  27. #define    CL_SEP        | 0x4000 +        /* address separator */
  28.  
  29. #define    IS_OK(c)    (Class[c] & CL_OK)
  30. #define IS_SPACE(c)    (Class[c] & CL_SPACE)
  31. #define IGNORE(c)    (c & 0x80 || Class[c] & CL_IGNORE)
  32. #define BEGIN_RANGE(c)    (Class[c] & CL_RANGE(0))
  33. #define END_RANGE(c)    (Class[c] & 0xff)
  34. #define IS_HYPHEN(c)    (Class[c] & CL_HYPHEN)
  35. #define IS_STOP(c)    (Class[c] & CL_STOP)
  36. #define    IS_SEPARATOR(c)    (Class[c] & (0 CL_SEP 0))
  37.  
  38. static short Class[128] = {
  39.     /* NUL */        CL_STOP ,
  40.     /* SOH */        CL_IGNORE ,
  41.     /* STX */        CL_IGNORE ,
  42.     /* ETX */        CL_IGNORE ,
  43.     /* EOT */        CL_IGNORE ,
  44.     /* ENQ */        CL_IGNORE ,
  45.     /* ACK */        CL_IGNORE ,
  46.     /* BEL */        CL_IGNORE ,
  47.     /* BS  */        CL_IGNORE ,
  48.     /* TAB */        CL_SPACE ,
  49.     /* NL  */        CL_IGNORE ,
  50.     /* VT  */        CL_IGNORE ,
  51.     /* FF  */        CL_IGNORE ,
  52.     /* CR  */        CL_IGNORE ,
  53.     /* SO  */        CL_IGNORE ,
  54.     /* SI  */        CL_IGNORE ,
  55.     /* DLE */        CL_IGNORE ,
  56.     /* DC1 */        CL_IGNORE ,
  57.     /* DC2 */        CL_IGNORE ,
  58.     /* DC3 */        CL_IGNORE ,
  59.     /* DC4 */        CL_IGNORE ,
  60.     /* NAK */        CL_IGNORE ,
  61.     /* SYN */        CL_IGNORE ,
  62.     /* ETB */        CL_IGNORE ,
  63.     /* CAN */        CL_IGNORE ,
  64.     /* EM  */        CL_IGNORE ,
  65.     /* SUB */        CL_IGNORE ,
  66.     /* ESC */        CL_IGNORE ,
  67.     /* FS  */        CL_IGNORE ,
  68.     /* GS  */        CL_IGNORE ,
  69.     /* RS  */        CL_IGNORE ,
  70.     /* US  */        CL_IGNORE ,
  71.  
  72.     /* space */        CL_SPACE ,
  73.     /*   !   */        CL_SPACE CL_SEP SEP_BANG,
  74.     /*   "   */        CL_RANGE( '"' ) ,
  75.     /*   #   */        CL_OK ,
  76.     /*   $   */        CL_OK ,
  77.     /*   %   */        CL_OK CL_SEP SEP_PERCENT,
  78.     /*   &   */        CL_OK ,
  79.     /*   '   */        CL_OK ,
  80.     /*   (   */        CL_RANGE( ')' ) ,
  81.     /*   )   */        CL_IGNORE ,
  82.     /*   *   */        CL_HYPHEN ,
  83.     /*   +   */        CL_HYPHEN ,
  84.     /*   ,   */        CL_STOP ,
  85.     /*   -   */        CL_HYPHEN ,
  86.     /*   .   */        CL_SPACE CL_SEP SEP_DOT,
  87.     /*   /   */        CL_OK ,
  88.     /*   0   */        CL_OK ,
  89.     /*   1   */        CL_OK ,
  90.     /*   2   */        CL_OK ,
  91.     /*   3   */        CL_OK ,
  92.     /*   4   */        CL_OK ,
  93.     /*   5   */        CL_OK ,
  94.     /*   6   */        CL_OK ,
  95.     /*   7   */        CL_OK ,
  96.     /*   8   */        CL_OK ,
  97.     /*   9   */        CL_OK ,
  98.     /*   :   */        CL_IGNORE ,
  99.     /*   ;   */        CL_STOP ,
  100.     /*   <   */        CL_IGNORE ,
  101.     /*   =   */        CL_HYPHEN ,
  102.     /*   >   */        CL_IGNORE ,
  103.     /*   ?   */        CL_IGNORE ,
  104.     /*   @   */        CL_OK CL_SEP SEP_AMPERSAND,
  105.     /*   A   */        CL_OK ,
  106.     /*   B   */        CL_OK ,
  107.     /*   C   */        CL_OK ,
  108.     /*   D   */        CL_OK ,
  109.     /*   E   */        CL_OK ,
  110.     /*   F   */        CL_OK ,
  111.     /*   G   */        CL_OK ,
  112.     /*   H   */        CL_OK ,
  113.     /*   I   */        CL_OK ,
  114.     /*   J   */        CL_OK ,
  115.     /*   K   */        CL_OK ,
  116.     /*   L   */        CL_OK ,
  117.     /*   M   */        CL_OK ,
  118.     /*   N   */        CL_OK ,
  119.     /*   O   */        CL_OK ,
  120.     /*   P   */        CL_OK ,
  121.     /*   Q   */        CL_OK ,
  122.     /*   R   */        CL_OK ,
  123.     /*   S   */        CL_OK ,
  124.     /*   T   */        CL_OK ,
  125.     /*   U   */        CL_OK ,
  126.     /*   V   */        CL_OK ,
  127.     /*   W   */        CL_OK ,
  128.     /*   X   */        CL_OK ,
  129.     /*   Y   */        CL_OK ,
  130.     /*   Z   */        CL_OK ,
  131.     /*   [   */        CL_OK ,
  132.     /*   \   */        CL_OK ,
  133.     /*   ]   */        CL_OK ,
  134.     /*   ^   */        CL_IGNORE ,
  135.     /*   _   */        CL_SPACE CL_SEP SEP_SCORE,
  136.     /*   `   */        CL_IGNORE ,
  137.     /*   a   */        CL_OK ,
  138.     /*   b   */        CL_OK ,
  139.     /*   c   */        CL_OK ,
  140.     /*   d   */        CL_OK ,
  141.     /*   e   */        CL_OK ,
  142.     /*   f   */        CL_OK ,
  143.     /*   g   */        CL_OK ,
  144.     /*   h   */        CL_OK ,
  145.     /*   i   */        CL_OK ,
  146.     /*   j   */        CL_OK ,
  147.     /*   k   */        CL_OK ,
  148.     /*   l   */        CL_OK ,
  149.     /*   m   */        CL_OK ,
  150.     /*   n   */        CL_OK ,
  151.     /*   o   */        CL_OK ,
  152.     /*   p   */        CL_OK ,
  153.     /*   q   */        CL_OK ,
  154.     /*   r   */        CL_OK ,
  155.     /*   s   */        CL_OK ,
  156.     /*   t   */        CL_OK ,
  157.     /*   u   */        CL_OK ,
  158.     /*   v   */        CL_OK ,
  159.     /*   w   */        CL_OK ,
  160.     /*   x   */        CL_OK ,
  161.     /*   y   */        CL_OK ,
  162.     /*   z   */        CL_OK ,
  163.     /*   {   */        CL_OK ,
  164.     /*   |   */        CL_OK ,
  165.     /*   }   */        CL_OK ,
  166.     /*   ~   */        CL_HYPHEN ,
  167.     /*  DEL  */        CL_IGNORE
  168. } ;
  169.  
  170.  
  171. int
  172. pack_name(dest, source, length)
  173. char *dest, *source;
  174. int length;
  175. {
  176.     register char *p, *q, *r, c;
  177.     register int n;
  178.     register int i;
  179.     register int sep;
  180.     register int ignore_braces = 0;
  181.     register char *name;
  182.     register int lname;
  183.     register int drop_space, prev_space;
  184.     char *maxq;
  185.     int lfirst, lmiddle, llast;
  186.     char namebuf[129];
  187.     char *separator[SEP_MAXIMUM];
  188.  
  189.     dest[0] = NUL;
  190.  
  191.     if (source == NULL || source[0] == NUL)
  192.     return 0;
  193.  
  194. full_scan:
  195.     p = source, q = namebuf, n = 0;
  196.     maxq = namebuf + sizeof namebuf - 1;
  197.  
  198. new_partition:
  199.     for (i = SEP_MAXIMUM; --i >= 0; separator[i] = NULL);
  200.  
  201.     while (( c = *p++ )) {
  202.     if (c == '<') {
  203.         while (q > namebuf && q[-1] == SP) q--;
  204.         if (q == namebuf) continue;
  205.         break;
  206.     }
  207.     if (c == ')') {
  208.         if (--n == 0 && !ignore_braces) break;
  209.         continue;
  210.     }
  211.     if (IGNORE((int8)c)) continue;
  212.     if (q == namebuf && IS_SPACE((int8)c)) continue;
  213.     if (c == '(') {
  214.         if (n++ == 0 && !ignore_braces) {
  215.         q = namebuf;
  216.         goto new_partition;
  217.         }
  218.         continue;
  219.     }
  220.     if (n > 0)
  221.         if (ignore_braces || n > 1) continue;
  222.     if (q >= maxq) break;
  223.     *q++ = c;
  224.     if (IS_SEPARATOR((int8)c)) {
  225.         switch ((sep = (Class[(int8)c] & 0xff))) {
  226.  
  227.          case SEP_DOT:
  228.         if (separator[SEP_AMPERSAND] && q - namebuf <= length)
  229.             break;
  230.         continue;
  231.  
  232.          case SEP_BANG:
  233.         if (separator[SEP_AMPERSAND]) continue;
  234.         break;
  235.  
  236.          default:
  237.         if (separator[sep]) continue;
  238.         break;
  239.         }
  240.  
  241.         separator[sep] = q - 1;
  242.     }
  243.     }
  244.  
  245.     *q = NUL;
  246.  
  247.     if (namebuf[0] == NUL && !ignore_braces ) {
  248.     ignore_braces = 1;
  249.     goto full_scan;
  250.     }
  251.  
  252.     if (namebuf[0] == NUL) return 0;
  253.  
  254.     name = namebuf;
  255.  
  256.     if (name[0] == '"') {
  257.     name++;
  258.     if (q[-1] == '"') *--q = NUL;
  259.     }
  260.  
  261.     if (q - name <= length) goto name_ok;
  262.  
  263.     /* sorry for the many goto's -- the 3B2 C compiler does not */
  264.     /* make correct code for complicated logical expressions!!  */
  265.     /* not even without -O                    */
  266.  
  267.     /* We must pack the name to make it fit */
  268.  
  269.     /* Name_of_person%... -> Name_of_person */
  270.  
  271.     if ((r = separator[SEP_PERCENT])) {
  272.     if (!(q = separator[SEP_SCORE]) || q > r )
  273.         goto no_percent;
  274.     if ((q = separator[SEP_AMPERSAND]) && q < r)
  275.         goto no_percent;
  276.     if ((q = separator[SEP_BANG]) && q < r)
  277.         goto no_percent;
  278.     *r = NUL;
  279.     goto parse_name;
  280.     }
  281.  
  282.  no_percent:
  283.  
  284.     /* name@site.domain -> name@site */
  285.  
  286.    if ((r = separator[SEP_AMPERSAND])) {
  287.  
  288.        if ((q = separator[SEP_PERCENT]) && q < r) {
  289.        *r = NUL;
  290.        if (r - name <= length) goto name_ok;
  291.  
  292.        *q = NUL;
  293.  
  294.        if (((p = separator[SEP_BANG]) && p < q)
  295.          || ((p = strrchr(name, '!')) && p < q)) {
  296.            name = p + 1;
  297.        }
  298.  
  299.        if (strchr(name, '.'))
  300.            goto parse_name;
  301.  
  302.        goto name_ok;
  303.        }
  304.  
  305.        if ((q = separator[SEP_DOT])) {
  306.        *q = NUL;
  307.        goto name_ok;
  308.        }
  309.  
  310.        *r = NUL;
  311.        if (r - name <= length) goto name_ok;
  312.  
  313.        if ((q = separator[SEP_BANG]) && q < r) {
  314.        name = q + 1;
  315.        goto name_ok;
  316.        }
  317.  
  318. #ifdef NOTDEF
  319.        if (strchr(name, '!') == NULL)
  320.        goto parse_name; /* take the chance ... */
  321. #endif
  322.     goto name_ok;    /* can't do it any better */
  323.     }
  324.  
  325.  
  326.     /* Phase 1: Normalization (remove superfluous characters) */
  327.  
  328.  parse_name:
  329.  
  330.     for (p = name, lname = 0, prev_space = 0; (c = *p); p++) {
  331.  
  332. /*
  333.     if (IGNORE(c)) {
  334.         *p = TAB;
  335.         if (p == name) name++;
  336.         continue;
  337.     }
  338. */
  339.  
  340.     if (IS_OK((int8)c)) {
  341.         lname++;
  342.         prev_space = 0;
  343.         continue;
  344.     }
  345.  
  346.     if (IS_HYPHEN((int8)c)) {
  347.         if (p == name) {
  348.         name++;
  349.         continue;
  350.         }
  351.         if (prev_space) {
  352.         *p = NUL; break;    /* strip from " -" */
  353.         /* *p = TAB; */     /* do not strip from " -" */
  354.         } else {
  355.         *p = '-';
  356.         lname++;
  357.         }
  358.         continue;
  359.     }
  360.  
  361.     if (BEGIN_RANGE((int8)c)) {
  362.  
  363.         if (p == name) {
  364.         name++;
  365.         continue;
  366.         }
  367.  
  368.         c = END_RANGE((int8)c);
  369.         for (q = p+1; *q && *q != c; q++);
  370.         if (*q) {
  371.         if (p[-1] != ' ') lname++;
  372.         while (p <= q) *p++ = ' ';
  373.         p--;
  374.         prev_space++;
  375.         continue;
  376.         }
  377.         c = ' ';
  378.     }
  379.  
  380.     if (IS_SPACE((int8)c)) {
  381.         *p = ' ';
  382.         if (p == name)
  383.         name++;
  384.         else
  385.         if (!prev_space) {
  386.             lname++;
  387.             prev_space++;
  388.         }
  389.         continue;
  390.     }
  391.  
  392.     if (IS_STOP((int8)c)) {
  393.         *p = NUL;
  394.         break;
  395.     }
  396.     }
  397.  drop_last_name:
  398.     while (p > name && (*--p == ' ' || *p == TAB)) *p = NUL;
  399.  
  400.     if (lname < length) goto name_ok;
  401.  
  402.  
  403.     /* Phase 2: Reduce middle names */
  404.  
  405.     for (r = p, llast = 0; r > name && *r != ' '; r--)
  406.     if (*r != TAB) llast++;
  407.  
  408.     /* r points to space before last name */
  409.  
  410.     if (strncmp(r, " Jr", 3) == 0 || strncmp(r, " II", 3) == 0) {
  411.     p = r+1;
  412.     lname -= llast;
  413.     goto drop_last_name;
  414.     }
  415.  
  416.     if (r == name) goto phase6;    /* only last name */
  417.  
  418.     for (q = name, lfirst = 0; *q && *q != ' '; q++)
  419.     if (*q != TAB) lfirst++;
  420.  
  421.     /* q points at space after first name */
  422.  
  423.     for (p = q, lmiddle = 0; p < r; ) {
  424.     /* find next middle name */
  425.     while (p < r && (*p == ' ' || *p == TAB)) p++;
  426.  
  427.     if (p >= r) break; /* found last name */
  428.  
  429.     p++; /* skip first char of middle name */
  430.     for (;*p != ' '; p++) { /* remove rest */
  431.         if (*p == TAB) continue;
  432.         *p = TAB;
  433.         lname--;
  434.     }
  435.     lmiddle += 2;    /* initial + space */
  436.     }
  437.  
  438.     if (lname < length) goto name_ok;
  439.  
  440.     /* If removing middle names is not enough, but reducing first name instead is, do it that way */
  441.  
  442.     if (lname - lmiddle >= length && lname - lfirst + 1 < length) goto phase4;
  443.  
  444.  
  445.     /* Phase 3: Remove middle names */
  446.  
  447.     for (p = q; p < r; p++) {
  448.     if (*p == TAB) continue;
  449.     if (*p == ' ') continue;
  450.     *p = TAB;
  451.     lname -= 2;
  452.     }
  453.  
  454.     if (lname < length) goto name_ok;
  455.  
  456.  
  457.     /* Phase 4: Reduce first name */
  458.  
  459.  phase4:
  460.     for (p = name+1; p < q; p++) {
  461.     if (*p == TAB) continue;
  462.     if (*p == ' ') continue;
  463.     if (*p == '-' && (p + 1) < q) {
  464.         p++;
  465.         continue;
  466.     }
  467.     *p = TAB;
  468.     lname--;
  469.     }
  470.  
  471.     if (lname < length) goto name_ok;
  472.  
  473.     /* Phase 5: Remove first name */
  474.  
  475.     name = r+1;
  476.     lname--;
  477.  
  478.     if (lname < length) goto name_ok;
  479.  
  480.     /* Phase 6: Cut last name */
  481.  phase6:
  482.     goto name_ok;
  483.  
  484.  name_ok:
  485.  
  486.     q = dest;
  487.     maxq = q + length;
  488.  
  489.     drop_space = 1;
  490.  
  491.     for (p = name; *p && q < maxq ; p++) {
  492.     if (*p == TAB) continue;
  493.  
  494.     if ( *p == ' ' ) {
  495.         if (!drop_space) {
  496.         drop_space = 1;
  497.         *q++ = ' ';
  498.         }
  499.         continue;
  500.     }
  501.     drop_space = 0;
  502.     *q++ = *p;
  503.     }
  504.  
  505.     *q = NUL;
  506.  
  507.     return strlen(dest);
  508. }
  509.  
  510. #ifdef NAME_TEST
  511.  
  512. main() {
  513.     char in[512], out[512];
  514.  
  515.     while (gets(in)) {
  516.     printf("'%s' -> (%d) ", in, pack_name(out,in,NAME_LENGTH));
  517.     puts(out);
  518.     }
  519.     exit(0);
  520. }
  521.  
  522. #endif
  523.