home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games (Alt) / INFESPGAMES.iso / os2 / backgam / source / process.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-10  |  11.7 KB  |  438 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 processes.                              *
  17.  *                                               *
  18.  * Rewritten by Ken Keys, orginally written by   *
  19.  * Leo Plotkin and modified by Greg Hudson.      *
  20.  * Handles /repeat and /quote processes.         *
  21.  *************************************************/
  22.  
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <sys/types.h>
  26. #include "tf.h"
  27. #include "dstring.h"
  28. #include "util.h"
  29. #include "history.h"
  30. #include "world.h"
  31. #include "socket.h"
  32. #include "macro.h"
  33. #include "expand.h"
  34. #include "output.h"
  35.  
  36. #define P_REPEAT     001
  37. #define P_QFILE      002
  38. #define P_QCOMMAND   004
  39. #define P_QRECALL    010
  40. #define P_QLOCAL     020
  41.  
  42. typedef union ProcIn {
  43.     FILE *fp;       /* I/O for shell command or file */
  44.     struct Queue *queue;   /* local command output */
  45. } ProcIn;
  46.     
  47. typedef struct Proc {
  48.     int pid;
  49.     int type;
  50.     int count;
  51.     int PDECL((*funct),(struct Proc *proc));
  52.     int ptime;
  53.     TIME_T timer;       /* time of next execution */
  54.     char *pre;          /* what to prefix */
  55.     char *suf;          /* what to suffix */
  56.     ProcIn in;          /* source of quote input */
  57.     struct World *world;/* where to send output */
  58.     char *cmd;          /* command or file name */
  59.     struct Proc *next, *prev;
  60. } Proc;
  61.  
  62. static void FDECL(newproc,(int type, int FDECL((*funct),(Proc *proc)),
  63.                            int count, char *pre, char *suf, ProcIn in,
  64.                            struct World *world, char *cmd, int ptime));
  65. static void FDECL(removeproc,(Proc *proc));
  66. static void FDECL(freeproc,(Proc *proc));
  67. static int  FDECL(runproc,(Proc *proc));
  68. static int  FDECL(do_repeat,(Proc *proc));
  69. static int  FDECL(do_quote,(Proc *proc));
  70.  
  71. void   NDECL(do_ps);
  72. void   FDECL(do_kill,(int pid));
  73. void   FDECL(kill_procs_by_world,(struct World *world));
  74. void   NDECL(kill_procs);
  75. void   FDECL(runall,(TIME_T now));
  76. void   FDECL(start_quote,(char *args));
  77. void   FDECL(start_repeat,(char *args));
  78.  
  79. TIME_T process_time = 1;          /* default process delay */
  80. TIME_T proctime = 0;              /* when next process should be run */
  81.  
  82. extern int lpquote;
  83.  
  84. static Proc *proclist = NULL;     /* procedures to execute */
  85.  
  86. void do_ps()
  87. {
  88.     Proc *p;
  89.     char c;
  90.     char buf[11];
  91.  
  92.     oprintf("  PID TYPE    WORLD      PTIME COUNT COMMAND");
  93.     for (p = proclist; p; p = p->next) {
  94.         if (p->world) sprintf(buf, "-w%-8s", p->world->name);
  95.         else sprintf(buf, "%10s", "");
  96.         if (p->type == P_REPEAT) {
  97.             oprintf("%5d /repeat %s -%-4d %5d %s", p->pid, buf,
  98.             (p->ptime == -1) ? process_time : p->ptime, p->count, p->cmd);
  99.         } else {
  100.             if (p->type == P_QFILE) c = '\'';
  101.             else if (p->type == P_QCOMMAND) c = '!';
  102.             else if (p->type == P_QRECALL) c = '#';
  103.             else /* (p->type == P_QLOCAL) */ c = '`';
  104.             oprintf("%5d /quote  %s -%-4d       %s%c\"%s\"%s", p->pid,
  105.                 buf, (p->ptime == -1) ? process_time : p->ptime, p->pre, c,
  106.                 p->cmd, p->suf);
  107.         }
  108.     }
  109. }
  110.  
  111. static void newproc(type, funct, count, pre, suf, in, world, cmd, ptime)
  112.     int type, count, ptime;
  113.     int FDECL((*funct),(Proc *proc));
  114.     char *pre, *suf, *cmd;
  115.     ProcIn in;
  116.     struct World *world;
  117. {
  118.     Proc *proc;
  119.     static int pid = 0;
  120.  
  121.     proc = (Proc *) MALLOC(sizeof(Proc));
  122.  
  123.     proc->count = count;
  124.     proc->funct = funct;
  125.     proc->ptime = ptime;
  126.     proc->type = type;
  127.     proc->timer = (TIME_T)time(NULL) + ((ptime == -1) ? process_time : ptime);
  128.     proc->pre = STRDUP(pre);
  129.     proc->suf = STRDUP(suf);
  130.     proc->cmd = STRDUP(cmd);
  131.     proc->pid = ++pid;
  132.     proc->in = in;
  133.     proc->world = world;
  134.  
  135.     if (proclist) proclist->prev = proc;
  136.     proc->next = proclist;
  137.     proc->prev = NULL;
  138.     proclist = proc;
  139.     if (proctime == 0 || proc->timer < proctime) proctime = proc->timer;
  140.     do_hook(H_PROCESS, "%% Starting process %d", "%d", proc->pid);
  141. }
  142.  
  143. static void freeproc(proc)
  144.     Proc *proc;
  145. {
  146.     do_hook(H_KILL, "%% Killing process %d", "%d", proc->pid);
  147.     if (proc->type == P_QCOMMAND) {
  148.         readers_clear(fileno(proc->in.fp));
  149.         pclose(proc->in.fp);
  150.     } else if (proc->type == P_QFILE) {
  151.         fclose(proc->in.fp);
  152.     } else if (proc->type == P_QLOCAL || proc->type == P_QRECALL) {
  153.         free_queue(proc->in.queue);
  154.         FREE(proc->in.queue);
  155.     }
  156.     FREE(proc->pre);
  157.     FREE(proc->suf);
  158.     FREE(proc->cmd);
  159.     FREE(proc);
  160. }
  161.  
  162. static void removeproc(proc)
  163.     Proc *proc;
  164. {
  165.     if (proc->next) proc->next->prev = proc->prev;
  166.     if (proc->prev) proc->prev->next = proc->next;
  167.     else proclist = proc->next;
  168. }
  169.  
  170. void kill_procs()
  171. {
  172.     Proc *next;
  173.  
  174.     for (; proclist; proclist = next) {
  175.         next = proclist->next;
  176.         freeproc(proclist);
  177.     }
  178.     proctime = 0;
  179. }
  180.  
  181. void kill_procs_by_world(world)
  182.     struct World *world;
  183. {
  184.     Proc *proc, *next;
  185.  
  186.     if (!proclist) return;
  187.     for (proc = proclist; proc; proc = next) {
  188.         next = proc->next;
  189.         if (proc->world == world) {
  190.             removeproc(proc);
  191.             freeproc(proc);
  192.         }
  193.     }
  194. }
  195.  
  196. void do_kill(pid)
  197.     int pid;
  198. {
  199.     Proc *proc;
  200.  
  201.     for (proc = proclist; proc && (proc->pid != pid); proc = proc->next);
  202.     if (proc) {
  203.         removeproc(proc);
  204.         freeproc(proc);
  205.     } else oputs("% no such process");
  206. }
  207.  
  208. void runall(now)
  209.     TIME_T now;
  210. {
  211.     Proc *t, *n;
  212.     TIME_T earliest = 0;
  213.  
  214.     proctime = 0;
  215.     for (t = proclist; t; t = n) {
  216.         n = t->next;
  217.         if (t->type == P_QCOMMAND && is_active(fileno(t->in.fp))) {
  218.             readers_clear(fileno(t->in.fp));
  219.             if (!runproc(t)) t = NULL;
  220.         } else if ((t->type != P_QCOMMAND) && (lpquote || (t->timer <= now))) {
  221.             if (!runproc(t)) t = NULL;
  222.         }
  223.  
  224.         if (t && (t->type == P_QCOMMAND) && (t->timer <= now))
  225.             readers_set(fileno(t->in.fp));
  226.         if (t && (!earliest || (t->timer < earliest)))
  227.             earliest = t->timer;
  228.     }
  229.     /* calculate next proc (proctime may have been set by a nested process) */
  230.     proctime = (proctime && proctime < earliest) ? proctime : earliest;
  231. }
  232.  
  233. static int runproc(p)
  234.     Proc *p;
  235. {
  236.     int notdone;
  237.     extern struct Sock *fsock, *xsock;
  238.  
  239.     if (p->world) xsock = p->world->socket;
  240.     notdone = (*p->funct)(p);
  241.     xsock = fsock;
  242.     if (notdone) {
  243.         return p->timer =
  244.             (TIME_T)time(NULL) + ((p->ptime == -1) ? process_time : p->ptime);
  245.     }
  246.     removeproc(p);
  247.     freeproc(p);
  248.     return 0;
  249. }
  250.  
  251. static int do_repeat(proc)
  252.     Proc *proc;
  253. {
  254.     Stringp dest;
  255.  
  256.     if (proc->count--) {
  257.         Stringinit(dest);
  258.         process_macro(proc->cmd, "", dest, TRUE);
  259.         Stringfree(dest);
  260.     }
  261.     return proc->count;
  262. }
  263.  
  264. static int do_quote(proc)
  265.     Proc *proc;
  266. {
  267.     static Stringp line, buffer;
  268.     static int strings_inited = FALSE;
  269.     Aline *aline;
  270.     extern Stringp qprefix;
  271.     extern int qecho;
  272.  
  273.     if (!strings_inited) {
  274.         Stringinit(line);
  275.         Stringinit(buffer);
  276.         strings_inited = TRUE;
  277.     }
  278.     if (proc->type == P_QLOCAL || proc->type == P_QRECALL) {
  279.         if ((aline = dequeue(proc->in.queue)) == NULL) return FALSE;
  280.         Sprintf(buffer, "%s%s%s", proc->pre, aline->str, proc->suf);
  281.     } else {
  282.         if (fgetS(line, proc->in.fp) == NULL) return FALSE;
  283.         newline_package(line, 0);
  284.         Sprintf(buffer, "%s%S%s", proc->pre, line, proc->suf);
  285.     }
  286.  
  287.     if (qecho) oprintf("%S%S", qprefix, buffer);
  288.     check_command(FALSE, buffer);
  289.     return TRUE;
  290. }
  291.  
  292. static void ecpy(dest, src)
  293.     Stringp dest;
  294.     char *src;
  295. {
  296.     char *start;
  297.  
  298.     Stringterm(dest, 0);
  299.     while (*src) {
  300.         if (*src == '\\' && *(src + 1)) src++;
  301.         for (start = src++; *src && *src != '\\'; src++);
  302.         Stringncat(dest, start, src - start);
  303.     }
  304. }
  305.  
  306. static int procopt(argp, ptime, world)
  307.     char **argp;
  308.     int *ptime;
  309.     struct World **world;
  310. {
  311.     char opt, *ptr;
  312.  
  313.     *world = NULL;
  314.     *ptime = -1;
  315.     startopt(*argp, "0w:");
  316.     while (opt = nextopt(&ptr, ptime)) {
  317.         switch(opt) {
  318.         case 'w':
  319.             if (!*ptr) *world = xworld();
  320.             else if ((*world = find_world(ptr)) == NULL) {
  321.                 oprintf("%% No world %s", ptr);
  322.                 return FALSE;
  323.             }
  324.             break;
  325.         case '0': break;
  326.         default:  return FALSE;
  327.         }
  328.     }
  329.     *argp = ptr;
  330.     return TRUE;
  331. }
  332.  
  333. void start_quote(args)
  334.     char *args;
  335. {
  336.     char *p, *command, *suffix;
  337.     int type;
  338.     Stringp expanded;
  339.     static Stringp pre, suf, cmd;
  340.     static int strings_initted = FALSE;
  341.     ProcIn in;
  342.     extern struct Queue *output_dest;
  343.     struct Queue *oldqueue;
  344.     int ptime;
  345.     struct World *world;
  346.  
  347.     if (!strings_initted) {
  348.         Stringinit(pre);
  349.         Stringinit(suf);
  350.         Stringinit(cmd);
  351.         strings_initted = TRUE;
  352.     }
  353.     if (!procopt(&args, &ptime, &world)) return;
  354.  
  355.     p = args;
  356.     while (*p && *p != '\'' && *p != '!' && *p != '#' && *p != '`') {
  357.         if (*p == '\\' && *(p + 1)) p += 2;
  358.         else p++;
  359.     }
  360.     if (*p == '\'') type = P_QFILE;
  361.     else if (*p == '!') type = P_QCOMMAND;
  362.     else if (*p == '#') type = P_QRECALL;
  363.     else if (*p == '`') type = P_QLOCAL;
  364.     else {
  365.         oputs("% Bad /quote syntax");
  366.         return;
  367.     }
  368.     *p = '\0';
  369.     if (*++p == '"') {
  370.         command = ++p;
  371.         if ((p = estrchr(p, '"', '\\')) == NULL) suffix = "";
  372.         else {
  373.             *p = '\0';
  374.             suffix = p + 1;
  375.         }
  376.     } else {
  377.         command = p;
  378.         suffix = "";
  379.     }
  380.     ecpy(pre, args);
  381.     ecpy(suf, suffix);
  382.     ecpy(cmd, command);
  383.     switch (type) {
  384.     case P_QFILE:
  385.         Stringexpand(cmd);
  386.         if ((in.fp = fopen(cmd->s, "r")) == NULL) {
  387.             operror(cmd->s);
  388.             return;
  389.         }
  390.         break;
  391.     case P_QCOMMAND:
  392.         Stringcat(cmd, " 2>&1");                     /* capture stderr, too */
  393.         if ((in.fp = popen(cmd->s, "r")) == NULL) {
  394.             operror(cmd->s);
  395.             return;
  396.         }
  397.         Stringterm(cmd, cmd->len - 5);               /* remove " 2>&1" */
  398.         break;
  399.     case P_QRECALL:
  400.         init_queue(in.queue = (struct Queue *)MALLOC(sizeof(struct Queue)));
  401.         if (!recall_history(cmd->s, in.queue)) {
  402.             FREE(in.queue);
  403.             return;
  404.         }
  405.         break;
  406.     case P_QLOCAL:
  407.         init_queue(in.queue = (struct Queue *)MALLOC(sizeof(struct Queue)));
  408.         oldqueue = output_dest;
  409.         output_dest = in.queue;
  410.         Stringinit(expanded);
  411.         process_macro(cmd->s, "", expanded, TRUE);
  412.         Stringfree(expanded);
  413.         output_dest = oldqueue;
  414.         break;
  415.     default:    /* impossible */
  416.         break;
  417.     }
  418.     newproc(type, do_quote, -1, pre->s, suf->s, in, world, cmd->s, ptime);
  419.     if (lpquote) runall(time(NULL));
  420. }
  421.  
  422. void start_repeat(args)
  423.     char *args;
  424. {
  425.     int ptime, count;
  426.     struct World *world;
  427.     ProcIn in;
  428.  
  429.     if (!procopt(&args, &ptime, &world)) return;
  430.     count = numarg(&args);
  431.     if (!args || !*args || (count <= 0)) {
  432.         oputs("% Bad /repeat syntax.");
  433.         return;
  434.     }
  435.     newproc(P_REPEAT, do_repeat, count, "", "", in, world, args, ptime);
  436.     if (lpquote) runall(time(NULL));
  437. }
  438.