home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / CKPM5X_S.ZIP / CKUUS5.C < prev    next >
C/C++ Source or Header  |  1990-03-03  |  29KB  |  962 lines

  1. /* File ckuus5.c - Spillover, created to even out sizes of ckuus*.c modules */
  2.  
  3. /* Includes */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include "ckcdeb.h"
  8. #include "ckcasc.h"
  9. #include "ckcker.h"
  10. #include "ckucmd.h"
  11. #include "ckuusr.h"
  12.  
  13. /* External variables */
  14.  
  15. extern int size, rpsiz, urpsiz, speed, local, backgrd, tvtflg,
  16.   server, displa, binary, parity, deblog, escape, xargc, flow,
  17.   turn, duplex, nfils, ckxech, pktlog, seslog, tralog, stdouf, stdinf,
  18.   turnch, dfloc, keep, maxrps, warn, quiet, cnflg, tlevel,
  19.   mdmtyp, zincnt, cmask, rcflag, success;
  20. extern char *DIRCMD, *PWDCMD, *DELCMD, cmerrp[];
  21. extern char *zhome(), *malloc();
  22. extern char *versio, *ckxsys, *dftty, *cmarg, *homdir, *lp;
  23. extern char debfil[], pktfil[], sesfil[], trafil[], cmdbuf[], cmdstr[];
  24. extern char cmdbuf[], atmbuf[], savbuf[], toktab[];
  25. extern CHAR sstate, ttname[], filnam[];
  26. extern struct mtab mactab[];
  27. extern struct keytab cmdtab[];
  28. extern int cmdlvl, maclvl, tlevel, rmailf, rprintf;
  29. extern int nmac, mecho, merror, techo, terror, repars, ncmd;
  30. extern int xxstring();
  31. #ifdef OS2
  32. extern char far * zfindfile(char far *);
  33. #endif
  34.  
  35. /* Variables declared here for use by other ckuus*.c modules */
  36. /* Space is allocated here to save room in ckuusr.c */
  37.  
  38. FILE *tfile[MAXTAKE];
  39. struct cmdptr cmdstk[CMDSTKL];
  40. int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL];
  41. char *m_arg[MACLEVEL][NARGS];
  42. char *g_var[GVARS], *macp[MACLEVEL];
  43. int macargc[MACLEVEL];
  44. int macx[MACLEVEL];
  45.  
  46. char line[LINBUFSIZ];            /* Character buffer for anything */
  47. char inpbuf[INPBUFSIZ];            /* Buffer for INPUT and REINPUT */
  48. char vnambuf[VNAML];            /* Buffer for variable names */
  49. char lblbuf[50];            /* Buffer for labels */
  50. char debfil[50];            /* Debugging log file name */
  51. char pktfil[50];            /* Packet log file name */
  52. char sesfil[50];            /* Session log file name */
  53. char trafil[50];            /* Transaction log file name */
  54. char tmpbuf[50];            /* Temporary buffer */
  55. char optbuf[50];            /* Options for MAIL or REMOTE PRINT */
  56. char kermrc[100];            /* Name of initialization file */
  57. char cmdstr[256];            /* Place to build generic command */
  58.  
  59. /*  T R A P  --  Terminal interrupt handler */
  60.  
  61. trap(sig,code) int sig, code; {
  62.     printf("^C...\n");
  63.     debug(F101,"trap() caught signal","",sig);
  64.     debug(F101," code","",code);
  65.     doexit(GOOD_EXIT);            /* Exit indicating success */
  66. }
  67.  
  68. /*  S T P T R A P -- Handle SIGTSTP signals */
  69.  
  70. #ifdef RTU
  71.     extern int rtu_bug;
  72. #endif
  73.  
  74. stptrap(sig,code) int sig, code; {
  75.     debug(F101,"stptrap() caught signal","",sig);
  76.     debug(F101," code","",code);
  77.     conres();                /* Reset the console */
  78. #ifdef SIGTSTP
  79. #ifdef RTU
  80.     rtu_bug = 1;
  81. #endif
  82.     kill(0, SIGSTOP);            /* If job control, suspend the job */
  83. #else
  84.     doexit(GOOD_EXIT);            /* Probably won't happen otherwise */
  85. #endif
  86.     concb(escape);            /* Put console back in Kermit mode */
  87.     if (!backgrd) prompt();        /* Reissue prompt when fg'd */
  88. }
  89.  
  90. /*  C M D I N I  --  Initialize the interactive command parser  */
  91.  
  92. cmdini() {
  93.  
  94. #ifdef AMIGA
  95.     congm();
  96.     concb(escape);
  97. #endif
  98.     cmdlvl = 0;                /* Start at command level 0 */
  99.     cmdstk[cmdlvl].src = CMD_KB;
  100.     cmdstk[cmdlvl].val = 0;
  101.     tlevel = -1;            /* Take file level = keyboard */
  102.     cmsetp("C-Kermit>");        /* Set default prompt */
  103.     initmac();                /* Initialize macro table */
  104.     addmac("ibm-linemode",
  105.        "set parity mark, set dupl half, set handsh xon, set flow none");
  106.  
  107. /* Look for init file in home or current directory. */
  108. /* (NOTE - should really use zkermini for this!)    */
  109. #ifdef OS2
  110.     if (rcflag)
  111.       lp = kermrc;
  112.     else
  113.       lp = zfindfile(kermrc);
  114.     strcpy(line,lp);
  115.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  116.         tlevel = 0;
  117.     cmdlvl++;
  118.     cmdstk[cmdlvl].src = CMD_TF;
  119.     cmdstk[cmdlvl].val = tlevel;
  120.     ifcmd[cmdlvl] = 0;
  121.     iftest[cmdlvl] = 0;
  122.     count[cmdlvl] = 0;
  123.         debug(F110,"init file",line,0);
  124.     } else {
  125.         debug(F100,"no init file","",0);
  126.     }
  127. #else 
  128.     homdir = zhome();
  129.     lp = line;
  130.     lp[0] = '\0';
  131. #ifdef vms
  132.     zkermini(line,sizeof(line),kermrc);
  133. #else
  134.     if (rcflag) {            /* If init file name from cmd line */
  135.     strcpy(lp,kermrc);        /* use it */
  136.     } else {                /* otherwise */
  137.     if (homdir) {            /* look in home directory for it */
  138.         strcpy(lp,homdir);
  139.         if (lp[0] == '/') strcat(lp,"/");
  140.     }
  141.     strcat(lp,kermrc);        /* and use the default name */
  142.     }
  143. #endif
  144. #ifdef AMIGA
  145.     reqoff();                /* disable requestors */
  146. #endif
  147.     debug(F110,"ini file is",line,0);
  148.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  149.     tlevel = 0;
  150.     cmdlvl++;
  151.     ifcmd[cmdlvl] = 0;
  152.     iftest[cmdlvl] = 0;
  153.     count[cmdlvl] = 0;
  154.     debug(F101,"open ok","",cmdlvl);
  155.     cmdstk[cmdlvl].src = CMD_TF;
  156.     cmdstk[cmdlvl].val = tlevel;
  157.     debug(F110,"init file",line,0);
  158.     }
  159.     if (homdir && (tlevel < 0)) {
  160.         strcpy(lp,kermrc);
  161.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  162.         tlevel = 0;
  163.         cmdlvl++;
  164.         cmdstk[cmdlvl].src = CMD_TF;
  165.         cmdstk[cmdlvl].val = tlevel;
  166.         ifcmd[cmdlvl] = 0;
  167.         iftest[cmdlvl] = 0;
  168.         count[cmdlvl] = 0;
  169.     }
  170.     }
  171. #endif
  172. #ifdef AMIGA
  173.     reqpop();                /* restore requestors */
  174. #else
  175.     congm();                /* Get console tty modes */
  176. #endif
  177. }
  178.  
  179. /*  P A R S E R  --  Top-level interactive command parser.  */
  180.  
  181. parser() {
  182.     int y, xx, yy, zz, cbn;
  183.     int icn;
  184.     char ic; 
  185.     char *cbp;
  186.  
  187. #ifdef AMIGA
  188.     reqres();            /* restore AmigaDOS requestors */
  189. #endif
  190.     concb(escape);        /* Put console in cbreak mode. */
  191.     conint(trap);        /* Turn on console terminal interrupts. */
  192.     ifcmd[0] = 0;        /* Command-level related variables */
  193.     iftest[0] = 0;        /* initialize variables at top level */
  194.     count[0] = 0;        /* of stack... */
  195. /*
  196.  sstate becomes nonzero when a command has been parsed that requires some
  197.  action from the protocol module.  Any non-protocol actions, such as local
  198.  directory listing or terminal emulation, are invoked directly from below.
  199. */
  200.     if (local && !backgrd) printf("\n"); /* Just returned from connect? */
  201.     sstate = 0;                /* Start with no start state. */
  202.     rmailf = rprintf = 0;        /* MAIL and PRINT modifiers for SEND */
  203.     *optbuf = NUL;            /* MAIL and PRINT options */
  204.     while (sstate == 0) {        /* Parse cmds until action requested */
  205.     while ((cmdstk[cmdlvl].src == CMD_TF)  /* If end of take file */
  206.            && (tlevel > -1)
  207.            && feof(tfile[tlevel])) {
  208.         popclvl();            /* pop command level */
  209.         cmini(ckxech);        /* and clear the cmd buffer. */
  210.         if (cmdlvl == 0) {        /* Just popped out of all cmd files? */
  211.         conint(trap);        /* Check background stuff again. */
  212.         return(0);        /* End of init file or whatever. */
  213.         }
  214.      }
  215.         if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
  216.         if (icn = conchk()) {    /* Yes */
  217.         while (icn--) {        /* User typed something */
  218.             ic = coninc(0);
  219.             if (ic == CR) {    /* Carriage return? */
  220.             printf(" Interrupted...\n");
  221.             dostop();
  222.             } else {
  223.             putchar(BEL);
  224.             }
  225.         }        
  226.         }
  227.         maclvl = cmdstk[cmdlvl].val; /* No interrupt, get current level */
  228.         cbp = cmdbuf;        /* Copy next cmd to macro buffer. */
  229.         *cbp = NUL;
  230.         if (*savbuf) {        /* In case then-part of 'if' command */
  231.         strcpy(cbp,savbuf);    /* was saved, restore it. */
  232.         *savbuf = '\0';
  233.         } else {            /* Else get next cmd from macro def */
  234.         debug(F111,"macro",macp,maclvl);
  235.         for (y = 0;        /* copy next macro part */
  236.              *macp[maclvl] && y < CMDBL;
  237.              y++,cbp++,macp[maclvl]++) {
  238.             *cbp = *macp[maclvl];
  239.             if (*cbp == ',') {    /* up to a comma */
  240.             macp[maclvl]++;
  241.             break;
  242.             }
  243.         }            /* or up to end, whichever is first */
  244.         if (*cmdbuf == NUL) {    /* If nothing was copied */
  245.             popclvl();        /* pop command level. */
  246.             debug(F101,"macro level popped","",maclvl);
  247.             continue;
  248.         } else {        /* otherwise, tack CR onto end */
  249.             *cbp++ = '\r';
  250.             *cbp = '\0';
  251.             if (mecho) printf("%s\n",cmdbuf);
  252.             debug(F110,"cmdbuf",cmdbuf,0);
  253.         }
  254.         }
  255.     } else if (cmdstk[cmdlvl].src == CMD_TF) { /* Reading TAKE file? */
  256.         debug(F101,"tlevel","",tlevel);
  257.         cbp = cmdbuf;        /* Get the next line. */
  258.         cbn = CMDBL;
  259.  
  260. /* Loop to get next command line and all continuation lines from take file. */
  261.  
  262. again:        if (*savbuf) {        /* In case then-part of 'if' command */
  263.         strcpy(line,savbuf);    /* was saved, restore it. */
  264.         *savbuf = '\0';
  265.         } else {
  266.         if (fgets(line,cbn,tfile[tlevel]) == NULL) continue;
  267.         }
  268.         if (icn = conchk()) {
  269.         while (icn--) {        /* User typed something... */
  270.             ic = coninc(0);    /* Look for carriage return */
  271.             if (ic == CR) {
  272.             printf(" Interrupted...\n");
  273.             dostop();
  274.             } else putchar(BEL); /* Ignore anything else */
  275.         }        
  276.         }
  277.         lp = line;            /* Got a line, copy it. */
  278.         debug(F110,"from TAKE file",lp,0);
  279.         while (*cbp++ = *lp++)
  280.           if (--cbn < 1) fatal("Command too long for internal buffer");
  281.         if (*(cbp - 3) == CMDQ || *(cbp - 3) == '-') { /* Continued? */
  282.         cbp -= 3;        /* If so, back up pointer, */
  283.         goto again;        /* go back, get next line. */
  284.         }
  285. /***        stripq(cmdbuf);        /* Strip any quotes from cmd buffer. */
  286.         untab(cmdbuf);        /* Convert tabs to spaces */
  287.         if (techo) printf("%s",cmdbuf); /* Echo if "take echo on" */
  288.     } else {            /* No take file, get typein. */
  289.         if (!backgrd) prompt();    /* Issue interactive prompt. */
  290.         cmini(ckxech);
  291.         }
  292.     repars = 1;            /* Now we know where command is */
  293.     displa = 0;            /* coming from, so read it. */
  294.     while (repars) {
  295.         cmres();            /* Reset buffer pointers. */
  296.         xx = cmkey2(cmdtab,ncmd,"Command","",toktab,xxstring);
  297.         debug(F101,"top-level cmkey2","",xx);
  298.         if (xx == -5) {
  299.         yy = chktok(toktab);
  300.         debug(F101,"top-level cmkey token","",yy);
  301.         ungword();
  302.         switch (yy) {
  303.           case '!': xx = XXSHE; break;
  304.           case '#': xx = XXCOM; break;
  305.           case ';': xx = XXCOM; break;
  306.           case ':': xx = XXLBL; break;
  307.           case '&': xx = XXECH; break;
  308.           default:
  309.             printf("\nInvalid - %s\n",cmdbuf);
  310.             xx = -2;
  311.         }
  312.         }
  313.         if (ifcmd[cmdlvl])        /* Count stmts after IF */
  314.           ifcmd[cmdlvl]++;
  315.         if (ifcmd[cmdlvl] > 2 && xx != XXELS && xx != XXCOM)
  316.           ifcmd[cmdlvl] = 0;
  317.         switch (zz = docmd(xx)) {
  318.         case -4:        /* EOF */
  319.             doexit(GOOD_EXIT);    /* ...exit successfully */
  320.             case -1:        /* Reparse needed */
  321.             repars = 1;
  322.             continue;
  323.         case -6:        /* Invalid command given w/no args */
  324.             case -2:        /* Invalid command given w/args */
  325.             /* This is going to be really ugly... */
  326.             yy = mlook(mactab,atmbuf,nmac); /* Look in macro table */
  327.             if (yy > -1) {                /* If it's there */
  328.             if (zz == -2) {                /* insert "do" */
  329.                 char *mp;
  330.                 mp = malloc(strlen(cmdbuf) + 5);
  331.                 if (!mp) {
  332.                 printf("?malloc error 1\n");
  333.                 return(-2);
  334.                 }
  335.                 sprintf(mp,"do %s ",cmdbuf);
  336.                 strcpy(cmdbuf,mp);
  337.                 free(mp);
  338.             } else sprintf(cmdbuf,"do %s \r",atmbuf);
  339.             if (ifcmd[cmdlvl] == 2)    /* This one doesn't count! */
  340.               ifcmd[cmdlvl]--;
  341.             debug(F111,"stuff cmdbuf",cmdbuf,zz);
  342.             repars = 1;    /* go for reparse */
  343.             continue;
  344.             } else printf("?Invalid - %s\n",cmdbuf);
  345.  
  346.             success = 0;
  347.             debug(F110,"top-level cmkey failed",cmdbuf,0);
  348.             if (backgrd)     /* if in background, terminate */
  349.             fatal("Kermit command error in background execution");
  350.             if (cmdstk[cmdlvl].src == CMD_TF && terror) {
  351.             ermsg("Kermit command error: take file terminated.");
  352.             popclvl();
  353.             }
  354.             if (cmdstk[cmdlvl].src == CMD_MD && merror) {
  355.             ermsg("Kermit command error: macro terminated.");
  356.             popclvl();
  357.             }
  358.             cmini(ckxech);    /* (fall thru) */
  359.              case -3:        /* Empty command OK at top level */
  360.         default:        /* Anything else (fall thru) */
  361.             repars = 0;        /* No reparse, get new command. */
  362.             continue;
  363.             }
  364.         }
  365.     }
  366.  
  367. /* Got an action command; disable terminal interrupts and return start state */
  368.  
  369.     if (!local) connoi();        /* Interrupts off only if remote */
  370.     return(sstate);
  371. }
  372.  
  373. /* OUTPUT command */
  374.  
  375. xxout(c) char c; {            /* Function to output a character. */
  376.     if (local)                /* If in local mode */
  377.       return(ttoc(c));            /* then to the external line */
  378.     else return(conoc(c));        /* otherwise to the console. */
  379. }
  380.  
  381. /* Returns 0 on failure, 1 on success */
  382.  
  383. dooutput(s) char *s; {
  384.     int x, y, quote;
  385.  
  386.     if (local && (tvtflg == 0)) {    /* If external line not conditioned */
  387.     y = ttvt(speed,flow);        /* do it now. */
  388.     if (y < 0) return(0);
  389.     tvtflg = 1;
  390.     }
  391.     quote = 0;                /* Initialize backslash (\) quote */
  392.     while (x = *s++) {            /* Loop through the string */
  393.     y = 0;                /* Error code, 0 = no error. */
  394.     if (x == CMDQ) {        /* Look for \b or \B in string */
  395.             quote = 1;            /* Got \ */
  396.         continue;            /* Get next character */
  397.     } else if (quote) {        /* This character is quoted */
  398.         quote = 0;            /* Turn off quote flag */
  399.         if (x == 'b' || x == 'B') {    /* If \b or \B */
  400.         debug(F101,"output BREAK","",0);
  401.         ttsndb();        /* send BREAK signal */
  402.         continue;        /* and not the b or B */
  403.         } else {            /* if \ not followed by b or B */
  404.         y = xxout(dopar(CMDQ));    /* output the backslash. */
  405.         }
  406.     }
  407.     y = xxout(dopar(x));    /* Output this character */
  408.     if (y < 0) {
  409.         printf("output error.\n");
  410.         return(0);
  411.     }
  412.     if (seslog)
  413.       if (zchout(ZSFILE,x) < 0) seslog = 0;
  414.     }
  415.     return(1);
  416. }
  417.  
  418. /* Display version herald and initial prompt */
  419.  
  420. herald() {
  421.     if (!backgrd)
  422.       printf("%s,%s\nType ? or 'help' for help\n",versio,ckxsys);
  423. }
  424.  
  425. fatal(msg) char *msg; {            /* Fatal error message */
  426. #ifdef OSK
  427.     printf("\nFatal: %s\n",msg);
  428. #else
  429.     printf("\r\nFatal: %s\n",msg);
  430. #endif /* OSK */
  431.     tlog(F110,"Fatal:",msg,0l);
  432.     doexit(BAD_EXIT);            /* Exit indicating failure */
  433. }
  434.  
  435.  
  436. ermsg(msg) char *msg; {            /* Print error message */
  437. #ifdef OSK
  438.     if (!quiet) printf("\n%s - %s\n",cmerrp,msg);
  439. #else
  440.     if (!quiet) printf("\r\n%s - %s\n",cmerrp,msg);
  441. #endif /* OSK */
  442.     tlog(F110,"Error -",msg,0l);
  443. }
  444.  
  445. /*  D O E X I T  --  Exit from the program.  */
  446.  
  447. doexit(exitstat) int exitstat; {
  448.     
  449.     ttclos();                /* Close external line, if any */
  450.     if (local) {
  451.     strcpy(ttname,dftty);        /* Restore default tty */
  452.     local = dfloc;            /* And default remote/local status */
  453.     }
  454.     if (!quiet) conres();        /* Restore console terminal. */
  455.     if (!quiet) connoi();        /* Turn off console interrupt traps. */
  456.  
  457.     if (deblog) {            /* Close any open logs. */
  458.     debug(F100,"Debug Log Closed","",0);
  459.     *debfil = '\0';
  460.     deblog = 0;
  461.     zclose(ZDFILE);
  462.     }
  463.     if (pktlog) {
  464.     *pktfil = '\0';
  465.     pktlog = 0;
  466.     zclose(ZPFILE);
  467.     }
  468.     if (seslog) {
  469.         *sesfil = '\0';
  470.     seslog = 0;
  471.     zclose(ZSFILE);
  472.     }
  473.     if (tralog) {
  474.     tlog(F100,"Transaction Log Closed","",0l);
  475.     *trafil = '\0';
  476.     tralog = 0;
  477.     zclose(ZTFILE);
  478.     }
  479.     syscleanup();
  480.     exit(exitstat);                /* Exit from the program. */
  481. }
  482.  
  483.  
  484. /*  B L D L E N  --  Make length-encoded copy of string  */
  485.  
  486. char *
  487. bldlen(str,dest) char *str, *dest; {
  488.     int len;
  489.     len = strlen(str);
  490.     *dest = tochar(len);
  491.     strcpy(dest+1,str);
  492.     return(dest+len+1);
  493. }
  494.  
  495.  
  496. /*  S E T G E N  --  Construct a generic command  */
  497.  
  498. setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; {
  499.     char *upstr, *cp;
  500.  
  501.     cp = cmdstr;
  502.     *cp++ = type;
  503.     *cp = NUL;
  504.     if (*arg1 != NUL) {
  505.     upstr = bldlen(arg1,cp);
  506.     if (*arg2 != NUL) {
  507.         upstr = bldlen(arg2,upstr);
  508.         if (*arg3 != NUL) bldlen(arg3,upstr);
  509.     }
  510.     }
  511.     cmarg = cmdstr;
  512.     debug(F110,"setgen",cmarg,0);
  513.  
  514.     return('g');
  515. }
  516.  
  517. /*  M L O O K  --  Lookup the macro name in the macro table  */
  518.  
  519. /*
  520.  Call this way:  v = mlook(table,word,n,&x);
  521.  
  522.    table - a 'struct mtab' table.
  523.    word  - the target string to look up in the table.
  524.    n     - the number of elements in the table.
  525.    x     - address of an integer for returning the table array index.
  526.  
  527.  The keyword table must be arranged in ascending alphabetical order, and
  528.  all letters must be lowercase.
  529.  
  530.  Returns the table index, 0 or greater, if the name was found, or:
  531.  
  532.   -3 if nothing to look up (target was null),
  533.   -2 if ambiguous,
  534.   -1 if not found.
  535.  
  536.  A match is successful if the target matches a keyword exactly, or if
  537.  the target is a prefix of exactly one keyword.  It is ambiguous if the
  538.  target matches two or more keywords from the table.
  539. */
  540. mlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
  541.  
  542.     int i, v, cmdlen;
  543.  
  544. /* Lowercase & get length of target, if it's null return code -3. */
  545.  
  546.     if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
  547.  
  548. /* Not null, look it up */
  549.  
  550.     for (i = 0; i < n-1; i++) {
  551.         if (!strcmp(table[i].kwd,cmd) ||
  552.            ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
  553.              strncmp(table[i+1].kwd,cmd,cmdlen))) {
  554.                 return(i);
  555.              }
  556.         if (v) return(-2);
  557.     }   
  558.  
  559. /* Last (or only) element */
  560.  
  561.     if (!strncmp(table[n-1].kwd,cmd,cmdlen)) {
  562.         return(n-1);
  563.     } else return(-1);
  564. }
  565.  
  566. /* mxlook is like mlook, but an exact full-length match is required */
  567.  
  568. mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
  569.     int i, j, cmdlen;
  570.     if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
  571.     for (i = 0; i < n; i++)
  572.       if ((strlen(table[i].kwd) == cmdlen) &&
  573.       (!strncmp(table[i].kwd,cmd,cmdlen))) return(i);
  574.     return(-1);
  575. }
  576.  
  577. addmac(nam,def) char *nam, *def; {    /* Add a macro to the macro table */
  578.     int i, y;
  579.     char *p, c;
  580.  
  581.     debug(F110,"addmac",nam,0);
  582.     debug(F110,"addmac",def,0);
  583.  
  584.     if (*nam == '%') {            /* If it's a variable name */
  585.     delmac(nam);            /* Delete any old value */
  586.     p = malloc(strlen(def) + 1);    /* Allocate space for its definition */
  587.     if (!p) {
  588.         printf("?malloc error 2\n");
  589.         return(-1);
  590.     }
  591.     strcpy(p,def);            /* Copy definition into new space */
  592.     c = *(nam + 1);            /* Variable name letter or digit */
  593.     if (c >= '0' && c <= '9') {    /* Digit? */
  594.         if (maclvl < 0) {        /* Yes, calling or in a macro? */
  595.         g_var[c] = p;        /* No, so make it global. */
  596.         debug(F111,"addmac numeric glob",p,maclvl);
  597.         } else {
  598.         m_arg[maclvl][c - '0'] = p; /* Put ptr in macro-arg table */
  599.         debug(F111,"addmac arg",p,maclvl);
  600.         }
  601.     } else {            /* It's a global variable */
  602.         if (c < 33 || c > GVARS) return(-1);
  603.         g_var[c] = p;        /* Put pointer in global-var table */
  604.         debug(F110,"addmac glob",p,0);
  605.     }
  606.     return(0);
  607.     }
  608.         
  609. /* Not a macro argument or a variable, so it's a macro definition */
  610.  
  611.     if (mxlook(mactab,nam,nmac) >= 0)    /* Look it up */
  612.       delmac(nam);            /* if it's already there, delete it. */
  613.  
  614.     lower(nam);
  615.     p = malloc(strlen(nam) + 1);    /* Allocate space for name */
  616.     if (!p) fatal("?malloc error 3");
  617.     for (y = 0;                /* Find the slot */
  618.      y < MAC_MAX && mactab[y].kwd != NULL && strcmp(nam,mactab[y].kwd) > 0;
  619.      y++) ;
  620.     if (y == MAC_MAX)            /* No more room. */
  621.       return(-1);
  622.     if (mactab[y].kwd != NULL) {    /* Must insert */
  623.     for (i = nmac; i > y; i--) {    /* Move the rest down one slot */
  624.         mactab[i].kwd = mactab[i-1].kwd;
  625.         mactab[i].val = mactab[i-1].val;
  626.         mactab[i].flgs = mactab[i-1].flgs;
  627.     }
  628.     }
  629.     p = malloc(strlen(nam) + 1);    /* Allocate space for name */
  630.     if (!p) {
  631.     printf("?malloc error 4\n");
  632.     return(-1);
  633.     }
  634.     strcpy(p,nam);            /* Copy name into new space */
  635.     mactab[y].kwd = p;            /* Add pointer to table */
  636.  
  637.     p = malloc(strlen(def) + 1);    /* Same deal for definition */
  638.     if (p == NULL) {
  639.     printf("?malloc error 5\n");
  640.     free(mactab[y].kwd);
  641.     mactab[y].kwd = NULL;
  642.     return(-1);
  643.     }
  644.     strcpy(p,def);
  645.     mactab[y].val = p;
  646.     mactab[y].flgs = 0;
  647.     nmac++;                /* Count this macro */
  648.     return(y);
  649. }
  650.  
  651. delmac(nam) char *nam; {        /* Delete the named macro */
  652.     int i, x;
  653.     char *p, c;
  654.  
  655.     if (*nam == '%') {            /* If it's a variable name */
  656.     c = *(nam + 1);            /* Variable name letter or digit */
  657.     if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */
  658.         p = m_arg[maclvl][c - '0'];    /* Get pointer from macro-arg table */
  659.         m_arg[maclvl][c - '0'] = NULL; /* Zero the table entry */
  660.     } else {            /* It's a global variable */
  661.         if (c < 33 || c > GVARS) return(0);
  662.         p = g_var[c];        /* Get pointer from global-var table */
  663.         g_var[c] = NULL;        /* Zero the table entry */
  664.     }
  665.     if (p) free(p);            /* Free the storage */
  666.     return(0);
  667.     }
  668.         
  669.     if ((x = mlook(mactab,nam,nmac)) < 0) return(x); /* Look it up */
  670.  
  671.     for (i = x; i < nmac; i++) {
  672.     mactab[i].kwd = mactab[i+1].kwd;
  673.     mactab[i].val = mactab[i+1].val;
  674.     mactab[i].flgs = mactab[i+1].flgs;
  675.     }
  676.     nmac--;                /* One less macro */
  677.     if (mactab[nmac].kwd)        /* Free the storage for the name */
  678.       free(mactab[nmac].kwd);
  679.     mactab[nmac].kwd = NULL;        /* Delete it from the table */
  680.     if (mactab[nmac].val)        /* Ditto for the definition */
  681.       free(mactab[nmac].val);
  682.     mactab[nmac].val = NULL;
  683.     mactab[nmac].flgs = 0;
  684.     return(0);
  685. }
  686.  
  687. initmac() {                /* Init macro & variable tables */
  688.     int i, j;
  689.  
  690.     nmac = 0;                /* No macros */
  691.     for (i = 0; i < MAC_MAX; i++) {    /* Initialize the macro table */
  692.     mactab[i].kwd = NULL;
  693.     mactab[i].val = NULL;
  694.     mactab[i].flgs = 0;
  695.     }
  696.     for (i = 0; i < MACLEVEL; i++) {    /* Init the macro argument tables */
  697.     for (j = 0; j < 10; j++) {
  698.         m_arg[i][j] = NULL;
  699.     }
  700.     }
  701.     for (i = 0; i < GVARS; i++) {    /* And the global variables table */
  702.     g_var[i] = NULL;
  703.     }
  704. }
  705.  
  706. /* Look up a % variable, return pointer to its value, else NULL */
  707.  
  708. char *
  709. varlook(vnp) char *vnp; {
  710.     char c;
  711.     char *p;
  712.     c = *(vnp + 1);            /* Fold case */
  713.     if (isupper(c)) *(vnp + 1) = tolower(c);
  714.     c = *(vnp + 1);            /* Variable name letter or digit */
  715.     if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */
  716.     p = m_arg[maclvl][c - '0'];    /* Get pointer from macro-arg table */
  717.     } else {                /* It's a global variable */
  718.     if (c > 31 && c <= GVARS)
  719.       p = g_var[c];            /* Get pointer from global-var table */
  720.     }
  721.     return(p);
  722. }
  723.  
  724. popclvl() {                /* Pop command level, return cmdlvl */
  725.     if (cmdlvl < 1) {            /* If we're already at top level */
  726.     cmdlvl = 0;            /* just make sure all the */
  727.     tlevel = -1;            /* stack pointers are set right */
  728.     maclvl = -1;            /* and return */
  729.     return(0);
  730.     } else if (cmdstk[cmdlvl].src == CMD_TF) { /* Reading from TAKE file? */
  731.     if (tlevel > -1) {        /* Yes, */
  732.         fclose(tfile[tlevel--]);    /* close it and pop take level */
  733.         cmdlvl--;            /* pop command level */
  734.     } else tlevel = -1;
  735.     } else if (cmdstk[cmdlvl].src == CMD_MD) { /* In a macro? */
  736.     if (maclvl > -1) {        /* Yes, */
  737.         macp[maclvl] = "";        /* set macro pointer to null string */
  738.         *cmdbuf = '\0';        /* clear the command buffer */
  739.         maclvl--;            /* pop macro level */
  740.         cmdlvl--;            /* and command level */
  741.     } else maclvl = -1;
  742.     }
  743.     return(cmdlvl < 1 ? 0 : cmdlvl);    /* Return command level */
  744. }
  745.  
  746. /* STOP - get back to C-Kermit prompt, no matter where from. */
  747.  
  748. dostop() {
  749.     while (popclvl()) ;            /* Pop all command levels */
  750.     cmini(ckxech);            /* Clear the command buffer. */
  751.     conint(trap);            /* Check background stuff again. */
  752.     return(0);
  753. }
  754.  
  755. /* Close the given log */
  756.  
  757. doclslog(x) int x; {
  758.     switch (x) {
  759.     case LOGD:
  760.         if (deblog == 0) {
  761.         printf("?Debugging log wasn't open\n");
  762.         return(0);
  763.         }
  764.         *debfil = '\0';
  765.         deblog = 0;
  766.         return(zclose(ZDFILE));
  767.  
  768.     case LOGP:
  769.         if (pktlog == 0) {
  770.         printf("?Packet log wasn't open\n");
  771.         return(0);
  772.         }
  773.         *pktfil = '\0';
  774.         pktlog = 0;
  775.         return(zclose(ZPFILE));
  776.  
  777.     case LOGS:
  778.         if (seslog == 0) {
  779.         printf("?Session log wasn't open\n");
  780.         return(0);
  781.         }
  782.         *sesfil = '\0';
  783.         seslog = 0;
  784.         return(zclose(ZSFILE));
  785.  
  786.         case LOGT:
  787.         if (tralog == 0) {
  788.         printf("?Transaction log wasn't open\n");
  789.         return(0);
  790.         }
  791.         *trafil = '\0';
  792.         tralog = 0;
  793.         return(zclose(ZTFILE));
  794.  
  795.     default:
  796.         printf("\n?Unexpected log designator - %ld\n", x);
  797.         return(0);
  798.     }
  799. }
  800.  
  801. static char *nm[] = { "disabled", "enabled" };
  802.  
  803. doshow(x) int x; {
  804.     int y;
  805.     char *s;
  806.     extern int en_cwd, en_del, en_dir, en_fin,
  807.       en_get, en_hos, en_sen, en_set, en_spa, en_typ, en_who;
  808.     extern int vernum, srvtim, incase, inecho, intime;
  809.     extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys;
  810.     extern char *connv, *dialv, *loginv;
  811.  
  812.     switch (x) {
  813.     case SHPAR:
  814.         if ((y = cmcfm()) < 0) return(y);
  815.         shopar();
  816.         break;
  817.  
  818.     case SHCOU:
  819.         if ((y = cmcfm()) < 0) return(y);
  820.         printf(" %d\n",count[cmdlvl]);
  821.         break;
  822.  
  823.         case SHSER:            /* Show Server */
  824.         if ((y = cmcfm()) < 0) return(y);
  825.         printf("Function           Status:\n");
  826.         printf(" GET                %s\n",nm[en_get]);
  827.         printf(" SEND               %s\n",nm[en_sen]);        
  828.         printf(" REMOTE CD/CWD      %s\n",nm[en_cwd]);
  829.         printf(" REMOTE DIRECTORY   %s\n",nm[en_dir]);
  830.         printf(" REMOTE HOST        %s\n",nm[en_hos]);        
  831.         printf(" REMOTE SET         %s\n",nm[en_set]);        
  832.         printf(" REMOTE SPACE       %s\n",nm[en_spa]);        
  833.         printf(" REMOTE TYPE        %s\n",nm[en_typ]);        
  834.         printf(" REMOTE WHO         %s\n",nm[en_who]);        
  835.         printf("Server Timeout: %d\n\n",srvtim);
  836.         break;
  837.  
  838.         case SHSTA:            /* Status of last command */
  839.         if ((y = cmcfm()) < 0) return(y);
  840.         if (success) printf(" SUCCESS\n"); else printf(" FAILURE\n");
  841.         break;
  842.  
  843.     case SHVER:
  844.         if ((y = cmcfm()) < 0) return(y);
  845.         printf("\nVersions:\n %s\n Numeric: %d\n",versio,vernum);
  846.         printf(" %s\n",protv);
  847.         printf(" %s\n",fnsv);
  848.         printf(" %s\n %s\n",cmdv,userv);
  849.         printf(" %s for%s\n",ckxv,ckxsys);
  850.         printf(" %s for%s\n",ckzv,ckzsys);
  851.         printf(" %s\n",connv);
  852.         printf(" %s\n %s\n\n",dialv,loginv);
  853.         break;
  854.  
  855.     case SHMAC:            /* Macro definitions */
  856.         x = cmfld("Macro name, variable name, or carriage return","",&s,
  857.               NULL);
  858.         if (x == -3)
  859.           *line = '\0';
  860.         else if (x < 0)
  861.           return(x);
  862.         else
  863.           strcpy(line,s);
  864.         if ((y = cmcfm()) < 0) return(y);        
  865.         if (*line != '\0' && *line != CMDQ && *line != '%') {
  866.         x = mlook(mactab,s,nmac);
  867.         switch (x) {
  868.           case -3:
  869.             return(0);
  870.           case -1:
  871.             printf("%s - not found\n",s);
  872.             return(0);
  873.           case -2:
  874.             y = strlen(line);
  875.             for (x = 0; x < nmac; x++)
  876.             if (!strncmp(mactab[x].kwd,line,y))
  877.               printf(" %s = %s\n",mactab[x].kwd,mactab[x].val);
  878.             return(0);
  879.           default:
  880.             printf(" %s = %s\n",mactab[x].kwd,mactab[x].val);
  881.             return(0);
  882.         }
  883.         }
  884.         printf("Macros:\n");
  885.         for (y = 0; y < nmac; y++) {
  886.         printf(" %s = %s\n",mactab[y].kwd,mactab[y].val);
  887.         }
  888.         x = 0;
  889.         for (y = 33; y < GVARS; y++)
  890.           if (g_var[y]) {
  891.           if (x == 0) printf("Global variables:\n");
  892.           x = 1;
  893.           printf(" %%%c = %s\n",y,g_var[y]);
  894.           }
  895.         if (maclvl > -1) {
  896.         printf("Macro arguments at level %d\n",maclvl);
  897.         for (y = 0; y < 10; y++)
  898.           if (m_arg[maclvl][y])
  899.             printf("%%%d = %s\n",y,m_arg[maclvl][y]);
  900.         }
  901.         break;
  902.  
  903.     case SHPRO:            /* Protocol parameters */
  904.         if ((y = cmcfm()) < 0) return(y);
  905.         shoparp();
  906.         printf("\n");
  907.         break;
  908.  
  909.     case SHCOM:            /* Communication parameters */
  910.         if ((y = cmcfm()) < 0) return(y);
  911.         printf("\n");
  912.         shoparc();
  913.         printf("\n");
  914.         break;
  915.  
  916.     case SHFIL:            /* File parameters */
  917.         if ((y = cmcfm()) < 0) return(y);
  918.         shoparf();
  919.         printf("\n");
  920.         break;
  921.  
  922.     case SHKEY: {            /* Key */
  923.         CHAR c;
  924.         if ((y = cmcfm()) < 0) return(y);        
  925.         printf(" Press key: ");
  926.         c = coninc(0);        /* For some reason this doesn't */
  927.         printf("\\%d\n",c);        /* return the 8th bit... */
  928.         break;
  929.         }
  930.  
  931.     case SHLNG:            /* Languages */
  932.         if ((y = cmcfm()) < 0) return(y);
  933.         shoparl();
  934.         break;
  935.  
  936.     case SHSCR:            /* Scripts */
  937.         if ((y = cmcfm()) < 0) return(y);        
  938.         printf(" Take  Echo:     %s\n", techo  ? "On" : "Off");
  939.         printf(" Take  Error:    %s\n", terror ? "On" : "Off");
  940.         printf(" Macro Echo:     %s\n", mecho  ? "On" : "Off");
  941.         printf(" Macro Error:    %s\n", merror ? "On" : "Off");
  942.         printf(" Input Case:     %s\n", incase ? "Observe" : "Ignore");
  943.         printf(" Input Echo:     %s\n", inecho ? "On" : "Off");
  944.         printf(" Input Timeout:  %s\n", intime ? "Quit" : "Proceed");
  945.         break;
  946.  
  947.       case SHSPD:
  948.         if ((y = cmcfm()) < 0) return(y);
  949.         y = ttgspd();
  950.         if (y > -1)
  951.           printf("%s, estimated speed: %d\n",ttname,y);
  952.         else
  953.           printf("%s, speed unknown\n",ttname);
  954.         break;
  955.  
  956.     default:
  957.         printf("\nNothing to show...\n");
  958.         return(-2);
  959.     }
  960.     return(success = 1);
  961. }
  962.