home *** CD-ROM | disk | FTP | other *** search
/ ftp.shrubbery.net / 2015-02-07.ftp.shrubbery.net.tar / ftp.shrubbery.net / pub / foad / foad-0.3.tar.gz / foad-0.3.tar / foad-0.3 / parser.y < prev    next >
Text File  |  2001-09-06  |  7KB  |  384 lines

  1. %{
  2. #include "foad.h"
  3.  
  4. #include <sys/stat.h>
  5.  
  6. extern    char    *progname,            /* program's name */
  7.         *c_bcc,
  8.         *c_from,
  9.         *c_cc,
  10.         *c_to;
  11. extern    s_addresses    bcc,
  12.         from,
  13.         cc,
  14.         to;
  15. extern    int    debug,
  16.         negate;
  17.  
  18. #define    YYDEBUG 1                /* include debugging */
  19. #define    YYERROR_VERBOSE 1
  20.  
  21. #define    Y_DEBUG        (debug > 1)
  22. %}
  23.  
  24. /* declarations */
  25. %union {
  26.     char        *cptr;
  27. }
  28.  
  29. %token    <cptr>    T_BCC T_BCC_CONT
  30. %token    <cptr>    T_FROM
  31. %token    <cptr>    T_CC T_CC_CONT
  32. %token    <cptr>    T_TO T_TO_CONT
  33. %token        T_CONT T_LINE
  34.  
  35. /* grammar */
  36. %start headers
  37. %%
  38. headers: stmts
  39.     {
  40.     }
  41.     ;
  42.  
  43. stmts:      stmt
  44.     | stmts stmt
  45.     ;
  46.  
  47. stmt:      bcc_stmt
  48.     | from_stmt
  49.     | to_stmt
  50.     | cc_stmt
  51.     | lines
  52.     | '\n'
  53.     ;
  54.  
  55. lines:    line
  56.     | lines line
  57.     ;
  58. line:    T_LINE '\n'
  59.     {
  60.       if (Y_DEBUG)
  61.         fprintf(stderr, "%s: parser line\n", progname);
  62.     }
  63.     | T_CONT '\n'
  64.     {
  65.       if (Y_DEBUG)
  66.         fprintf(stderr, "%s: parser continue\n", progname);
  67.     }
  68.     ;
  69.  
  70. bcc_stmt: bcc_bits
  71.     | bcc_stmt bcc_bits
  72.     ;
  73. bcc_bits: T_BCC '\n'
  74.     {
  75.       if (c_bcc)
  76.         append(&c_bcc, ",");
  77.       append(&c_bcc, $1);
  78.       if (Y_DEBUG)
  79.         fprintf(stderr, "%s: parser BCC: %s\n", progname, $1);
  80.       free($1);
  81.     }
  82.     | T_BCC_CONT '\n'
  83.     {
  84.       append(&c_bcc, $1);
  85.       if (Y_DEBUG)
  86.         fprintf(stderr, "%s: parser BCC continue: %s\n", progname, $1);
  87.       free($1);
  88.     }
  89.     ;
  90.  
  91. from_stmt: T_FROM '\n'
  92.     {
  93.       append(&c_from, $1);
  94.       if (Y_DEBUG)
  95.         fprintf(stderr, "%s: parser FROM: %s\n", progname, $1);
  96.       free($1);
  97.     }
  98.     ;
  99.  
  100. cc_stmt: cc_bits
  101.     | cc_stmt cc_bits
  102.     ;
  103.  
  104. cc_bits: T_CC '\n'
  105.     {
  106.       if (c_cc)
  107.         append(&c_cc, ",");
  108.       append(&c_cc, $1);
  109.       if (Y_DEBUG)
  110.         fprintf(stderr, "%s: parser CC: %s\n", progname, $1);
  111.       free($1);
  112.     }
  113.     | T_CC_CONT '\n'
  114.     {
  115.       append(&c_cc, $1);
  116.       if (Y_DEBUG)
  117.         fprintf(stderr, "%s: parser CC continue: %s\n", progname, $1);
  118.       free($1);
  119.     }
  120.     ;
  121.  
  122. to_stmt: to_bits
  123.     | to_stmt to_bits
  124.     ;
  125. to_bits: T_TO '\n'
  126.     {
  127.       if (c_to)
  128.         append(&c_to, ",");
  129.       append(&c_to, $1);
  130.       if (Y_DEBUG)
  131.         fprintf(stderr, "%s: parser TO: %s\n", progname, $1);
  132.       free($1);
  133.     }
  134.     | T_TO_CONT '\n'
  135.     {
  136.       append(&c_to, $1);
  137.       if (Y_DEBUG)
  138.         fprintf(stderr, "%s: parser TO continue: %s\n", progname, $1);
  139.       free($1);
  140.     }
  141.     ;
  142.  
  143. %%
  144.  
  145. /* C */
  146.  
  147. /*   
  148.       function: int read_header()
  149.    description: use the parser to read the mail headers from stdin, then
  150.         split() them
  151.        returns: non-zero on parser error
  152.  */
  153. int
  154. read_header(void)
  155. {
  156.     extern FILE    *yyin;
  157.     int        val = 0;
  158.  
  159.     yyin = stdin;
  160.     val = yyparse();
  161.  
  162.     if (debug) {
  163.     if (c_from)
  164.         fprintf(stderr, " c_from = %s\n", c_from);
  165.     if (c_to)
  166.         fprintf(stderr, "   c_to = %s\n", c_to);
  167.     if (c_cc)
  168.         fprintf(stderr, "   c_cc = %s\n", c_cc);
  169.     if (c_bcc)
  170.         fprintf(stderr, "  c_bcc = %s\n", c_bcc);
  171.     }
  172.     if (! val) {
  173.     split(c_from, &from);
  174.     split(c_to, &to);
  175.     split(c_cc, &cc);
  176.     split(c_bcc, &bcc);
  177.     }
  178.  
  179.     return(val);
  180. }
  181.  
  182. /*   
  183.       function: int append(dest string **, string *)
  184.    description: append string to the of dest string
  185.        returns: NULL on error
  186.  */
  187. int
  188. append(char **dst, char *s)
  189. {
  190.     char    *new;
  191.     int        len;
  192.  
  193.     if (s == NULL)
  194.     return(0);
  195.  
  196.     while (*s == ' ' || *s == '\t') { s++; }
  197.  
  198.     if (*dst == NULL)
  199.     len = strlen(s) + 2;
  200.     else
  201.     len = strlen(*dst) + strlen(s) + 2;
  202.  
  203.     if ((new = malloc(len)) == NULL) {
  204.     fprintf(stderr, "%s: malloc failure: %s\n", progname, strerror(errno));
  205.     exit(1 ^ negate);
  206.     }
  207.     bzero(new, len);
  208.  
  209.     if (*dst != NULL)
  210.     strcpy(new, *dst);
  211.     strcat(new, s);
  212.  
  213.     free(*dst);
  214.     *dst = new;
  215.  
  216.     return(0);
  217. }
  218.  
  219. /*   
  220.       function: int lappend(linked list *, node *)
  221.    description: append a linked list node to linked list
  222.        returns: NULL on error
  223.  */
  224. int
  225. lappend(struct s_addresses *dst, node *n)
  226. {
  227.     node    *next;
  228.  
  229.     if (dst->next == NULL) {
  230.     dst->next = n;
  231.     } else {
  232.     next = dst->next;
  233.     while (next) {
  234.         if (next->next == NULL) {
  235.         next->next = n;
  236.         break;
  237.         } else
  238.         next = next->next;
  239.     }
  240.     }
  241.     return(0);
  242. }
  243.  
  244. /*   
  245.       function: int split(header string *, per-header linked list *)
  246.    description: split a header (from/to/cc/bcc) into the address portion
  247.         only and add it to the linked list (for the header)
  248.        returns: exit on error
  249.  */
  250. int
  251. split(char *a, s_addresses *dst)
  252. {
  253.     char    *comma,
  254.         *left,
  255.         *quote;
  256.     int        end;
  257.     node    *new = NULL;
  258.  
  259.     if (a == NULL)
  260.     return(0);
  261.  
  262.     /* string quoted "strings" */
  263.     for (;;) {
  264.     if ((quote = index(a, '"')) == NULL)
  265.         break;
  266.     if ((comma = index(quote + 1, '"')) == NULL) {
  267.         fprintf(stderr, "%s: apparent address format error, unmatched \"s:"
  268.         " %s\n", progname, a);
  269.         exit(1 ^ negate);
  270.     }
  271.     strcpy(quote, comma + 1);
  272.     }
  273.     /* string quoted (strings) */
  274.     for (;;) {
  275.     if ((quote = index(a, '(')) == NULL)
  276.         break;
  277.     if ((comma = index(quote + 1, ')')) == NULL) {
  278.         fprintf(stderr, "%s: apparent address format error, unmatched ()s:"
  279.         " %s\n", progname, a);
  280.         exit(1 ^ negate);
  281.     }
  282.     strcpy(quote, comma + 1);
  283.     }
  284.     /* strip ' ;' or ': ;' constructs */
  285.     left = a;
  286.     for (;;) {
  287.     if ((comma = index(left, ';')) == NULL)
  288.         break;
  289.     quote = comma;
  290.     /* backup until we find a ':' */
  291.     while (quote > a && *(quote - 1) != ':') {
  292.         quote--;
  293.     }
  294.     if (quote > a && *(quote - 1) == ':') {
  295.         /* strip ": ;" */
  296.         strcpy(quote, comma);
  297.         *quote = ',';
  298.         left = quote;
  299.     } else {
  300.         /* strip ";" */
  301.         strcpy(comma, comma + 1);
  302.         left = comma;
  303.     }
  304.     }
  305.     /* strip spaces at EOL and before commas */
  306.     end = strlen(a) - 1;
  307.     while (*(a + end) == ' ' || *(a + end) == '\t') {
  308.     *(a + end) = '\0';
  309.     end--;
  310.     }
  311.     left = a;
  312.     while ((comma = index(left, ',')) != NULL) {
  313.     quote = comma;
  314.     while (*(quote - 1) == ' ' || *(quote - 1) == '\t') {
  315.         quote--;
  316.     }
  317.     if (*quote == ' ' || *quote == '\t')
  318.         strcpy(quote, comma);
  319.     left = quote + 1;
  320.     }
  321.  
  322.     /* split *a into individual addresses */
  323.     end = 0;
  324.     for (;;) {
  325.     /* skip leading space */
  326.     while (*a == ' ' || *a == '\t') { a++; }
  327.     if (a == NULL)
  328.         break;
  329.  
  330.     /* new space */
  331.     if (new == NULL) {
  332.         if ((new = malloc(sizeof(node))) == NULL) {
  333.         fprintf(stderr, "%s: malloc failure: %s\n", progname,
  334.             strerror(errno));
  335.         exit(1 ^ negate);
  336.         }
  337.         bzero((void *) new, sizeof(node));
  338.     }
  339.  
  340.     /* should be left with addresses separated by commas */
  341.     if ((comma = index(a, ',')) != NULL) {
  342.         *comma = '\0';
  343.     } else {
  344.         comma = a + strlen(a);
  345.         end = 1;
  346.     }
  347.     
  348.     if (*(comma - 1) == '>') {
  349.         *(comma - 1) = '\0';
  350.         if ((left = strrchr(a, '<')) == NULL) {
  351.         fprintf(stderr, "%s: apparent address format error: %s\n",
  352.             progname, a);
  353.         exit(1 ^ negate);
  354.         }
  355.         left++;
  356.         if (comma - left <= 0)
  357.         goto SKIP;
  358.     } else if ((left = strrchr(a, ' ')) != NULL) {
  359.         left++;
  360.     }
  361.  
  362.     if (left == NULL)
  363.         left = a;
  364.  
  365.     if (strlen(left) == 0)
  366.         goto SKIP;
  367.  
  368.     if (debug > 1)
  369.         fprintf(stderr, "%s: split() adding: %s\n", progname, left);
  370.  
  371.     new->addr = strdup(left);
  372.     lappend(dst, new);  new = NULL;
  373.  
  374. SKIP:    if (end)
  375.         break;
  376.     a = comma + 1;
  377.     }
  378.  
  379.     if (new)
  380.     free(new);
  381.  
  382.     return(0);
  383. }
  384.