home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games (Alt) / INFESPGAMES.iso / os2 / backgam / source / history.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-20  |  12.7 KB  |  471 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 history and logging                                    *
  17.  *                                                              *
  18.  * Maintains the circular lists for input and output histories. *
  19.  * Handles text queuing and file I/O for logs.                  *
  20.  ****************************************************************/
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include "tf.h"
  25. #include "dstring.h"
  26. #include "util.h"
  27. #include "history.h"
  28. #include "world.h"
  29. #include "socket.h"
  30. #include "macro.h"
  31. #include "output.h"
  32.  
  33. #define torange(x, r) (((x) >= 0) ? ((x)%(r)) : ((x)%(r) + (r)))
  34. #define empty(q) (!(q)->alines || !(q)->size)
  35.  
  36. static void   FDECL(init_history,(History *q, int maxsize));
  37. static void   FDECL(saveline,(History *q, Aline *aline));
  38. static void   FDECL(display_history,(History *q, int start, int end,
  39.               int numbers, char *pattern, Queue *buf, int attrs));
  40. static int    FDECL(check_watchname,(History *q));
  41. static int    FDECL(check_watchdog,(History *q, char *str));
  42.  
  43. void   NDECL(init_histories);
  44. void   FDECL(free_history,(History *q));
  45. int    FDECL(history_full,(History *q));
  46. void   FDECL(record_world,(History *q, Aline *aline));
  47. void   FDECL(record_local,(Aline *aline));
  48. void   FDECL(record_input,(char *str));
  49. int    FDECL(recall_history,(char *args, Queue *buf));
  50. void   FDECL(recall_input,(Stringp str, int dir));
  51. int    FDECL(is_suppressed,(History *q, char *str));
  52. void   FDECL(history_sub,(char *pattern));
  53. void   FDECL(do_log,(char *args));
  54.  
  55. static History input[1], global[1], local[1];
  56.  
  57. extern int log_on, gag;
  58.  
  59. Stringp lastname;
  60.  
  61. static void init_history(q, maxsize)
  62.     History *q;
  63.     int maxsize;
  64. {
  65.     q->alines = (Aline **) MALLOC(maxsize * sizeof(Aline *));
  66.     q->maxsize = maxsize;
  67.     q->pos = q->index = -1;
  68.     q->size = q->num = 0;
  69.     q->logfile = NULL;
  70. }
  71.  
  72. void init_histories()
  73. {
  74.     init_history(input, SAVEINPUT);
  75.     init_history(global, SAVEGLOBAL);
  76.     init_history(local, SAVELOCAL);
  77.     Stringinit(lastname);
  78. }
  79.  
  80. #ifdef DMALLOC
  81. void free_histories()
  82. {
  83.     free_history(input);
  84.     free_history(global);
  85.     free_history(local);
  86.     Stringfree(lastname);
  87. }
  88. #endif
  89.  
  90. void free_history(q)
  91.     History *q;
  92. {
  93.     int i;
  94.  
  95.     if (q->alines) {
  96.         for (i = 0; i < q->size; i++) free_aline(q->alines[i]);
  97.         FREE(q->alines);
  98.         if (q->logfile) {
  99.             tfclose(q->logfile);
  100.             if (!--log_on) put_logging(FALSE);
  101.         }
  102.     }
  103. }
  104.  
  105. static void saveline(q, aline)
  106.     History *q;
  107.     Aline *aline;
  108. {
  109.     if (!(aline->attrs & F_NORECORD)) {
  110.         if (!q->alines) init_history(q, SAVEWORLD);
  111.         q->pos = torange(q->pos + 1, q->maxsize);
  112.         if (q->size < q->maxsize) q->size++;
  113.         else free_aline(q->alines[q->pos]);
  114.         (q->alines[q->pos] = aline)->links++;
  115.         q->num++;
  116.     }
  117.     if (q->logfile) {
  118.         tfputs(aline->str, q->logfile);
  119.         tfputc('\n', q->logfile);
  120.         tfflush(q->logfile);
  121.     }
  122. }
  123.  
  124. int history_full(q)
  125.     History *q;
  126. {
  127.     return (q->alines && q->pos == torange(q->index - 1, q->size));
  128. }
  129.  
  130. void record_local(aline)
  131.     Aline *aline;
  132. {
  133.     saveline(local, aline);
  134.     saveline(global, aline);
  135. }
  136.  
  137. void record_world(q, aline)
  138.     History *q;
  139.     Aline *aline;
  140. {
  141.     if (q) saveline(q, aline);
  142.     saveline(global, aline);
  143. }
  144.  
  145. void record_input(str)
  146.     char *str;
  147. {
  148.     saveline(input, new_aline(str, F_NEWLINE));
  149.     input->index = input->pos;
  150. }
  151.  
  152. void recall_input(s, dir)
  153.     Stringp s;
  154.     int dir;
  155. {
  156.     if (empty(input)) return;
  157.     Stringcpy(s, input->alines[torange(input->index + 1 + dir, input->size)]->str);
  158.     if (input->size > 1) input->index = torange(input->index + dir, input->size);
  159. }
  160.  
  161. int recall_history(args, buf)
  162.     char *args;
  163.     Queue *buf;
  164. {
  165.     int num, start, end, numbers = FALSE;
  166.     short attrs = 0;
  167.     char opt, *arg, *place, *pattern;
  168.     World *world = xworld();
  169.     History *q = NULL;
  170.     static Aline *startmsg = NULL, *endmsg = NULL;
  171.  
  172.     if (!startmsg) {
  173.         startmsg = new_aline("---- Recall start ----", F_NEWLINE | F_NORECORD);
  174.         endmsg = new_aline("----- Recall end -----", F_NEWLINE | F_NORECORD);
  175.         startmsg->links = endmsg->links = 1;
  176.     }
  177.     startopt(args, "a:f:w:lgi");
  178.     while(opt = nextopt(&arg, &num)) {
  179.         switch (opt) {
  180.         case 'w':
  181.             if (!*arg || (world = find_world(arg)) == NULL) {
  182.                 oprintf("%% No world %s", arg);
  183.                 return 0;
  184.             }
  185.             q = world->history;
  186.             break;
  187.         case 'l':
  188.             q = local;
  189.             break;
  190.         case 'g':
  191.             q = global;
  192.             break;
  193.         case 'i':
  194.             q = input;
  195.             break;
  196.         case 'a': case 'f':
  197.             if ((num = parse_attrs(arg)) == -1) return 0;
  198.             attrs |= num;
  199.             break;
  200.         default: return 0;
  201.         }
  202.     }
  203.     if (!q) q = world ? world->history : global;
  204.     if (empty(q)) return 0;
  205.     if (arg && (pattern = strchr(arg, ' ')) != NULL) {
  206.         *pattern++ = '\0';
  207.         if (!smatch_check(pattern)) return 0;
  208.     } else pattern = NULL;
  209.     if (arg && *arg == '#') {
  210.         numbers = TRUE;
  211.         arg++;
  212.     }
  213.     if (!arg || !*arg) {
  214.         start = end = q->pos;
  215.     } else if (*arg == '-') {
  216.         start = atoi(++arg);
  217.         if (start > q->size) start = q->size;
  218.         if (start < 1) start = 1;
  219.         start = end = torange(q->pos - start + 1, q->size);
  220.     } else if (!isdigit(*arg)) {
  221.         oputs("% Bad recall syntax.");
  222.         return 0;
  223.     } else {
  224.         if ((start = atoi(arg)) < 1) start = 1;
  225.         if ((place = strchr(arg, '-')) == NULL) {
  226.             if (start > q->size) start = q->size;
  227.             end = q->pos;
  228.             start = torange(q->pos - start + 1, q->size);
  229.         } else {
  230.             if (start > q->num) start = q->num;
  231.             end = isdigit(place[1]) ? atoi(place + 1) : start;
  232.             if (end < start) end = start;
  233.             else if (end > q->num) end = q->num;
  234.             end = torange(end - 1, q->size);
  235.             start = torange(start - 1, q->size);
  236.         }
  237.     }
  238.     if (buf == NULL) aoutput(startmsg);
  239.     display_history(q, start, end, numbers, pattern, buf, ~attrs);
  240.     if (buf == NULL) aoutput(endmsg);
  241.     return 1;
  242. }
  243.  
  244. static void display_history(q, start, end, numbers, pattern, buf, attrs)
  245.     History *q;
  246.     Queue *buf;
  247.     int start, end, numbers;
  248.     char *pattern;
  249.     int attrs;
  250. {
  251.     int i, done = FALSE;
  252.     char *str;
  253.     Aline *aline;
  254.     STATIC_BUFFER(buffer)
  255.  
  256.     attrs |= F_NORM;
  257.     for (i = start; !done; i = torange(i + 1, q->size)) {
  258.         if (i == end) done = TRUE;
  259.         if (gag && (q->alines[i]->attrs & F_GAG & attrs)) continue;
  260.         if (pattern && !equalstr(pattern, q->alines[i]->str)) continue;
  261.         if (numbers) {
  262.             Sprintf(buffer, "%d: %s", q->num - torange(q->pos - i, q->size),
  263.                 q->alines[i]->str);
  264.             str = buffer->s;
  265.         } else str = q->alines[i]->str;
  266.  
  267.         if (numbers || q->alines[i]->attrs & ~attrs & F_ALL) {
  268.             aline = new_aline(str, (q->alines[i]->attrs & attrs) | F_NEWLINE);
  269.         } else aline = q->alines[i];            /* share aline if possible */
  270.         if (buf) {
  271.             enqueue(buf, aline);
  272.         } else {
  273.             aline->attrs |= F_NORECORD;           /* don't record /recalls */
  274.             aoutput(aline);
  275.         }
  276.     }
  277. }
  278.  
  279. static int check_watchname(q)
  280.     History *q;
  281. {
  282.     extern int wnmatch, wnlines, gpri;
  283.     int pos = q->pos, size = q->size;
  284.     int nmatches = 0, i, slines, nlen = lastname->len;
  285.     char *name = lastname->s;
  286.  
  287.     if (wnlines > q->size) slines = q->size;
  288.     else slines = wnlines;
  289.     for (i = 0; i < slines; i++) {
  290.         if (!strncmp(q->alines[torange(pos - i, size)]->str, name, nlen))
  291.             if (++nmatches == wnmatch) break;
  292.     }
  293.     if (nmatches < wnmatch) return 0;
  294.     oprintf("%% Watchname: gagging \"%S*\"", lastname);
  295.     Stringcat(lastname, " *");
  296.     add_macro(new_macro("",lastname->s,"",0,"","",NULL,gpri,100,F_GAG,0,0));
  297.     Stringterm(lastname, nlen);
  298.     return 1;
  299. }
  300.  
  301. static int check_watchdog(q, str)
  302.     History *q;
  303.     char *str;
  304. {
  305.     extern int wdmatch, wdlines;
  306.     int pos = q->pos, size = q->size;
  307.     int nmatches = 0, i, slines;
  308.  
  309.     if (wdlines > q->size) slines = q->size;
  310.     else slines = wdlines;
  311.     for (i = 0; i < slines; i++) {
  312.         if (!cstrcmp(q->alines[torange(pos - i, size)]->str, str))
  313.             if (nmatches++ == wdmatch) return 1;
  314.     }
  315.     return 0;
  316. }
  317.  
  318. int is_suppressed(q, str)
  319.     History *q;
  320.     char *str;
  321. {
  322.     extern int wn_enabled, wd_enabled;
  323.  
  324.     if (empty(q)) return 0;
  325.     return ((wn_enabled && check_watchname(q)) ||
  326.             (wd_enabled && check_watchdog(q, str)));
  327. }
  328.  
  329. void history_sub(pattern)
  330.     char *pattern;
  331. {
  332.     int size = input->size, pos = input->pos, i;
  333.     Aline **l = input->alines;
  334.     char *replace, *loc = NULL;
  335.     STATIC_BUFFER(buffer)
  336.  
  337.     if (empty(input) || !*pattern) return;
  338.     if ((replace = strchr(pattern, '^')) == NULL) return;
  339.     else *replace++ = '\0';
  340.     for (i = 0; i < size; i++)
  341.         if ((loc = STRSTR(l[torange(pos - i, size)]->str, pattern)) != NULL)
  342.             break;
  343.     if (i == size) return;
  344.     i = torange(pos - i, size);
  345.     Stringncpy(buffer, l[i]->str, loc - l[i]->str);
  346.     Stringcat(buffer, replace);
  347.     Stringcat(buffer, loc + (replace - pattern - 1));
  348.     record_input(buffer->s);
  349.     check_command(FALSE, buffer);
  350. }
  351.  
  352. void init_queue(q)
  353.     Queue *q;
  354. {
  355.     q->head = q->tail = NULL;
  356. }
  357.  
  358. void enqueue(q, aline)
  359.     Queue *q;
  360.     Aline *aline;
  361. {
  362.     Textnode *node;
  363.  
  364.     node = (Textnode *)MALLOC(sizeof(Textnode));
  365.     (node->aline = aline)->links++;
  366.     node->next = NULL;
  367.     if (!q->head) q->head = node;
  368.     else q->tail->next = node;
  369.     q->tail = node;
  370. }
  371.  
  372. Aline *dequeue(q)
  373.     Queue *q;
  374. {
  375.     Textnode *node;
  376.     Aline *result;
  377.  
  378.     if (!q->head) return NULL;
  379.     result = (node = q->head)->aline;
  380.     if (!(q->head = q->head->next)) q->tail = NULL;
  381.     FREE(node);
  382.     return result;
  383. }
  384.  
  385. void free_queue(q)
  386.     Queue *q;
  387. {
  388.     Textnode *node;
  389.  
  390.     while (node = q->head) {
  391.         q->head = q->head->next;
  392.         free_aline(node->aline);
  393.         FREE(node);
  394.     }
  395.     q->tail = NULL;
  396. }
  397.  
  398. void listlog(world)
  399.     World *world;
  400. {
  401.     if (world->history->logfile)
  402.         oprintf("%% Logging world %s output to %s",
  403.           world->name, world->history->logfile->name);
  404. }
  405.  
  406. void do_log(args)
  407.     char *args;
  408. {
  409.     char c;
  410.     World *world;
  411.     History *history = global;
  412.     TFILE *logfile;
  413.  
  414.     startopt(args, "ligw:");
  415.     while (c = nextopt(&args, NULL))
  416.         switch (c) {
  417.         case 'l':
  418.             history = local;
  419.             break;
  420.         case 'i':
  421.             history = input;
  422.             break;
  423.         case 'g':
  424.             history = global;
  425.             break;
  426.         case 'w':
  427.             if (!*args) world = xworld();
  428.             else world = find_world(args);
  429.             if (!world) {
  430.                 oprintf("%% No world %s", args);
  431.                 history = NULL;
  432.             } else history = world->history;
  433.             break;
  434.         }
  435.     if (!history) return;
  436.     if (!*args) {
  437.         if (log_on) {
  438.             if (input->logfile)
  439.                 oprintf("%% Logging input to %s", input->logfile->name);
  440.             if (local->logfile)
  441.                 oprintf("%% Logging local output to %s", local->logfile->name);
  442.             if (global->logfile)
  443.                 oprintf("%% Logging global output to %s", global->logfile->name);
  444.             mapsock(listlog);
  445.         } else {
  446.             oputs("% Logging disabled.");
  447.         }
  448.         return;
  449.     } else if (cstrcmp(args, "OFF") == 0) {
  450.         if (history->logfile) {
  451.             tfclose(history->logfile);
  452.             history->logfile = NULL;
  453.             if (!--log_on) put_logging(FALSE);
  454.         }
  455.         return;
  456.     } else if (cstrcmp(args, "ON") == 0) {
  457.         logfile = tfopen(NULL, "LOGFILE", "a");
  458.     } else {
  459.         logfile = tfopen(args, NULL, "a");
  460.     }
  461.     if (!logfile) return;
  462.     if (history->logfile) {
  463.         tfclose(history->logfile);
  464.         log_on--;
  465.     }
  466.     oprintf("%% Logging to file %s", logfile->name);
  467.     history->logfile = logfile;
  468.     if (!log_on++) put_logging(TRUE);
  469. }
  470.  
  471.