home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / CKPM5X_S.ZIP / CKUUS4.C < prev    next >
C/C++ Source or Header  |  1990-03-24  |  39KB  |  1,244 lines

  1. /*
  2.   File ckuus4.c -- Functions moved from other ckuus*.c modules to even
  3.   out their sizes.
  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. #include "ckcxla.h"
  13. #ifndef AMIGA
  14. #include <signal.h>
  15. #include <setjmp.h>
  16. #endif
  17.  
  18. #ifdef OS2
  19. #define SIGALRM SIGUSR1
  20. void alarm( unsigned );
  21. #endif
  22.  
  23. extern CHAR mystch, stchr, eol, seol, padch, mypadc, ctlq;
  24. extern CHAR *data, *rdatap, ttname[];
  25. extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist;
  26. extern char cmdbuf[], line[], debfil[], pktfil[], sesfil[], trafil[];
  27. extern kermrc[];
  28. extern char inpbuf[];           /* Buffer for INPUT and REINPUT */
  29. extern char *inpbp;         /* And pointer to same */
  30. extern struct keytab cmdtab[];
  31. extern int ncmd, network;
  32. extern int rcflag;
  33. extern struct mtab mactab[];
  34. extern int escape;
  35. extern int nmac;
  36. extern int action, cflg, xargc, stdouf, stdinf, displa, cnflg, nfils, cnflg;
  37. extern int nrmt, nprm, dfloc, deblog, seslog, speed, local, parity, duplex;
  38. extern int turn, turnch, pktlog, tralog, mdmtyp, flow, cmask, timef, spsizf;
  39. extern int rtimo, timint, srvtim, npad, mypadn, bctr, delay;
  40. extern int maxtry, spsiz, urpsiz, maxsps, maxrps, ebqflg, ebq;
  41. extern int rptflg, rptq, fncnv, binary, pktlog, warn, quiet, fmask, keep;
  42. extern int tsecs, bctu, len, atcapu, lpcapu, swcapu, sq, rpsiz;
  43. extern int wslots, wslotsn, wslotsr;
  44. extern int capas, atcapr;
  45. extern int spackets, rpackets, timeouts, retrans, crunched, wmax;
  46. extern int fcharset, tcharset, tslevel;
  47. extern int indef, intime, incase, inecho;
  48. extern int rptn, language, nlng, cmask, zincnt;
  49. extern int xxstring();
  50.  
  51. extern CHAR *zinptr;
  52. extern long filcnt, tfc, tlci, tlco, ffc, flci, flco;
  53. extern char *dftty, *versio, *ckxsys;
  54. extern struct langinfo langs[];
  55. extern struct keytab prmtab[];
  56. extern struct keytab remcmd[];
  57. extern struct keytab lngtab[];
  58. extern struct csinfo fcsinfo[], tcsinfo[];
  59.  
  60. char *malloc();
  61.  
  62. /* Macro stuff */
  63. extern int maclvl;
  64. extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
  65. extern char *g_var[GVARS];    /* for external 2-dimensional arrays. */
  66.  
  67. /* Pointers to translation functions (ditto!) */
  68. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
  69. CHAR (*sx)();               /* Local translation function */
  70.  
  71. /*** The following functions moved here from ckuus2.c because that module ***/
  72. /*** got too big... ***/
  73.  
  74.  
  75.  
  76. /*  P R E S C A N -- Quick look thru command-line args for init file name */
  77. prescan() {
  78.     int yargc; char **yargv;
  79.     char x;
  80.  
  81.     yargc = xargc;
  82.     yargv = xargv;
  83.     strcpy(kermrc,KERMRC);      /* Default init file name */
  84.     while (--yargc > 0) {       /* Look for -y on command line */
  85.     yargv++;
  86.     if (**yargv == '-') {       /* Option starting with dash */
  87.         x = *(*yargv+1);        /* Get option letter */
  88.         if (x == 'y') {     /* Is it y? */
  89.         yargv++, yargc--;   /* Yes, count and check argument */
  90.         if (yargc < 1) fatal("missing name in -y");
  91.         strcpy(kermrc,*yargv);  /* Replace init file name */
  92.         rcflag = 1;     /* Flag that this has been done */
  93.         return;
  94.         } else if (x == 'd') {  /* Do this early as possible! */
  95.         debopn("debug.log");
  96.         return;
  97.         }
  98.     } 
  99.     }
  100. }
  101.  
  102.  
  103. /*  C M D L I N  --  Get arguments from command line  */
  104. /*
  105.  Simple Unix-style command line parser, conforming with 'A Proposed Command
  106.  Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1,
  107.  No.3, 1984.
  108. */
  109. cmdlin() {
  110.     char x;             /* Local general-purpose int */
  111.     cmarg = "";             /* Initialize globals */
  112.     cmarg2 = "";
  113.     action = cflg = 0;
  114.  
  115.     while (--xargc > 0) {       /* Go through command line words */
  116.     xargv++;
  117.     debug(F111,"xargv",*xargv,xargc);
  118.         if (**xargv == '-') {       /* Got an option (begins with dash) */
  119.         x = *(*xargv+1);        /* Get the option letter */
  120.         if (doarg(x) < 0) doexit(BAD_EXIT); /* Go handle the option */
  121.         } else {            /* No dash where expected */
  122.         usage();
  123.         doexit(BAD_EXIT);
  124.     }
  125.     }
  126.     debug(F101,"action","",action);
  127.     if (!local) {
  128.     if ((action == 'g') || (action == 'r') ||
  129.         (action == 'c') || (cflg != 0))
  130.         fatal("-l and -b required");
  131.     }
  132.     if (*cmarg2 != 0) {
  133.     if ((action != 's') && (action != 'r') &&
  134.         (action != 'v'))
  135.         fatal("-a without -s, -r, or -g");
  136.     }
  137.     if ((action == 'v') && (stdouf) && (!local)) {
  138.         if (isatty(1))
  139.         fatal("unredirected -k can only be used in local mode");
  140.     }
  141.     if ((action == 's') || (action == 'v') ||
  142.         (action == 'r') || (action == 'x')) {
  143.     if (local) displa = 1;
  144.     if (stdouf) { displa = 0; quiet = 1; }
  145.     }
  146.  
  147.     if (quiet) displa = 0;      /* No display if quiet requested */
  148.  
  149.     if (cflg) {
  150.     conect();           /* Connect if requested */
  151.     if (action == 0) {
  152.         if (cnflg) conect();    /* And again if requested */
  153.         doexit(GOOD_EXIT);      /* Then exit indicating success */
  154.     }
  155.     }
  156.     if (displa) concb(escape);      /* (for console "interrupts") */
  157.     return(action);         /* Then do any requested protocol */
  158. }
  159.  
  160. /*  D O A R G  --  Do a command-line argument.  */
  161.  
  162. doarg(x) char x; {
  163.     int z; char *xp;
  164.  
  165.     xp = *xargv+1;          /* Pointer for bundled args */
  166.     while (x) {
  167.     switch (x) {
  168.  
  169. case 'x':               /* server */
  170.     if (action) fatal("conflicting actions");
  171.     action = 'x';
  172.     break;
  173.  
  174. case 'f':
  175.     if (action) fatal("conflicting actions");
  176.     action = setgen('F',"","","");
  177.     break;
  178.  
  179. case 'r':               /* receive */
  180.     if (action) fatal("conflicting actions");
  181.     action = 'v';
  182.     break;
  183.  
  184. case 'k':               /* receive to stdout */
  185.     if (action) fatal("conflicting actions");
  186.     stdouf = 1;
  187.     action = 'v';
  188.     break;
  189.  
  190. case 's':               /* send */
  191.     if (action) fatal("conflicting actions");
  192.     if (*(xp+1)) fatal("invalid argument bundling after -s");
  193.     z = nfils = 0;          /* Initialize file counter, flag */
  194.     cmlist = xargv+1;           /* Remember this pointer */
  195.     while (--xargc > 0) {       /* Traverse the list */ 
  196.     xargv++;
  197.     if (**xargv == '-') {       /* Check for sending stdin */
  198.         if (strcmp(*xargv,"-") != 0) break;
  199.         z++;
  200.         }
  201.     nfils++;            /* Bump file counter */
  202.     }
  203.     xargc++, xargv--;           /* Adjust argv/argc */
  204.     if (nfils < 1) fatal("missing filename for -s");
  205.     if (z > 1) fatal("-s: too many -'s");
  206.     if (z == 1) {
  207.     if (nfils == 1) nfils = 0;
  208.     else fatal("invalid mixture of filenames and '-' in -s");
  209.     }
  210.     if (nfils == 0) {
  211.     if (isatty(0)) fatal("sending from terminal not allowed");
  212.     else stdinf = 1;
  213.     }
  214.     debug(F101,*xargv,"",nfils);
  215.     action = 's';
  216.     break;
  217.  
  218. case 'g':               /* get */
  219.     if (action) fatal("conflicting actions");
  220.     if (*(xp+1)) fatal("invalid argument bundling after -g");
  221.     xargv++, xargc--;
  222.     if ((xargc == 0) || (**xargv == '-'))
  223.         fatal("missing filename for -g");
  224.     cmarg = *xargv;
  225.     action = 'r';
  226.     break;
  227.  
  228. case 'c':               /* connect before */
  229.     cflg = 1;
  230.     break;
  231.  
  232. case 'n':               /* connect after */
  233.     cnflg = 1;
  234.     break;
  235.  
  236. case 'h':               /* help */
  237.     usage();
  238.     doexit(GOOD_EXIT);
  239.  
  240. case 'a':               /* "as" */
  241.     if (*(xp+1)) fatal("invalid argument bundling after -a");
  242.     xargv++, xargc--;
  243.     if ((xargc < 1) || (**xargv == '-'))
  244.         fatal("missing name in -a");
  245.     cmarg2 = *xargv;
  246.     break;
  247.  
  248. case 'y':               /* alternate init-file name */
  249.     if (*(xp+1)) fatal("invalid argument bundling after -y");
  250.     xargv++, xargc--;
  251.     if (xargc < 1) fatal("missing name in -y");
  252.     /* strcpy(kermrc,*xargv); ...this was already done in prescan()... */
  253.     break;
  254.  
  255. case 'l':               /* set line */
  256.     if (*(xp+1)) fatal("invalid argument bundling after -l");
  257.     xargv++, xargc--;
  258.     if ((xargc < 1) || (**xargv == '-'))
  259.         fatal("communication line device name missing");
  260.     strcpy(ttname,*xargv);
  261. /*  if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1;  */
  262.     local = (strcmp(ttname,CTTNAM) != 0); /* (better than old way) */
  263.     debug(F101,"local","",local);
  264.     ttopen(ttname,&local,0);
  265.     break;
  266.  
  267. case 'b':                       /* set baud */
  268.     if (*(xp+1)) fatal("invalid argument bundling");
  269.     xargv++, xargc--;
  270.     if ((xargc < 1) || (**xargv == '-'))
  271.         fatal("missing baud");
  272.     z = atoi(*xargv);           /* Convert to number */
  273.     if (chkspd(z) > -1) speed = z;  /* Check it */
  274.         else fatal("unsupported baud rate");
  275.     break;
  276.  
  277. case 'e':               /* Extended packet length */
  278.     if (*(xp+1)) fatal("invalid argument bundling");
  279.     xargv++, xargc--;
  280.     if ((xargc < 1) || (**xargv == '-'))
  281.         fatal("missing length");
  282.     z = atoi(*xargv);           /* Convert to number */
  283.     if (z > 10 && z < maxrps) {
  284.         rpsiz = urpsiz = z;
  285.     if (z > 94) rpsiz = 94;     /* Fallback if other Kermit can't */
  286.     } else fatal("Unsupported packet length");
  287.     break;
  288.  
  289. case 'i':               /* Treat files as binary */
  290.     binary = 1;
  291.     break;
  292.  
  293. case 'w':               /* File warning */
  294.     warn = 1;
  295.     break;
  296.  
  297. case 'q':               /* Quiet */
  298.     quiet = 1;
  299.     break;
  300.  
  301. case 'd':               /* debug */
  302. /** debopn("debug.log"); *** already did this in prescan() **/
  303.     break;
  304.  
  305. case 'p':               /* set parity */
  306.     if (*(xp+1)) fatal("invalid argument bundling");
  307.     xargv++, xargc--;
  308.     if ((xargc < 1) || (**xargv == '-'))
  309.         fatal("missing parity");
  310.     switch(x = **xargv) {
  311.     case 'e':
  312.     case 'o':
  313.     case 'm':
  314.     case 's': parity = x; break;
  315.     case 'n': parity = 0; break;
  316.     default:  fatal("invalid parity");
  317.         }
  318.     break;
  319.  
  320. case 't':
  321.     turn = 1;               /* Line turnaround handshake */
  322.     turnch = XON;           /* XON is turnaround character */
  323.     duplex = 1;             /* Half duplex */
  324.     flow = 0;               /* No flow control */
  325.     break;
  326.  
  327. #ifdef OS2
  328. case 'u':
  329.     /* get numeric argument */
  330.     if (*(xp+1)) fatal("invalid argument bundling");
  331.     *xargv++, xargc--;
  332.     if ((xargc < 1) || (**xargv == '-'))
  333.         fatal("missing handle");
  334.     z = atoi(*xargv);           /* Convert to number */
  335.     ttclos();
  336.     if (!ttiscom(z)) fatal("invalid handle");
  337.     speed = ttspeed();
  338.     break;
  339. #endif /* OS2 */
  340.  
  341. default:
  342.     fatal("invalid argument, type 'kermit -h' for help");
  343.         }
  344.  
  345.     x = *++xp;              /* See if options are bundled */
  346.     }
  347.     return(0);
  348. }
  349.  
  350.  
  351. /*  T R A N S M I T  --  Raw upload  */
  352.  
  353. /*  Obey current line, duplex, parity, flow, text/binary settings. */
  354. /*  Returns 0 upon apparent success, 1 on obvious failure.  */
  355.  
  356. /***
  357.  Things to add:
  358.  . Make both text and binary mode obey set file bytesize.
  359.  . Maybe allow user to specify terminators other than CR?
  360.  . Maybe allow user to specify prompts other than single characters?
  361. ***/
  362.  
  363. int tr_int;             /* Flag if TRANSMIT interrupted */
  364.  
  365. SIGTYP
  366. trtrap() {              /* TRANSMIT interrupt trap */
  367.     tr_int = 1;
  368.     return;
  369. }
  370.  
  371.  
  372. /*  T R A N S M I T  --  Raw upload  */
  373.  
  374. transmit(s,t) char *s; char t; {
  375.  
  376. #ifndef OS2
  377.     SIGTYP (* oldsig)();        /* For saving old interrupt trap. */
  378. #endif
  379.     int z = 1;              /* Return code. 0=fail, 1=succeed. */
  380.     int x, c, i, n;         /* Workers... */
  381.     CHAR tt;
  382.  
  383.     tt = dopar(t);          /* Turnaround char, with parity */
  384.  
  385.     if (zopeni(ZIFILE,s) == 0) {    /* Open the file to be transmitted */
  386.     printf("?Can't open %s\n",s);
  387.     return(0);
  388.     }
  389.     x = -1;             /* Open the communication line */
  390.     if (ttopen(ttname,&x,mdmtyp) < 0) { /* (does no harm if already open) */
  391.     printf("Can't open %s\n",ttname);
  392.     return(0);
  393.     }
  394.     x = x ? speed : -1;         /* Put the line in "packet mode" */
  395.     if (ttpkt(x,flow,parity) < 0) {
  396.     printf("Can't condition line\n");
  397.     return(0);
  398.     }
  399.     i = 0;              /* Beginning of buffer. */
  400. #ifndef OS2
  401. #ifndef AMIGA
  402.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  403. #endif
  404. #endif
  405.     tr_int = 0;             /* Have not been interrupted (yet). */
  406.     z = 1;              /* Return code presumed good. */
  407.  
  408.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  409.     if (tr_int) {           /* Interrupted? */
  410.         printf("^C...\n");      /* Print message */
  411.         z = 0;
  412.         break;
  413.     }
  414.     if (duplex) conoc(c);       /* Echo character on screen */
  415.     if (binary) {           /* If binary file */
  416.         if (ttoc(dopar(c)) < 0) {   /* just try to send the character */
  417.         printf("?Can't transmit character\n");
  418.         z = 0;
  419.         break;
  420.         }
  421.         if (! duplex) {
  422.         x = ttinc(1);       /* Try to read back echo */
  423.         if (x > -1) conoc(x);
  424.         }
  425.     } else {            /* Line at a time for text files... */
  426.         if (c == '\n') {        /* Got a line */
  427.         if (i == 0 || line[i-1] != dopar('\r'))
  428.           line[i++] = dopar('\r'); /* Terminate it with CR */
  429.         if (ttol(line,i) < 0) { /* try to send it */
  430.             printf("?Can't transmit line\n");
  431.             z = 0;
  432.             break;
  433.         }
  434.         i = 0;          /* Reset the buffer pointer */
  435.         if (t) {        /* If we want a turnaround character */
  436.             x = 0;      /* wait for it */
  437.             while ((x != -1) && (x != t)) {
  438.             x = ttinc(1);
  439.             if (! duplex) conoc(x); /* also echo any echoes */
  440.             }
  441.         }
  442.         } else {            /* Not a newline, regular character */
  443.         line[i++] = dopar(c);   /* Put it in line buffer. */
  444.         if (i == LINBUFSIZ) {   /* If buffer full, */
  445.             if (ttol(line,i) < 0) { /* try to send it. */
  446.             printf("Can't send buffer\n");
  447.             z = 0;
  448.             break;
  449.             }           /* Don't wait for turnaround */
  450.             i = 0;      /* Reset buffer pointer */
  451.         }
  452.         }
  453.     }
  454.     }
  455. #ifndef OS2
  456. #ifndef AMIGA
  457.     signal(SIGINT,oldsig);      /* put old signal action back. */
  458. #endif
  459. #endif
  460.     ttres();                /* Done, restore tty, */
  461.     zclose(ZIFILE);         /* close file, */
  462.     return(z);              /* and return successfully. */
  463. }
  464.  
  465. /*  D O T Y P E  --  Type a file  */
  466.  
  467. dotype(s) char *s; {
  468.  
  469. #ifndef OS2
  470.     SIGTYP (* oldsig)();        /* For saving old interrupt trap. */
  471. #endif
  472.     int z = 1;              /* Return code. */
  473.     int x, c, i, n;         /* Workers... */
  474.  
  475.     if (zopeni(ZIFILE,s) == 0) {    /* Open the file to be transmitted */
  476.     printf("?Can't open %s\n",s);
  477.     return(0);
  478.     }
  479.     i = 0;              /* Beginning of buffer. */
  480. #ifndef OS2
  481. #ifndef AMIGA
  482.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  483. #endif
  484. #endif
  485.     tr_int = 0;             /* Have not been interrupted (yet). */
  486.     z = 1;              /* Return code presumed good. */
  487.  
  488.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  489.     if (tr_int) {           /* Interrupted? */
  490.         printf("^C...\n");      /* Print message */
  491.         z = 0;
  492.         break;
  493.     }
  494.     conoc(c);           /* Echo character on screen */
  495.     }
  496. #ifndef OS2
  497. #ifndef AMIGA
  498.     signal(SIGINT,oldsig);      /* put old signal action back. */
  499. #endif
  500. #endif
  501.     tr_int = 0;
  502.     ttres();                /* Done, restore tty, */
  503.     zclose(ZIFILE);         /* close file, */
  504.     return(z);              /* and return successfully. */
  505. }
  506. /*  X L A T E  --  Translate a local file from one character set to another */
  507.  
  508. /*
  509.   Translates from current file character set (fcharset) to the current
  510.   transfer character set (tcharset).  For now there's no way to ask it
  511.   to translate in the other direction, e.g. from Latin-1 to German ASCII.
  512. */
  513.  
  514. xlate(fin, fout) char *fin, *fout; {    /* Call with names of in & out files */
  515.  
  516. #ifndef OS2
  517.     SIGTYP (* oldsig)();        /* For saving old interrupt trap. */
  518. #endif
  519.     int z = 1;              /* Return code. */
  520.     int x, c;               /* Workers. */
  521.  
  522.     if (zopeni(ZIFILE,fin) == 0) {  /* Open the file to be transmitted */
  523.     printf("?Can't open input file %s\n",fin);
  524.     return(0);
  525.     }
  526.     if (zopeno(ZOFILE,fout) == 0) { /* And the output file */
  527.     printf("?Can't open output file %s\n",fout);
  528.     return(0);
  529.     }
  530. #ifndef OS2
  531. #ifndef AMIGA
  532.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  533. #endif
  534. #endif
  535.     tr_int = 0;             /* Have not been interrupted (yet). */
  536.     z = 1;              /* Return code presumed good. */
  537.  
  538.     printf("%s (%s) => %s (%s)\n",  /* Say what we're doing. */
  539.        fin, fcsinfo[fcharset].name,
  540.        fout,tcsinfo[tcharset].name
  541.     );
  542.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  543.     if (tr_int) {           /* Interrupted? */
  544.         printf("^C...\n");      /* Print message */
  545.         z = 0;
  546.         break;
  547.     }
  548.     sx = xls[tcharset][fcharset];   /* Get translation function */
  549.     if (zchout(ZOFILE,(*sx)(c)) < 0) { /* Output translated character */
  550.         printf("File output error\n");
  551.         z = 0;
  552.         break;
  553.     }
  554.     }
  555. #ifndef OS2
  556. #ifndef AMIGA
  557.     signal(SIGINT,oldsig);      /* put old signal action back. */
  558. #endif
  559. #endif
  560.     tr_int = 0;
  561.     zclose(ZIFILE);         /* close files, */
  562.     zclose(ZOFILE);
  563.     return(z);              /* and return successfully. */
  564. }
  565.  
  566. /*  D O L O G  --  Do the log command  */
  567.  
  568. dolog(x) int x; {
  569.     int y; char *s;
  570.  
  571.     switch (x) {
  572.  
  573.     case LOGD:
  574. #ifdef DEBUG
  575.         y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
  576. #else
  577.             y = -2; s = "";
  578.         printf("%s","- Sorry, debug log not available\n");
  579. #endif
  580.         break;
  581.  
  582.     case LOGP:
  583.         y = cmofi("Name of packet log file","packet.log",&s,xxstring);
  584.         break;
  585.  
  586.     case LOGS:
  587.         y = cmofi("Name of session log file","session.log",&s,xxstring);
  588.         break;
  589.  
  590.     case LOGT:
  591. #ifdef TLOG
  592.         y = cmofi("Name of transaction log file","transact.log",&s,
  593.               xxstring);
  594. #else
  595.             y = -2; s = "";
  596.         printf("%s","- Sorry, transaction log not available\n");
  597. #endif
  598.         break;
  599.  
  600.     default:
  601.         printf("\n?Unexpected log designator - %d\n",x);
  602.         return(-2);
  603.     }
  604.     if (y < 0) return(y);
  605.  
  606.     strcpy(line,s);
  607.     s = line;
  608.     if ((y = cmcfm()) < 0) return(y);
  609.  
  610.     switch (x) {
  611.  
  612.     case LOGD:
  613.         return(deblog = debopn(s));
  614.  
  615.     case LOGP:
  616.         return(pktlog = pktopn(s));
  617.  
  618.     case LOGS:
  619.         return(seslog=sesopn(s));
  620.  
  621.     case LOGT:
  622.         return(tralog=traopn(s));
  623.  
  624.     default:
  625.         return(-2);
  626.     }
  627. }
  628.  
  629. int pktopn(char * s)
  630.     {
  631.     extern char pktfil[];
  632.     
  633.     int y;
  634.  
  635.     zclose(ZPFILE);
  636.     if(s[0]='\0')
  637.         return(0);
  638.  
  639.     y = zopeno(ZPFILE,s);
  640.     if (y > 0) 
  641.         strcpy(pktfil,s); 
  642.     else 
  643.         *pktfil = '\0';
  644.     
  645.     return(y);
  646.     }
  647.  
  648.  
  649. int traopn(char * s)
  650.     {
  651.     extern char trafil[];
  652.  
  653.     int y;
  654.  
  655.     zclose(ZTFILE);
  656.     if(s[0]=='\0')
  657.         return(0);
  658.  
  659.     y = zopeno(ZTFILE,s);
  660.     if (y > 0) {
  661.     strcpy(trafil,s);
  662.     tlog(F110,"Transaction Log:",versio,0l);
  663.     tlog(F100,ckxsys,"",0);
  664.     ztime(&s);
  665.     tlog(F100,s,"",0l);
  666.         }
  667.     else *trafil = '\0';
  668.     
  669.     return(y);
  670.     }
  671.  
  672.  
  673. int sesopn(s)
  674. char * s;
  675.     {
  676.     extern char sesfil[];
  677.     int y;
  678.  
  679.     zclose(ZSFILE);
  680.     if(s[0]=='\0')
  681.         return(0);
  682.  
  683.     y = zopeno(ZSFILE,s);
  684.     if (y > 0) strcpy(sesfil,s); else *sesfil = '\0';
  685.  
  686.     return(y);
  687.     }
  688.  
  689.  
  690.  
  691. /*  D E B O P N  --  Open a debugging file  */
  692.  
  693. debopn(s) char *s; {
  694. #ifdef DEBUG
  695.     char *tp;
  696.  
  697.     zclose(ZDFILE);
  698.     if(s[0]=='\0')
  699.         {
  700.         return(deblog=0);
  701.         }
  702.  
  703.     deblog = zopeno(ZDFILE,s);
  704.     if (deblog > 0) {
  705.     strcpy(debfil,s);
  706.     debug(F110,"Debug Log ",versio,0);
  707.     debug(F100,ckxsys,"",0);
  708.     ztime(&tp);
  709.     debug(F100,tp,"",0);
  710.     } else *debfil = '\0';
  711.     return(deblog);
  712. #else
  713.     return(0);
  714. #endif
  715. }
  716.  
  717. /*  S H O P A R  --  Show Parameters  */
  718.  
  719. shoparc() {
  720.     int i;
  721.     extern struct keytab mdmtab[]; extern int nmdm;
  722.  
  723.     puts("Communications Parameters:");
  724.  
  725.     if (network) {
  726.     printf(" Host: %s",ttname);
  727.     } else {
  728.     printf(" Line: %s, speed: ",ttname);
  729.     if (speed < 0) printf("unknown"); else printf("%d",speed);
  730.     }
  731.     printf(", mode: ");
  732.     if (local) printf("local"); else printf("remote");
  733.     if (network == 0) {
  734.     for (i = 0; i < nmdm; i++) {
  735.         if (mdmtab[i].val == mdmtyp) {
  736.         printf(", modem-dialer: %s",mdmtab[i].kwd);
  737.         break;
  738.         }
  739.     }
  740.     }
  741.     printf("\n Bits: %d",(parity) ? 7 : 8);
  742.     printf(", parity: ");
  743.     switch (parity) {
  744.     case 'e': printf("even");  break;
  745.     case 'o': printf("odd");   break;
  746.     case 'm': printf("mark");  break;
  747.     case 's': printf("space"); break;
  748.     case 0:   printf("none");  break;
  749.     default:  printf("invalid - %d",parity); break;
  750.     }       
  751.     printf(", duplex: ");
  752.     if (duplex) printf("half, "); else printf("full, ");
  753.     printf("flow: ");
  754.     if (flow == 1) printf("xon/xoff");
  755.     else if (flow == 0) printf("none");
  756.     else printf("%d",flow);
  757.     printf(", handshake: ");
  758.     if (turn) printf("%d\n",turnch); else printf("none\n");
  759.     printf("Terminal emulation: %d bits\n", (cmask == 0177) ? 7 : 8);
  760.     return(0);
  761. }
  762.  
  763. shoparf() {
  764.     printf("\nFile parameters:              Attributes:       ");
  765.     if (atcapr) printf("on"); else printf("off");
  766.     printf("\n File Names:   ");
  767.     if (fncnv) printf("%-12s","converted"); else printf("%-12s","literal");
  768. #ifdef DEBUG
  769.     printf("   Debugging Log:    ");
  770.     if (deblog) printf("%s",debfil); else printf("none");
  771. #endif
  772.     printf("\n File Type:    ");
  773.     if (binary) printf("%-12s","binary"); else printf("%-12s","text");
  774.     printf("   Packet Log:       ");
  775.     if (pktlog) printf(pktfil); else printf("none");
  776.     printf("\n File Warning: ");
  777.     if (warn) printf("%-12s","on"); else printf("%-12s","off");
  778.     printf("   Session Log:      ");
  779.     if (seslog) printf(sesfil); else printf("none");
  780.     printf("\n File Display: ");
  781.     if (quiet) printf("%-12s","off"); else printf("%-12s","on");
  782. #ifdef TLOG
  783.     printf("   Transaction Log:  ");
  784.     if (tralog) printf(trafil); else printf("none");
  785. #endif
  786.     if (! binary) {
  787.     shocharset();
  788.     } else printf("\n");
  789.     printf("\nFile Byte Size: %d",(fmask == 0177) ? 7 : 8);
  790.     printf(", Incomplete File Disposition: ");
  791.     if (keep) printf("keep"); else printf("discard");
  792. #ifdef KERMRC    
  793.     printf(", Init file: %s",kermrc);
  794. #endif
  795.     printf("\n");
  796. }
  797.  
  798. shoparp() {
  799.     printf("\nProtocol Parameters:   Send    Receive");
  800.     if (timef || spsizf) printf("    (* = override)");
  801.     printf("\n Timeout:      %11d%9d", rtimo,  timint);
  802.     if (timef) printf("*"); else printf(" ");
  803.     printf("       Server timeout:%4d\n",srvtim);
  804.     printf("\n Padding:      %11d%9d", npad,   mypadn);
  805.     printf("        Block Check: %6d\n",bctr);
  806.     printf(  " Pad Character:%11d%9d", padch,  mypadc);
  807.     printf("        Delay:       %6d\n",delay);
  808.     printf(  " Packet Start: %11d%9d", mystch, stchr);
  809.     printf("        Max Retries: %6d\n",maxtry);
  810.     printf(  " Packet End:   %11d%9d", seol,   eol);
  811.     if (ebqflg)
  812.       printf("        8th-Bit Prefix: '%c'",ebq);
  813.     printf(  "\n Packet Length:%11d", spsiz);
  814.     printf( spsizf ? "*" : " " ); printf("%8d",  urpsiz);
  815.     printf( (urpsiz > 94) ? " (94)" : "     ");
  816.     if (rptflg)
  817.       printf("   Repeat Prefix:  '%c'",rptq);
  818.     printf(  "\n Length Limit: %11d%9d", maxsps, maxrps);
  819.     printf("        Window:%12d%4d\n",wslotsr,wslotsn);
  820. }
  821.  
  822. shoparl() {
  823.     int i;
  824.     printf("\nAvailable Languages:\n");
  825.     for (i = 0; i < MAXLANG; i++) {
  826.     printf(" %s\n",langs[i].description);
  827.     }   
  828.     printf("\nCurrent Language: %s\n",langs[language].description);
  829.     shocharset();
  830.     printf("\n\n");
  831. }
  832.  
  833. shocharset() {
  834.     printf("\nFile Character-Set: %s (",fcsinfo[fcharset].name);
  835.     if (fcsinfo[fcharset].size == 128) printf("7-bit)");
  836.     else printf("8-bit)");
  837.     printf("\nTransfer Character Set");
  838.     if (tslevel == TS_L2)
  839.       printf(": (international)");
  840.     else
  841.       printf(": %s",tcsinfo[tcharset].name);
  842. }
  843.  
  844. shopar() {
  845.     printf("\n%s,%s, ",versio,ckxsys); 
  846.     shoparc();
  847.     shoparp();
  848.     shoparf();
  849. }
  850.  
  851. /*  D O S T A T  --  Display file transfer statistics.  */
  852.  
  853. dostat() {
  854.     printf("\nMost recent transaction --\n");
  855.     printf(" files: %ld\n",filcnt);
  856.     printf(" total file characters  : %ld\n",tfc);
  857.     printf(" communication line in  : %ld\n",tlci);
  858.     printf(" communication line out : %ld\n",tlco);
  859.     printf(" packets sent           : %d\n", spackets);
  860.     printf(" packets received       : %d\n", rpackets);
  861.     printf(" damaged packets rec'd  : %d\n", crunched);
  862.     printf(" timeouts               : %d\n", timeouts);
  863.     printf(" retransmissions        : %d\n", retrans);
  864.     printf(" window slots used      : %d\n", wmax);
  865.     printf(" elapsed time           : %d sec\n",tsecs);
  866.     if (filcnt > 0) {
  867.     if (tsecs > 0) {
  868.         long lx;
  869.         lx = tfc / tsecs;
  870.         printf(" effective data rate    : %ld cps\n",lx);
  871.         if (speed > 0 && network == 0) {
  872.         lx = (lx * 100l) / speed;
  873.         printf(" efficiency             : %ld %%\n",lx * 10L);
  874.         }
  875.     }
  876.     printf(" packet length          : %d (send), %d (receive)\n",
  877.            spsiz,urpsiz);
  878.     printf(" block check type used  : %d\n",bctu);
  879.     printf(" compression            : ");
  880.     if (rptflg) printf("yes [%c] (%d)\n",rptq,rptn); else printf("no\n");
  881.     printf(" 8th bit prefixing      : ");
  882.     if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n\n");
  883.     } else printf("\n");
  884.     return(1);
  885. }
  886.  
  887. /*  F S T A T S  --  Record file statistics in transaction log  */
  888.  
  889. fstats() {
  890.     tfc += ffc;
  891.     tlog(F100," end of file","",0l);
  892.     tlog(F101,"  file characters        ","",ffc);
  893.     tlog(F101,"  communication line in  ","",flci);
  894.     tlog(F101,"  communication line out ","",flco);
  895. }
  896.  
  897.  
  898. /*  T S T A T S  --  Record statistics in transaction log  */
  899.  
  900. tstats() {
  901.     char *tp; int x;
  902.  
  903.     ztime(&tp);             /* Get time stamp */
  904.     tlog(F110,"End of transaction",tp,0l);  /* Record it */
  905.  
  906.     if (filcnt < 1) return;     /* If no files, done. */
  907.  
  908. /* If multiple files, record character totals for all files */
  909.  
  910.     if (filcnt > 1) {
  911.     tlog(F101," files","",filcnt);
  912.     tlog(F101," total file characters   ","",tfc);
  913.     tlog(F101," communication line in   ","",tlci);
  914.     tlog(F101," communication line out  ","",tlco);
  915.     }
  916.  
  917. /* Record timing info for one or more files */
  918.  
  919.     tlog(F101," elapsed time (seconds)  ","",(long) tsecs);
  920.     if (tsecs > 0) {
  921.     long lx;
  922.     lx = (tfc / tsecs) * 10;
  923.     tlog(F101," effective data rate     ","",lx);
  924.     if (speed > 0 && network == 0) {
  925.         lx = (lx * 100L) / speed;
  926.         tlog(F101," efficiency (percent)    ","",lx);
  927.     }
  928.     }
  929.     tlog(F100,"","",0L);        /* Leave a blank line */
  930. }
  931.  
  932. /*  S D E B U  -- Record spar results in debugging log  */
  933.  
  934. sdebu(len) int len; {
  935.     debug(F111,"spar: data",rdatap,len);
  936.     debug(F101," spsiz ","", spsiz);
  937.     debug(F101," timint","",timint);
  938.     debug(F101," npad  ","",  npad);
  939.     debug(F101," padch ","", padch);
  940.     debug(F101," seol  ","",  seol);
  941.     debug(F101," ctlq  ","",  ctlq);
  942.     debug(F101," ebq   ","",   ebq);
  943.     debug(F101," ebqflg","",ebqflg);
  944.     debug(F101," bctr  ","",  bctr);
  945.     debug(F101," rptq  ","",  rptq);
  946.     debug(F101," rptflg","",rptflg);
  947.     debug(F101," atcapu","",atcapu);
  948.     debug(F101," lpcapu","",lpcapu);
  949.     debug(F101," swcapu","",swcapu);
  950.     debug(F101," wslotsn","", wslotsn);
  951. }
  952. /*  R D E B U -- Debugging display of rpar() values  */
  953.  
  954. rdebu(len) int len; {
  955.     debug(F111,"rpar: data",data,len); /*** was rdatap ***/
  956.     debug(F101," rpsiz ","",xunchar(data[0]));
  957.     debug(F101," rtimo ","", rtimo);
  958.     debug(F101," mypadn","",mypadn);
  959.     debug(F101," mypadc","",mypadc);
  960.     debug(F101," eol   ","",   eol);
  961.     debug(F101," ctlq  ","",  ctlq);
  962.     debug(F101," sq    ","",    sq);
  963.     debug(F101," ebq   ","",   ebq);
  964.     debug(F101," ebqflg","",ebqflg);
  965.     debug(F101," bctr  ","",  bctr);
  966.     debug(F101," rptq  ","",data[9]);
  967.     debug(F101," rptflg","",rptflg);
  968.     debug(F101," capas ","",capas);
  969.     debug(F101," bits  ","",data[capas]);
  970.     debug(F101," atcapu","",atcapu);
  971.     debug(F101," lpcapu","",lpcapu);
  972.     debug(F101," swcapu","",swcapu);
  973.     debug(F101," wslotsr","", wslotsr);
  974.     debug(F101," rpsiz(extended)","",rpsiz);
  975. }
  976.  
  977. /*  D O C O N E C T  --  Do the connect command  */
  978.  
  979. /*  Note, we don't call this directly from dial, because we need to give */
  980. /*  the user a chance to change parameters (e.g. parity) after the */
  981. /*  connection is made. */
  982.  
  983. doconect() {
  984.     int x;
  985.     conres();               /* Put console back to normal */
  986.     x = conect();           /* Connect */
  987.     concb(escape);          /* Put console into cbreak mode, */
  988.     return(x);              /* for more command parsing. */
  989. }
  990.  
  991. /* The INPUT command */
  992.  
  993. doinput(timo,s) int timo; char *s; {
  994.     int x, y, i, icn;
  995.     char *xp, *xq;
  996.     CHAR c;
  997.  
  998.     y = strlen(s);
  999.     debug(F111,"doinput",s,y);
  1000.     if (timo <= 0) timo = 1;        /* Give at least 1 second timeout */
  1001.     x = 0;              /* Return code, assume failure */
  1002.     i = 0;              /* String pattern match position */
  1003.  
  1004.     xp = malloc(y+2);           /* Make a separate copy of the */
  1005.     if (!xp) {              /* input string for editing. */
  1006.     printf("?malloc error 5\n");
  1007.     return(x);
  1008.     }
  1009.     xq = xp;                /* Save pointer to beginning */
  1010.     if (!incase) {          /* INPUT CASE = IGNORE?  */
  1011.     while (*s) {            /* Yes, convert to lowercase */
  1012.         *xp = *s;
  1013.         if (isupper(*xp)) *xp = tolower(*xp);
  1014.         *xp++; *s++;
  1015.     }
  1016.     *xp = NUL;          /* Terminate the search string. */
  1017.     s = xq;             /* Point back to beginning. */
  1018.     }
  1019.     while (1) {             /* Character-getting loop */
  1020.     if (timo) {
  1021.         debug(F100,"input calling ttinc(0)","",0);
  1022.         if (local) {        /* One case for local */
  1023.         y = ttinc(1);       /* Get character from comm line. */
  1024.         debug(F101,"input ttinc(1) returns","",y);
  1025.         if (icn = conchk()) {   /* Interrupted from keyboard? */
  1026.             debug(F101,"input interrupted from keyboard","",icn);
  1027.             while (icn--) coninc(0); /* Yes, read what was typed. */
  1028.             x = 0;      /* And fail. */
  1029.             break;
  1030.         }
  1031.         } else {            /* Another for remote */
  1032.         y = coninc(1);
  1033.         debug(F101,"input coninc(1) returns","",y);
  1034.         }
  1035.         if (y < 0) {
  1036.         if (--timo == 0) break; /* Failed. */
  1037.         debug(F101,"input timo","",timo);
  1038.         }
  1039.     }
  1040.     if (y < 1) continue;        /* No character arrived, keep trying */
  1041.     c = cmask & (CHAR) y;       /* Mask off parity */
  1042.     *inpbp++ = c;           /* Store result in circular buffer */
  1043.     if (inpbp >= inpbuf + INPBUFSIZ) inpbp = inpbuf;
  1044.     if (inecho) conoc(c);       /* Echo and log the input character */
  1045.     if (seslog)
  1046.       if (zchout(ZSFILE,c) < 0) seslog = 0;
  1047.     if (!incase) {          /* Ignore alphabetic case? */
  1048.         if (isupper(c)) c = tolower(c); /* Yes */
  1049.     }
  1050.     debug(F000,"doinput char","",c);
  1051.     debug(F000,"compare char","",s[i]);
  1052.     if (c == s[i]) i++; else i = 0; /* Check for match */
  1053.     if (s[i] == '\0') {     /* Matched all the way to end? */
  1054.         x = 1;          /* Yes, */
  1055.         break;          /* done. */
  1056.     }
  1057.     }
  1058.     if (xq) free(xq);           /* Free dynamic memory */
  1059.     return(x);
  1060. }
  1061.  
  1062. /* REINPUT Command */
  1063.  
  1064. /* Note, the timeout parameter is required, but ignored. */
  1065. /* Syntax is compatible with MS-DOS Kermit except timeout can't be omitted. */
  1066. /* This function only looks at the characters already received */
  1067. /* and does not read any new characters from the communication line. */
  1068.  
  1069. doreinp(timo,s) int timo; char *s; {
  1070.     int x, y, i;
  1071.     char *xx, *xp, *xq;
  1072.     CHAR c;
  1073.  
  1074.     y = strlen(s);
  1075.     debug(F111,"doinput",s,y);
  1076.     if (timo <= 0) timo = 1;        /* Give at least 1 second timeout */
  1077.     x = 0;              /* Return code, assume failure */
  1078.     i = 0;              /* String pattern match position */
  1079.  
  1080.     xp = malloc(y+2);           /* Make a separate copy of the */
  1081.     if (!xp) {              /* search string. */
  1082.     printf("?malloc error 6\n");
  1083.     return(x);
  1084.     }
  1085.     xq = xp;                /* Keep pointer to beginning. */
  1086.     if (!incase) {          /* INPUT CASE = IGNORE?  */
  1087.     while (*s) {            /* Yes, convert to lowercase */
  1088.         *xp = *s;
  1089.         if (isupper(*xp)) *xp = tolower(*xp);
  1090.         *xp++; *s++;
  1091.     }
  1092.     s = xq;
  1093.     }
  1094.     xx = inpbp;
  1095.     do {
  1096.     c = *xx++;
  1097.     if (xx >= inpbuf + INPBUFSIZ) xx = inpbuf;
  1098.     if (!incase) {          /* Ignore alphabetic case? */
  1099.         if (isupper(c)) c = tolower(c); /* Yes */
  1100.     }
  1101.     debug(F000,"doreinp char","",c);
  1102.     debug(F000,"compare char","",s[i]);
  1103.     if (c == s[i]) i++; else i = 0; /* Check for match */
  1104.     if (s[i] == '\0') {     /* Matched all the way to end? */
  1105.         x = 1;          /* Yes, */
  1106.         break;          /* done. */
  1107.     }
  1108.     } while (xx != inpbp);
  1109.     return(x);
  1110. }
  1111.  
  1112.  
  1113. /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
  1114.  
  1115. /*
  1116.  Copies result to new string.
  1117.   strips enclosing braces or doublequotes.
  1118.   interprets backslash escapes.
  1119.   returns 0 on success, nonzero on failure.
  1120.   tries to be compatible with MS-DOS Kermit.
  1121.  
  1122.  Syntax of input string:
  1123.   string = chars | "chars" | {chars}
  1124.   chars = (c* e*)*
  1125.   where c = any printable character, ascii 32-126
  1126.   and e = a backslash escape
  1127.   and * means 0 or more repetitions of preceding quantity
  1128.   backslash escape = \operand
  1129.   operand = {number} or number
  1130.   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
  1131.   radix code is oO (octal), hHxX (hex), dD or none (decimal).
  1132. */
  1133.  
  1134. yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
  1135.     int x;
  1136.     static char *new;
  1137.     new = *s2;
  1138.     if ((x = strlen(s)) == 0) {
  1139.     *new = '\0';
  1140.     return(0);
  1141.     }
  1142.     x--;
  1143.     *new++ = s[x];
  1144.     s[x] = 0;
  1145.     return(xxstring(s,&new));
  1146. }
  1147.  
  1148. /*
  1149.   X X S T R I N G  --  Expand variables and backslash codes.
  1150.  
  1151.     int xxtstring(s,&s2);
  1152.  
  1153.   Expands \%x variables via recursive descent.
  1154.   Argument s is a pointer to string to expand (source).
  1155.   Argument s2 is the address of where to put result (destination).
  1156.   Returns -1 on failure, 0 on success,
  1157.     with destination string null-terminated and s2 pointing to the
  1158.     terminating null, so that subsequent characters can added.
  1159. */
  1160.  
  1161. xxstring(s,s2) char *s; char **s2; {
  1162.     int x,              /* Current character */
  1163.         y,              /* Worker */
  1164.         z;              /* Flag for enclosing braces, quotes */
  1165.     static int depth = 0;       /* Call depth, avoid overflow */
  1166.     char *new;              /* Where to build expanded string */
  1167.  
  1168.     depth++;                /* Sink to a new depth */
  1169.     if (depth > 20) {           /* Too deep? */
  1170.     printf("?definition is circular or too deep\n");
  1171.     depth = 0;
  1172.     **s2 = NUL;
  1173.     return(-1);
  1174.     }
  1175.     y = strlen(s);          /* Get length */
  1176.     z = 0;              /* Flag for stripping last char */
  1177. #ifdef COMMENT
  1178.     if (*s == 34) {         /* Strip enclosing quotes, if any */
  1179.     if (s[y-1] == 34) {
  1180.         s++;
  1181.         z = 1;
  1182.     }
  1183.     } else if (*s == '{') {     /* or else enclosing braces */
  1184.     if (s[y-1] == '}') {
  1185.         s++;
  1186.         z = 1;
  1187.     }
  1188.     }
  1189. #endif /* COMMENT */
  1190.     while ( x = *s ) {          /* Loop for all characters */
  1191.         if (x != CMDQ) {        /* Convert backslash escapes */
  1192.         *(*s2)++ = *s++;        /* Normal char, copy it */
  1193.         continue;
  1194.     } else {
  1195.         if ((x = *(s+1)) != '%') {  /* If it's a backslash code */
  1196.         y = xxesc(&s);      /* Go interpret it */
  1197.         if (y < 0) {        /* Upon failure */
  1198.             *(*s2)++ = CMDQ;    /* Just copy the characters */
  1199.             *(*s2)++ = x;
  1200.             s++;        /* move source pointer past them */
  1201.             continue;       /* and go back for more */
  1202.         } else *(*s2)++ = y;    /* else deposit interpreted value */
  1203.         } else {            /* Otherwise it's a variable */
  1204.         char vb, *vp, *ss; int j;
  1205.         s += 2;         /* Get the letter or digit */
  1206.         vb = *s++;      /* and move source pointer past it */
  1207.         if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
  1208.             vb -= '0';      /* convert character to integer */
  1209.             if (maclvl < 0) /* Digit variables are global */
  1210.               vp = g_var[vb];   /* if no macro is active */
  1211.             else        /* otherwise */
  1212.               vp = m_arg[maclvl][vb]; /* they're on the stack */
  1213.         } else vp = g_var[vb];  /* Letter for global variable */
  1214.         if (vp) {       /* If definition not empty */
  1215.             new = *s2;      /* Recurse... */
  1216.             if (xxstring(vp,&new) < 0) return(-1);
  1217.             *s2 = new;
  1218.         }
  1219.         }
  1220.     }
  1221.     }
  1222. #ifdef COMMENT
  1223.     if (z) (*s2)--;         /* Strip trailing quote or brace */
  1224. #endif /* COMMENT */
  1225.     *(*s2) = NUL;           /* Terminate the new string */
  1226.     depth--;                /* Adjust stack depth gauge */
  1227.     return(0);              /* and return. */
  1228. }
  1229.  
  1230. xxstrcmp(s1,s2) char *s1; char *s2; {   /* Caseless string comparison. */
  1231.     int x;              /* Returns 0 if equal, 1 if not. */
  1232.     char t1, t2;
  1233.     x = strlen(s1);
  1234.     if (x != strlen(s2)) return(1); /* Unequal lengths, so unequal. */
  1235.     while (x--) {
  1236.     t1 = *s1++;
  1237.     t2 = *s2++;
  1238.     if (isupper(t1)) t1 = tolower(t1);
  1239.     if (isupper(t2)) t2 = tolower(t2);
  1240.     if (t1 != t2) break;
  1241.     }
  1242.     return(!(x == -1));
  1243. }
  1244.