home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games (Alt) / INFESPGAMES.iso / os2 / backgam / source / expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-02  |  13.5 KB  |  435 lines

  1. /*************************************************************
  2.  *    ______                                                 *
  3.  *   /     /\  TinyFugue was derived from a client initially *
  4.  *  /   __/  \ written by Anton Rang (Tarrant) and later     *
  5.  *  |  / /\  | modified by Leo Plotkin (Grod).  The early    *
  6.  *  |  |/    | versions of TinyFugue written by Greg Hudson  *
  7.  *  |  X__/  | (Explorer_Bob).  The current version is       *
  8.  *  \ /      / written and maintained by Ken Keys (Hawkeye), *
  9.  *   \______/  who can be reached at kkeys@ucsd.edu.         *
  10.  *                                                           *
  11.  *             No copyright 1992, no rights reserved.        *
  12.  *             Fugue is in the public domain.                *
  13.  *************************************************************/
  14.  
  15. /********************************************************************
  16.  * Fugue macro text expander                                        *
  17.  *                                                                  *
  18.  * Expands a macro body, doing argument and reentrance substitution *
  19.  * Originally written by Greg Hudson, with mods by Ken Keys.        *
  20.  ********************************************************************/
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include "tf.h"
  25. #include "dstring.h"
  26. #include "util.h"
  27. #include "macro.h"
  28. #include "socket.h"
  29. #include "command1.h"
  30. #include "output.h"
  31.  
  32. #define MAX_ARGS 100
  33. #ifndef BSD
  34. #define RANDOM rand
  35. #else
  36. #define RANDOM random
  37. #endif
  38.  
  39. extern int mecho;
  40. extern Stringp mprefix, lastname;
  41.  
  42. static int recur_count = 0;
  43. #ifndef MAX_RECUR
  44. #define MAX_RECUR 100
  45. #endif
  46.  
  47. typedef struct Arg {
  48.     Stringp text;
  49.     int spaces;
  50. } Arg;
  51.  
  52. enum cmd_types {
  53.     SEND,
  54.     EXECUTE,
  55.     SUBSTITUTE,
  56.     SUBINCLUDE
  57. };
  58.  
  59. typedef struct Line {
  60.     Stringp text;
  61.     struct Line *next;
  62. } Line;
  63.  
  64. typedef struct Cmd {
  65.     Stringp text;
  66.     enum cmd_types type;
  67.     struct Cmd *next;
  68. } Cmd;
  69.  
  70. static Cmd  *FDECL(new_cmd,(enum cmd_types type));
  71. static Line *NDECL(new_line);
  72. static Cmd  *FDECL(reentrance_sub,(char *body));
  73. static Line *FDECL(newline_sub,(char *body));
  74. static void  FDECL(argsub,(char *src, Stringp dest, int argc, Arg **argv));
  75. static void  FDECL(include_subs,(Cmd *c, Stringp buffer, int argc, Arg **argv));
  76.  
  77. void FDECL(process_macro,(char *body, char *args, Stringp dest, int toplevel));
  78.  
  79. static Cmd *new_cmd(type)
  80.     enum cmd_types type;
  81. {
  82.     Cmd *c;
  83.  
  84.     c = (Cmd *) MALLOC(sizeof(Cmd));
  85.     Stringinit(c->text);
  86.     c->next = NULL;
  87.     c->type = type;
  88.     return c;
  89. }
  90.  
  91. static Line *new_line()
  92. {
  93.     Line *l;
  94.  
  95.     l = (Line *) MALLOC(sizeof(Line));
  96.     Stringinit(l->text);
  97.     l->next = NULL;
  98.     return l;
  99. }
  100.  
  101. static Cmd *reentrance_sub(body)
  102.     char *body;
  103. {
  104.     char *start, *in = body;
  105.     Cmd *header, *c;
  106.  
  107.     if (!*in) return NULL;
  108.     header = new_cmd(SEND);
  109.     c = header;
  110.     while (*in) {
  111.         if (*in == '/') {
  112.             if (*++in == '/') while (*in == '/') Stringadd(c->text, *in++);
  113.             else {
  114.                 if (c->type == EXECUTE || c->type == SUBINCLUDE)
  115.                     c->next = new_cmd(SEND);
  116.                 else c->next = new_cmd(EXECUTE);
  117.                 c = c->next;
  118.             }
  119.         } else if (*in == '$') {
  120.             if (*++in == '$') while (*in == '$') Stringadd(c->text, *in++);
  121.             else {
  122.                 if (c->type == SUBSTITUTE) c->next = new_cmd(SEND);
  123.                 else if (c->type == SUBINCLUDE) c->next = new_cmd(EXECUTE);
  124.                 else if (c->type == EXECUTE) c->next = new_cmd(SUBINCLUDE);
  125.                 else c->next = new_cmd(SUBSTITUTE);
  126.                 c = c->next;
  127.             }
  128.         } else {
  129.             for (start = in++; *in && *in != '/' && *in != '$'; in++);
  130.             Stringncat(c->text, start, in - start);
  131.         }
  132.     }
  133.     return header;
  134. }
  135.  
  136. static Line *newline_sub(body)
  137.     char *body;
  138. {
  139.     Line *header, *l;
  140.     char *start, *in = body, ch;
  141.  
  142.     if (*in == '\0') return NULL;
  143.     header = new_line();
  144.     l = header;
  145.     while (*in) {
  146.         if (*in == '%') {
  147.             ch = *(in + 1);
  148.             if (ch == '%') while (*in == '%') Stringadd(l->text, *in++);
  149.             else if (ch == '\\' || ch == ';') {
  150.                 in += 2;
  151.                 l->next = new_line();
  152.                 l = l->next;
  153.             } else Stringadd(l->text, *in++);
  154.         } else if (*in == '\\') {
  155.             if (isdigit(*(in + 1))) {
  156.                 ch = atoi(in + 1);
  157.                 Stringadd(l->text, ch);
  158.                 while (isdigit(*++in));
  159.             } else Stringadd(l->text, *in++);
  160.         } else {
  161.             for (start = in++; *in && *in != '%' && *in != '\\'; in++);
  162.             Stringncat(l->text, start, in - start);
  163.         }
  164.     }
  165.     return header;
  166. }
  167.  
  168. static void argsub(src, dest, argc, argv)
  169.     char *src;
  170.     Stringp dest;
  171.     int argc;
  172.     Arg **argv;
  173. {
  174.     char *in, *start;
  175.     int i, n;
  176.     int bracket, empty;
  177.  
  178.     Stringterm(dest, 0);
  179.     in = src;
  180.     while (*in) {
  181.         if (*in == '%') {
  182.             if (*++in == '%') {
  183.                 while (*in == '%') Stringadd(dest, *in++);
  184.                 continue;
  185.             }
  186.             bracket = empty = FALSE;
  187.             n = -1;
  188.             if (*in == '{') {
  189.                 ++in;
  190.                 bracket = TRUE;
  191.             }
  192.             if (*in == '-') {
  193.                 ++in;
  194.                 if (isdigit(*in)) {
  195.                     n = atoi(in);
  196.                     for (++in; isdigit(*in); ++in);
  197.                     if (n == 0) {
  198.                         if (argc) {
  199.                             for (i = 0; i < argc; i++) {
  200.                                 SStringcat(dest, argv[i]->text);
  201.                                 Stringnadd(dest, ' ', argv[i]->spaces);
  202.                             }
  203.                         } else empty = TRUE;
  204.                     } else {
  205.                         if (n < argc) {
  206.                             for (i = n; i < argc; i++) {
  207.                                 SStringcat(dest, argv[i]->text);
  208.                                 Stringnadd(dest, ' ', argv[i]->spaces);
  209.                             }
  210.                         } else empty = TRUE;
  211.                     }
  212.                 } else if (ucase(*in) == 'L') {
  213.                     ++in;
  214.                     if (isdigit(*in)) {
  215.                         n = argc - atoi(in);
  216.                         while (isdigit(*++in));
  217.                     } else n = argc - 1;
  218.                     if (n > 0) {
  219.                         for (i = 0; i < n; i++) {
  220.                             SStringcat(dest, argv[i]->text);
  221.                             Stringnadd(dest, ' ', argv[i]->spaces);
  222.                         }
  223.                     } else empty = TRUE;
  224.                 } else {
  225.                     ++in;
  226.                     Stringadd(dest, '%');
  227.                     continue;
  228.                 }
  229.             } else {
  230.                 if (isdigit(*in)) {
  231.                     n = atoi(in);
  232.                     for (++in; isdigit(*in); ++in);
  233.                     if (n == 0) {
  234.                         if (argc) {
  235.                             for (i = 0; i < argc; i++) {
  236.                                 SStringcat(dest, argv[i]->text);
  237.                                 Stringnadd(dest, ' ', argv[i]->spaces);
  238.                             }
  239.                         } else empty = TRUE;
  240.                     } else {
  241.                         if (--n < argc) SStringcat(dest, argv[n]->text);
  242.                         else empty = TRUE;
  243.                     }
  244. #if 0
  245.                 } else if (ucase(*in) == 'S') {
  246.                     ++in;
  247.                     if (isdigit(*in)) {
  248.                         n = atoi(in) - 1;
  249.                         while (isdigit(*++in));
  250.                     } else n = 0;
  251.                     for (subexpr = sublist; n && subexpr; n--, subexpr = subexpr->next);
  252.                     if (subexpr) Stringcat(dest, subexpr->str);
  253.                     else empty = TRUE;
  254. #endif
  255.                 } else if (ucase(*in) == 'L') {
  256.                     ++in;
  257.                     if (isdigit(*in)) {
  258.                         n = argc - atoi(in);
  259.                         while (isdigit(*++in));
  260.                     } else n = argc - 1;
  261.                     if (n >= 0) SStringcat(dest, argv[n]->text);
  262.                     else empty = TRUE;
  263.                 } else if (lcase(*in) == '*') {
  264.                     ++in;
  265.                     if (argc) {
  266.                         for (i = 0; i < argc; i++) {
  267.                             SStringcat(dest, argv[i]->text);
  268.                             Stringnadd(dest, ' ', argv[i]->spaces);
  269.                         }
  270.                     } else empty = TRUE;
  271.                 } else if (ucase(*in) == 'R') {
  272.                     ++in;
  273.                     if (argc) {
  274.                         n = RANDOM() % argc;
  275.                         SStringcat(dest, argv[n]->text);
  276.                     } empty = TRUE;
  277.                 } else if (ucase(*in) == 'E') {
  278.                     ++in;
  279.                     Stringadd(dest, '\033');
  280.                 } else if (lcase(*in) == 'n') {
  281.                     ++in;
  282.                     SStringcat(dest, lastname);
  283.                 } else {
  284.                     Stringadd(dest, '%');
  285.                     if (bracket) Stringadd(dest, '{');
  286.                     continue;
  287.                 }
  288.             }
  289.             if (bracket) {
  290.                 if (*in == '-') {
  291.                     if (empty) {
  292.                         for (start = ++in; *in && *in != '}'; in++);
  293.                         Stringncat(dest, start, in - start);
  294.                     } else while (*in && *in != '}') in++;
  295.                 }
  296.                 if (*in != '}') {
  297.                     /* syntax error: missing '}' */
  298.                 } else ++in;
  299.             } else {
  300.                 if (*in == '-') {
  301.                     oputs("% WARNING: \"%arg-default\" won't be supported in future; use \"%{arg-default}\"");
  302.                     if (empty) {
  303.                         ++in;
  304.                     } else while (*in && !isspace(*in)) in++;
  305.                 }
  306.             }
  307.         } else {
  308.             for (start = in++; *in && *in != '%'; in++);
  309.             Stringncat(dest, start, in - start);
  310.         }
  311.     }
  312. }
  313.  
  314. /* Execute sequence is always terminated by a SEND, so simply process as
  315.  * many SUBINCLUDEs and concatenate as many EXECUTEs as found onto buffer,
  316.  * which already includes the text of the first command.
  317.  */
  318. static void include_subs(c, buffer, argc, argv)
  319.     Cmd *c;
  320.     Stringp buffer;
  321.     int argc;
  322.     Arg **argv;
  323. {
  324.     Stringp temp1, temp2;
  325.     Cmd *p, *pn;
  326.  
  327.     Stringinit(temp1);
  328.     Stringinit(temp2);
  329.     p = c->next;
  330.     while (p != NULL && p->type != SEND) {
  331.         if (p->type == SUBINCLUDE) {
  332.             argsub(p->text->s, temp1, argc, argv);
  333.             get_macro_body(temp1->s, temp2);
  334.             if (mecho && temp1->len)
  335.                 oprintf("%S$%S --> %S", mprefix, temp1, temp2);
  336.             SStringcat(buffer, temp2);
  337.         } else if (p->type == EXECUTE) {
  338.             argsub(p->text->s, temp1, argc, argv);
  339.             SStringcat(buffer, temp1);
  340.         } else oputs("% Unexpected type in include_subs()");
  341.         pn = p->next;
  342.         Stringfree(p->text);
  343.         FREE(p);
  344.         p = pn;
  345.     }
  346.     Stringfree(temp1);
  347.     Stringfree(temp2);
  348.     c->next = p;
  349. }
  350.  
  351. void process_macro(body, args, dest, toplevel)
  352.     Stringp dest;
  353.     char *body, *args;
  354.     int toplevel;
  355. {
  356.     Stringp buffer, sublevel;
  357.     Line *l, *ln;
  358.     Cmd *c, *cn;
  359.     char *in;
  360.     int argc = 0, vecsize = 20;
  361.     Arg **argv;
  362.  
  363.     if (++recur_count > MAX_RECUR) {
  364.         oputs("% Too many recursions.");
  365.         recur_count--;
  366.         return;
  367.     }
  368.     argv = (Arg **) MALLOC(vecsize * sizeof(Arg *));
  369.     for (in = args; isspace(*in); in++);
  370.     while (*in) {
  371.         if (argc == vecsize)
  372.             argv = (Arg**)REALLOC((char*)argv, sizeof(Arg*) * (vecsize += 10));
  373.         argv[argc] = (Arg *) MALLOC(sizeof(Arg));
  374.         Stringinit(argv[argc]->text);
  375.         in = getword(argv[argc]->text, in);
  376.         for (argv[argc]->spaces = 0; isspace(*in); in++) argv[argc]->spaces++;
  377.         argc++;
  378.     }
  379.  
  380.     Stringinit(buffer);
  381.     Stringinit(sublevel);
  382.     l = newline_sub(body);
  383.     while (l != NULL) {
  384.         c = reentrance_sub(l->text->s);
  385.         Stringfree(l->text);
  386.         while (c != NULL) {
  387.             if (c->text->len) {
  388.                 argsub(c->text->s, buffer, argc, argv);
  389.                 if (c->type == SEND) SStringcat(dest, buffer);
  390.                 else {
  391.                     Stringterm(sublevel, 0);
  392.                     if (c->type == EXECUTE) {
  393.                         include_subs(c, buffer, argc, argv);
  394.                         if (mecho && buffer->len)
  395.                             oprintf("%S/%S", mprefix, buffer);
  396.                         handle_command(buffer->s, sublevel);
  397.                     }
  398.                     if (c->type == SUBSTITUTE) {
  399.                         get_macro_body(buffer->s, sublevel);
  400.                         if (mecho && buffer->len)
  401.                             oprintf("%S$%S --> %S", mprefix, buffer,
  402.                              sublevel);
  403.                     }
  404.                     SStringcat(dest, sublevel);
  405.                 }
  406.             }
  407.             Stringfree(c->text);
  408.             cn = c->next;
  409.             FREE(c);
  410.             c = cn;
  411.         }
  412.         ln = l->next;
  413.         FREE(l);
  414.         l = ln;
  415.         if (l != NULL || toplevel) {
  416.             newline_package(dest, 1);
  417.             if (dest->len > 1) {
  418.                 newline_package(dest, 0);
  419.                 if (mecho) oprintf("%S%S", mprefix, dest);
  420.                 newline_package(dest, 1);
  421.                 transmit(dest->s, dest->len);
  422.             }
  423.             Stringterm(dest, 0);
  424.         }
  425.     }
  426.     while (--argc >= 0) {
  427.         Stringfree(argv[argc]->text);
  428.         FREE(argv[argc]);
  429.     }
  430.     FREE(argv);
  431.     Stringfree(sublevel);
  432.     Stringfree(buffer);
  433.     recur_count--;
  434. }
  435.