ckuus5.c
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:266k
源码类别:

通讯/手机编程

开发平台:

Windows_Unix

  1. #include "ckcsym.h"
  2. #ifdef NOICP
  3. int cmdsrc() { return(0); }
  4. #endif /* NOICP */
  5. #ifndef NOICP
  6. /*  C K U U S 5 --  "User Interface" for C-Kermit, part 5  */
  7. /*
  8.   Author: Frank da Cruz <fdc@columbia.edu>,
  9.   Columbia University Academic Information Systems, New York City.
  10.   Copyright (C) 1985, 2000,
  11.     Trustees of Columbia University in the City of New York.
  12.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  13.     copyright text in the ckcmai.c module for disclaimer and permissions.
  14. */
  15. /* Includes */
  16. #include "ckcdeb.h"
  17. #include "ckcasc.h"
  18. #include "ckcker.h"
  19. #include "ckuusr.h"
  20. #include "ckcnet.h"
  21. #ifndef NOCSETS
  22. #include "ckcxla.h"
  23. #endif /* NOCSETS */
  24. #ifdef MAC
  25. #include "ckmasm.h"
  26. #endif /* MAC */
  27. #ifdef CK_SSL
  28. #include "ck_ssl.h"
  29. #endif /* CK_SSL */
  30. #ifdef OS2
  31. #include "ckoetc.h"
  32. #ifndef NT
  33. #define INCL_NOPM
  34. #define INCL_VIO /* Needed for ckocon.h */
  35. #include <os2.h>
  36. #undef COMMENT
  37. #else /* NT */
  38. #include <windows.h>
  39. #define TAPI_CURRENT_VERSION 0x00010004
  40. #include <tapi.h>
  41. #include <mcx.h>
  42. #include "ckntap.h"
  43. #define APIRET ULONG
  44. extern int DialerHandle;
  45. extern int StartedFromDialer;
  46. #endif /* NT */
  47. #include "ckocon.h"
  48. #include "ckokey.h"
  49. #ifdef putchar
  50. #undef putchar
  51. #endif /* putchar */
  52. #define putchar(x) conoc(x)
  53. extern int cursor_save ;
  54. extern bool cursorena[] ;
  55. #endif /* OS2 */
  56. /* For formatted screens, "more?" prompting, etc. */
  57. #ifdef FT18
  58. #define isxdigit(c) isdigit(c)
  59. #endif /* FT18 */
  60. #ifdef STRATUS /* Stratus Computer, Inc.  VOS */
  61. #ifdef putchar
  62. #undef putchar
  63. #endif /* putchar */
  64. #define putchar(x) conoc(x)
  65. #ifdef getchar
  66. #undef getchar
  67. #endif /* getchar */
  68. #define getchar(x) coninc(0)
  69. #endif /* STRATUS */
  70. /* External variables */
  71. extern int carrier, cdtimo, local, quiet, backgrd, bgset, sosi, suspend,
  72.   binary, escape, xargs, flow, cmdmsk, duplex, ckxech, seslog, what,
  73.   inserver, diractive, tlevel, cwdf, nfuncs, msgflg, remappd, hints, mdmtyp,
  74.   zincnt, cmask, rcflag, success, xitsta, pflag, tnlm, tn_nlm, xitwarn,
  75.   debses, xaskmore, parity, saveask, wasclosed, whyclosed;
  76. #ifdef CK_SPEED
  77. extern int prefixing;
  78. #endif /* CK_SPEED */
  79. extern int g_matchdot;
  80. #ifdef RECURSIVE
  81. extern int recursive;
  82. #endif /* RECURSIVE */
  83. #ifdef IKSDCONF
  84. extern char * iksdconf;
  85. #endif /* IKSDCONF */
  86. extern int ngetpath, exitonclose;
  87. extern char * getpath[];
  88. extern CHAR * epktmsg;
  89. extern char * snd_move;
  90. extern char * snd_rename;
  91. extern char * rcv_move;
  92. extern char * rcv_rename;
  93. extern char * g_snd_move;
  94. extern char * g_snd_rename;
  95. extern char * g_rcv_move;
  96. extern char * g_rcv_rename;
  97. extern char * nm[];
  98. #ifdef CK_UTSNAME
  99. extern char unm_mch[];
  100. extern char unm_mod[];
  101. extern char unm_nam[];
  102. extern char unm_rel[];
  103. extern char unm_ver[];
  104. #endif /* CK_UTSNAME */
  105. #ifndef NOPUSH
  106. #ifndef NOFRILLS
  107. extern char editor[];
  108. extern char editfile[];
  109. extern char editopts[];
  110. #ifdef BROWSER
  111. extern char browser[];
  112. extern char browsopts[];
  113. extern char browsurl[];
  114. #endif /* BROWSER */
  115. #endif /*  NOFRILLS */
  116. #endif /* NOPUSH */
  117. #ifndef NOSERVER
  118. extern char * x_user, * x_passwd, * x_acct;
  119. #endif /* NOSERVER */
  120. #ifdef CKLOGDIAL
  121. extern int dialog;
  122. extern char diafil[];
  123. #endif /* CKLOGDIAL */
  124. #ifndef NOSPL
  125. extern int cfilef, xxdot;
  126. extern char cmdfil[];
  127. struct localvar * localhead[CMDSTKL];
  128. struct localvar * localtail = NULL;
  129. struct localvar * localnext = NULL;
  130. _PROTOTYP( static VOID shoinput, (void) );
  131. _PROTOTYP( static char gettok,   (void) );
  132. _PROTOTYP( static VOID factor,   (void) );
  133. _PROTOTYP( static VOID term,     (void) );
  134. _PROTOTYP( static VOID termp,    (void) );
  135. _PROTOTYP( static VOID exprp,    (void) );
  136. _PROTOTYP( static VOID expr,     (void) );
  137. _PROTOTYP( static VOID simple,   (void) );
  138. _PROTOTYP( static VOID simpler,  (void) );
  139. _PROTOTYP( static VOID simplest, (void) );
  140. _PROTOTYP( static long xparse,   (void) );
  141. #endif /* NOSPL */
  142. #ifdef MAC
  143. char * ckprompt = "Mac-Kermit>"; /* Default prompt for Macintosh */
  144. char * ikprompt = "IKSD>";
  145. #else  /* Not MAC */
  146. #ifdef NOSPL
  147. #ifdef OS2
  148. char * ckprompt = "K-95> "; /* Default prompt for Win32 */
  149. char * ikprompt = "IKSD> ";
  150. #else
  151. char * ckprompt = "C-Kermit>";
  152. char * ikprompt = "IKSD>";
  153. #endif /* NT */
  154. #else  /* NOSPL */
  155. #ifdef OS2
  156. /* Default prompt for OS/2 and Win32 */
  157. char * ckprompt = "[\freplace(\v(dir),/,\\)] K-95> ";
  158. char * ikprompt = "[\freplace(\v(dir),/,\\)] IKSD> ";
  159. #else
  160. #ifdef VMS
  161. char * ckprompt = "\v(dir) C-Kermit>"; /* Default prompt VMS */
  162. char * ikprompt = "\v(dir) IKSD>";
  163. #else
  164. char * ckprompt = "(\v(dir)) C-Kermit>"; /* Default prompt for others */
  165. char * ikprompt = "(\v(dir)) IKSD>";
  166. #endif /* VMS */
  167. #endif /* NT */
  168. #endif /* NOSPL */
  169. #endif /* MAC */
  170. #ifndef CCHMAXPATH
  171. #define CCHMAXPATH 257
  172. #endif /* CCHMAXPATH */
  173. char inidir[CCHMAXPATH] = { NUL, NUL }; /* Directory INI file executed from */
  174. #ifdef TNCODE
  175. extern int tn_b_nlm; /* TELNET BINARY newline mode */
  176. #endif /* TNCODE */
  177. #ifndef NOKVERBS
  178. extern struct keytab kverbs[]; /* Table of Kverbs */
  179. extern int nkverbs; /* Number of Kverbs */
  180. #endif /* NOKVERBS */
  181. #ifndef NOPUSH
  182. extern int nopush;
  183. #endif /* NOPUSH */
  184. #ifdef CK_RECALL
  185. extern int cm_recall;
  186. #endif /* CK_RECALL */
  187. extern char *ccntab[];
  188. /* Printer stuff */
  189. extern char *printername;
  190. extern int printpipe;
  191. #ifdef BPRINT
  192. extern int printbidi, pportparity, pportflow;
  193. extern long pportspeed;
  194. #endif /* BPRINT */
  195. #ifdef OS2
  196. _PROTOTYP (int os2getcp, (void) );
  197. _PROTOTYP (int os2getcplist, (int *, int) );
  198. #ifdef OS2MOUSE
  199. extern int tt_mouse;
  200. #endif /* OS2MOUSE */
  201. extern int tt_update, tt_updmode, tt_font, updmode;
  202. extern struct keytab termfont[];
  203. extern int ntermfont;
  204. extern unsigned char colornormal, colorunderline, colorstatus,
  205.     colorhelp, colorselect, colorborder, colorgraphic, colordebug,
  206.     colorreverse, colorcmd;
  207. extern int priority;
  208. extern struct keytab prtytab[];
  209. extern int nprty;
  210. char * cmdmac = NULL;
  211. #endif /* OS2 */
  212. #ifdef VMS
  213. _PROTOTYP (int zkermini, (char *, int, char *) );
  214. #endif /* VMS */
  215. extern long vernum;
  216. extern int inecho, insilence, inbufsize, nvars, inintr;
  217. extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav,
  218.  *cknetv, *clcmds;
  219. #ifdef CK_AUTHENTICATION
  220. extern char * ckathv;
  221. #endif /* CK_AUTHENTICATION */
  222. #ifdef CK_SSL
  223. extern char * cksslv;
  224. #endif /* CK_SSL */
  225. #ifdef CK_ENCRYPTION
  226. #ifndef CRYPT_DLL
  227. extern char * ckcrpv;
  228. #endif /* CRYPT_DLL */
  229. #endif /* CK_ENCRYPTION */
  230. #ifdef TNCODE
  231. extern char *cktelv;
  232. #endif /* TNCODE */
  233. extern int srvidl;
  234. #ifdef OS2
  235. extern char *ckonetv;
  236. extern int interm;
  237. #ifdef CK_NETBIOS
  238. extern char *ckonbiv;
  239. #endif /* CK_NETBIOS */
  240. #ifdef OS2MOUSE
  241. extern char *ckomouv;
  242. #endif /* OS2MOUSE */
  243. #endif /* OS2 */
  244. #ifndef NOLOCAL
  245. extern char *connv;
  246. #endif /* NOLOCAL */
  247. #ifndef NODIAL
  248. extern char *dialv;
  249. #endif /* NODIAL */
  250. #ifndef NOSCRIPT
  251. extern char *loginv;
  252. extern int secho;
  253. #endif /* NOSCRIPT */
  254. #ifndef NODIAL
  255. extern int nmdm, dirline;
  256. extern struct keytab mdmtab[];
  257. #endif /* NODIAL */
  258. extern int network, ttnproto;
  259. #ifdef OS2
  260. /* SET TERMINAL items... */
  261. extern int tt_type, tt_arrow, tt_keypad, tt_wrap, tt_answer, tt_scrsize[];
  262. extern int tt_bell, tt_roll[], tt_ctstmo, tt_cursor, tt_pacing, tt_type_mode;
  263. extern char answerback[];
  264. extern struct tt_info_rec tt_info[]; /* Indexed by terminal type */
  265. extern int max_tt;
  266. #endif /* OS2 */
  267. _PROTOTYP( VOID shotrm, (void) );
  268. _PROTOTYP( int shofea, (void) );
  269. #ifdef OS2
  270. extern int tt_rows[], tt_cols[];
  271. #else /* OS2 */
  272. extern int tt_rows, tt_cols;
  273. #endif /* OS2 */
  274. extern int cmd_rows, cmd_cols;
  275. #ifdef CK_TMPDIR
  276. extern int f_tmpdir; /* Directory changed temporarily */
  277. extern char savdir[]; /* Temporary directory */
  278. #endif /* CK_TMPDIR */
  279. #ifndef NOLOCAL
  280. extern int tt_crd, tt_escape;
  281. #endif /* NOLOCAL */
  282. #ifndef NOCSETS
  283. extern int language, nfilc, tcsr, tcsl, tcs_transp, fcharset;
  284. extern struct keytab fcstab[];
  285. extern struct csinfo fcsinfo[];
  286. #ifndef MAC
  287. extern struct keytab ttcstab[];
  288. #endif /* MAC */
  289. #endif /* NOCSETS */
  290. extern long speed;
  291. #ifndef NOXMIT
  292. extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt;
  293. extern char xmitbuf[];
  294. #endif /* NOXMIT */
  295. extern char **xargv, *versio, *ckxsys, *dftty, *lp;
  296. #ifdef DCMDBUF
  297. extern char *cmdbuf, *atmbuf; /* Command buffers */
  298. #ifndef NOSPL
  299. extern char *savbuf; /* Command buffers */
  300. #endif /* NOSPL */
  301. #else
  302. extern char cmdbuf[], atmbuf[]; /* Command buffers */
  303. #ifndef NOSPL
  304. extern char savbuf[]; /* Command buffers */
  305. #endif /* NOSPL */
  306. #endif /* DCMDBUF */
  307. extern char toktab[], ttname[], psave[];
  308. extern CHAR sstate, feol;
  309. extern int cmflgs, techo, repars, ncmd;
  310. extern struct keytab cmdtab[];
  311. #ifndef NOSETKEY
  312. KEY *keymap;
  313. #ifndef OS2
  314. #define mapkey(x) keymap[x]
  315. #endif /* OS2 */
  316. MACRO *macrotab;
  317. _PROTOTYP( VOID shostrdef, (CHAR *) );
  318. #endif /* NOSETKEY */
  319. extern int cmdlvl;
  320. #ifndef NOSPL
  321. extern struct mtab *mactab;
  322. extern struct keytab mackey[];
  323. extern struct keytab vartab[], fnctab[];
  324. extern int maclvl, nmac, mecho, fndiags, fnerror, fnsuccess;
  325. #endif /* NOSPL */
  326. FILE *tfile[MAXTAKE]; /* TAKE file stack */
  327. char *tfnam[MAXTAKE];
  328. int tfline[MAXTAKE];
  329. int topcmd = -1; /* cmdtab index of current command */
  330. #ifdef DCMDBUF /* Initialization filespec */
  331. char *kermrc = NULL;
  332. #else
  333. char kermrcb[KERMRCL];
  334. char *kermrc = kermrcb;
  335. #endif /* DCMDBUF */
  336. int noherald = 0;
  337. int cm_retry = 1; /* Command retry enabled */
  338. xx_strp xxstring = zzstring;
  339. #ifndef NOXFER
  340. extern int displa, bye_active, protocol, pktlog, remfile, rempipe, unkcs,
  341.   keep, lf_opts, fncnv, pktpaus, autodl, xfrcan, xfrchr, xfrnum, srvtim,
  342.   srvdis, query, retrans, streamed, reliable, crunched, timeouts,
  343.   fnrpath, autopath, rpackets, spackets, epktrcvd, srvping;
  344. #ifdef CK_AUTODL
  345. extern int inautodl, cmdadl;
  346. #endif /* CK_AUTODL */
  347. #ifndef NOSERVER
  348. extern int en_asg, en_cwd, en_cpy, en_del, en_dir, en_fin, en_bye, en_ret,
  349.   en_get, en_hos, en_que, en_ren, en_sen, en_set, en_spa, en_typ, en_who,
  350.   en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
  351. #endif /* NOSERVER */
  352. extern int atcapr,
  353.   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
  354.   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
  355. #ifdef STRATUS
  356. extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
  357. #endif /* STRATUS */
  358. #ifdef CK_PERMS
  359. extern int atlpri, atlpro, atgpri, atgpro;
  360. #endif /* CK_PERMS */
  361. #ifdef CK_LOGIN
  362. extern char * anonfile; /* Anonymous login init file */
  363. extern char * anonroot; /* Anonymous file-system root */
  364. extern char * userfile;                 /* Forbidden user file */
  365. extern int isguest; /* Flag for anonymous user */
  366. #endif /* CK_LOGIN */
  367. #endif /* NOXFER */
  368. #ifdef DCMDBUF
  369. int *xquiet = NULL;
  370. #else
  371. int xquiet[CMDSTKL];
  372. #endif /* DCMDBUF */
  373. #ifndef NOSPL
  374. extern long ck_alarm;
  375. extern char alrm_date[], alrm_time[];
  376. /* Local declarations */
  377. static int nulcmd = 0; /* Flag for next cmd to be ignored */
  378. /* Definitions for predefined macros */
  379. /* First, the single-line macros, installed with addmac()... */
  380. /* IBM-LINEMODE macro */
  381. char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none";
  382. /* FATAL macro */
  383. char *m_fat = "if def \%1 echo \%1, if not = \v(local) 0 hangup, stop 1";
  384. #ifdef CK_SPEED
  385. #ifdef IRIX65
  386. char *m_fast = "set win 30, set rec pack 4000, set prefix cautious";
  387. #else
  388. #ifdef IRIX
  389. /* Because of bug in telnet server */
  390. char *m_fast = "set window 30, set rec pack 4000, set send pack 4000,
  391.  set pref cautious";
  392. #else
  393. #ifdef pdp11
  394. char *m_fast = "set win 3, set rec pack 1024, set prefix cautious";
  395. #else
  396. #ifdef BIGBUFOK
  397. char *m_fast = "set win 30, set rec pack 4000, set prefix cautious";
  398. #else
  399. char *m_fast = "set win 4, set rec pack 2200, set prefix cautious";
  400. #endif /* BIGBUFOK */
  401. #endif /* IRIX */
  402. #endif /* IRIX65 */
  403. #endif /* pdp11 */
  404. #ifdef pdp11
  405. char *m_cautious = "set win 2, set rec pack 512, set prefixing cautious";
  406. #else
  407. char *m_cautious = "set win 4, set rec pack 1000, set prefixing cautious";
  408. #endif /* pdp11 */
  409. char *m_robust = "set win 1, set rec pack 90, set prefixing all, 
  410. set reliable off, set clearchannel off";
  411. #else
  412. #ifdef BIGBUFOK
  413. #ifdef IRIX65
  414. char *m_fast = "set win 30, set rec pack 4000";
  415. #else
  416. #ifdef IRIX
  417. char *m_fast = "set win 30, set rec pack 4000, set send pack 4000";
  418. #else
  419. char *m_fast = "set win 30, set rec pack 4000";
  420. #endif /* IRIX */
  421. #endif /* IRIX65 */
  422. #else /* Not BIGBUFOK */
  423. char *m_fast = "set win 4, set rec pack 2200";
  424. #endif /* BIGBUFOK */
  425. char *m_cautious = "set win 4, set rec pack 1000";
  426. char *m_robust = "set win 1, set rec pack 90, set reliable off";
  427. #endif /* CK_SPEED */
  428. #ifdef VMS
  429. char *m_purge = "run purge \%*";
  430. #endif /* VMS */
  431. #ifdef OS2
  432. char *m_manual = "browse \v(exedir)docs/manual/kermit95.htm";
  433. #endif /* OS2 */
  434. /* Now the multiline macros, defined with addmmac()... */
  435. /* FOR macro */
  436. char *for_def[] = { "_assign _for\v(cmdlevel) { _getargs,",
  437. "define \\\%1 \feval(\%2),:_..top,if \%5 \\\%1 \%3 goto _..bot,",
  438. "\%6,:_..inc,incr \\\%1 \%4,goto _..top,:_..bot,_putargs},",
  439. "def break goto _..bot, def continue goto _..inc,",
  440. "do _for\v(cmdlevel) \%1 \%2 \%3 \%4 { \%5 },_assign _for\v(cmdlevel)",
  441. ""};
  442. /* WHILE macro */
  443. char *whil_def[] = { "_assign _whi\v(cmdlevel) {_getargs,",
  444. ":_..inc,\%1,\%2,goto _..inc,:_..bot,_putargs},",
  445. "_def break goto _..bot, _def continue goto _..inc,",
  446. "do _whi\v(cmdlevel),_assign _whi\v(cmdlevel)",
  447. ""};
  448. /* SWITCH macro */
  449. char *sw_def[] = { "_assign _sw_\v(cmdlevel) {_getargs,",
  450. "_forward \%1,\%2,:default,:_..bot,_putargs},_def break goto _..bot,",
  451. "do _sw_\v(cmdlevel),_assign _sw_\v(cmdlevel)",
  452. ""};
  453. /* XIF macro */
  454. char *xif_def[] = {
  455. "_assign _if\v(cmdlevel) {_getargs,\%1,_putargs},",
  456. "do _if\v(cmdlevel),_assign _if\v(cmdlevel)",
  457. ""};
  458. /*
  459.   Variables declared here for use by other ckuus*.c modules.
  460.   Space is allocated here to save room in ckuusr.c.
  461. */
  462. #ifdef DCMDBUF
  463. struct cmdptr *cmdstk;
  464. int
  465.   *ifcmd  = NULL,
  466.   *count  = NULL,
  467.   *iftest = NULL,
  468.   *intime = NULL,
  469.   *inpcas = NULL,
  470.   *takerr = NULL,
  471.   *merror = NULL;
  472. #else
  473. struct cmdptr cmdstk[CMDSTKL];
  474. int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL], intime[CMDSTKL],
  475.   inpcas[CMDSTKL], takerr[CMDSTKL], merror[CMDSTKL];
  476. #endif /* DCMDBUF */
  477. /* Macro stack */
  478. char *m_line[MACLEVEL] = { NULL, NULL }; /* Stack of macro invocation lines */
  479. char **m_xarg[MACLEVEL]; /* Pointers to arg vector arrays */
  480. int n_xarg[MACLEVEL]; /* Sizes of arg vector arrays */
  481. char *m_arg[MACLEVEL][NARGS]; /* Args of each level */
  482. int macargc[MACLEVEL]; /* Argc of each level */
  483. char *macp[MACLEVEL]; /* Current position in each macro */
  484. char *macx[MACLEVEL]; /* Beginning of each macro def */
  485. char *mrval[MACLEVEL]; /* RETURN value at each level */
  486. int topargc = 0; /* Argc at top level */
  487. char **topxarg = NULL; /* Argv at top level */
  488. char *toparg[MAXARGLIST+2];
  489. /* Global Variables */
  490. char *g_var[GVARS]; /* Global %a..z pointers */
  491. extern char varnam[]; /* %x variable name buffer */
  492. /* Arrays -- Dimension must be 'z' - ARRAYBASE + 1 */
  493. char **a_ptr[28]; /* Array pointers, for arrays a-z */
  494. int a_dim[28]; /* Dimensions for each array */
  495. char **aa_ptr[CMDSTKL][28]; /* Array stack for automatic arrays */
  496. int aa_dim[CMDSTKL][28]; /* Dimensions for each array */
  497. /* INPUT command buffers and variables */
  498. char * inpbuf = NULL; /* Buffer for INPUT and REINPUT */
  499. extern char * inpbp; /* Global/static pointer to it  */
  500. char inchar[2] = { NUL, NUL }; /* Last character that was INPUT */
  501. int  incount = 0; /* INPUT character count */
  502. extern int instatus; /* INPUT status */
  503. static char * i_text[] = { /* INPUT status text */
  504.     "success", "timeout", "interrupted", "internal error", "i/o error"
  505. };
  506. char lblbuf[LBLSIZ]; /* Buffer for labels */
  507. #else  /* NOSPL */
  508. int takerr[MAXTAKE];
  509. #endif /* NOSPL */
  510. static char *prevdir = NULL;
  511. int pacing = 0; /* OUTPUT pacing */
  512. #ifdef DCMDBUF
  513. char *line; /* Character buffer for anything */
  514. char *tmpbuf;
  515. #else
  516. char line[LINBUFSIZ+1];
  517. char tmpbuf[TMPBUFSIZ+1]; /* Temporary buffer */
  518. #endif /* DCMDBUF */
  519. char *tp; /* Temporary buffer pointer */
  520. int timelimit = 0, asktimer = 0; /* Timers for time-limited commands */
  521. #ifdef CK_APC /* Application Program Command (APC) */
  522. int apcactive = APC_INACTIVE;
  523. int apcstatus = APC_OFF; /* OFF by default everywhere */
  524. #ifdef DCMDBUF
  525. char *apcbuf;
  526. #else
  527. char apcbuf[APCBUFLEN];
  528. #endif /* DCMDBUF */
  529. #endif /* CK_APC */
  530. extern char pktfil[],
  531. #ifdef DEBUG
  532.   debfil[],
  533. #endif /* DEBUG */
  534. #ifdef TLOG
  535.   trafil[],
  536. #endif /* TLOG */
  537.   sesfil[];
  538. #ifndef NOFRILLS
  539. extern int rmailf, rprintf; /* REMOTE MAIL & PRINT items */
  540. extern char optbuf[];
  541. #endif /* NOFRILLS */
  542. char *homdir = ""; /* Pointer to home directory string */
  543. char numbuf[20]; /* Buffer for numeric strings. */
  544. extern int noinit;
  545. #ifndef NOSPL
  546. _PROTOTYP( VOID freelocal, (int) );
  547. _PROTOTYP( static long expon, (long, long) );
  548. _PROTOTYP( static long gcd, (long, long) );
  549. _PROTOTYP( static long fact, (long) );
  550. int /* Initialize macro data structures. */
  551. macini() { /* Allocate mactab and preset the first element. */
  552.     int i;
  553.     if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX)))
  554.       return(-1);
  555.     mactab[0].kwd = NULL;
  556.     mactab[0].mval = NULL;
  557.     mactab[0].flgs = 0;
  558.     for (i = 0; i < MACLEVEL; i++)
  559.       localhead[i] = NULL;
  560.     return(0);
  561. }
  562. #endif /* NOSPL */
  563. /*  C M D S R C  --  Returns current command source  */
  564. /*  0 = top level, 1 = file, 2 = macro, -1 = error (shouldn't happen) */
  565. int
  566. cmdsrc() {
  567. #ifndef NOSPL
  568.     if (cmdlvl == 0)
  569.       return(0);
  570.     else if (cmdstk[cmdlvl].src == CMD_MD)
  571.       return(2);
  572.     else if (cmdstk[cmdlvl].src == CMD_TF)
  573.       return(1);
  574.     else
  575.       return(-1);
  576. #else
  577.     if (tlevel < 0)
  578.       return(0);
  579.     else
  580.       return(1);
  581. #endif /* NOSPL */
  582. }
  583. /*  C M D I N I  --  Initialize the interactive command parser  */
  584. static int cmdinited = 0; /* Command parser initialized */
  585. extern int cmdint; /* Interrupts are allowed */
  586. #ifdef CK_AUTODL
  587. int cmdadl = 1; /* Autodownload */
  588. #else
  589. int cmdadl = 0;
  590. #endif /* CK_AUTODL */
  591. char * k_info_dir = NULL; /* Where to find text files */
  592. #ifdef UNIX
  593. static char * txtdir[] = {
  594.     "/usr/local/doc/", /* Linux, SunOS, ... */
  595.     "/usr/share/lib/", /* HP-UX 10.xx... */
  596.     "/usr/share/doc/", /* Other possibilities... */
  597.     "/usr/local/lib/", /* NOTE: Each of these is tried */
  598.     "/usr/local/share/", /* as is, and also with a kermit */
  599.     "/usr/local/share/doc/", /* subdirectory. */
  600.     "/usr/local/share/lib/",
  601.     "/usr/doc/",
  602.     "/opt/",
  603.     "/doc/",
  604.     ""
  605. };
  606. #endif /* UNIX */
  607. VOID
  608. cmdini() {
  609.     int i = 0, x = 0, y = 0, z = 0, skip = 0;
  610.     char * p;
  611. #ifdef TTSPDLIST
  612.     long * ss = NULL;
  613.     extern int nspd;
  614.     extern struct keytab * spdtab;
  615. #endif /* TTSPDLIST */
  616. #ifndef NOSPL
  617. /*
  618.   On stack to allow recursion!
  619. */
  620.     char vnambuf[VNAML]; /* Buffer for variable names */
  621. #endif /* NOSPL */
  622.     if (cmdinited) /* Already initialized */
  623.       return; /* Don't do it again */
  624.     p = getenv("K_INFO_DIRECTORY");
  625.     if (p && *p && strlen(p) <= CKMAXPATH)
  626.       makestr(&k_info_dir,p);
  627.     if (!k_info_dir) {
  628.         p = getenv("K_INFO_DIR");
  629.         if (p && *p && strlen(p) <= CKMAXPATH)
  630.   makestr(&k_info_dir,p);
  631.     }
  632. #ifdef UNIX
  633.     if (k_info_dir) { /* Look for Kermit docs directory */
  634. if (zchki(k_info_dir) == -2) {
  635.     char xbuf[CKMAXPATH+32], *s = "";
  636.     if (ckrchar(k_info_dir) != '/')
  637.       s = "/";
  638.     sprintf(xbuf,"%s%sckermit2.txt",k_info_dir,s);
  639.     if (zchki(xbuf) < 0)
  640.       makestr(&k_info_dir,NULL);
  641. }
  642.     }
  643.     if (!k_info_dir) {
  644. char xbuf[CKMAXPATH+32];
  645. int i;
  646. for (i = 0; *(txtdir[i]); i++) {
  647.     sprintf(xbuf,"%s%s",txtdir[i],"ckermit2.txt");
  648.     if (zchki(xbuf) > 0) {
  649. makestr(&k_info_dir,txtdir[i]);
  650. debug(F110,"k_info_dir 1",k_info_dir,0);
  651. break;
  652.     }
  653.     sprintf(xbuf,"%skermit/%s",txtdir[i],"ckermit2.txt");
  654.     if (zchki(xbuf) > 0) {
  655. sprintf(xbuf,"%skermit/",txtdir[i]);
  656. makestr(&k_info_dir,xbuf);
  657. debug(F110,"k_info_dir 2",k_info_dir,0);
  658. break;
  659.     }
  660. }
  661. if (k_info_dir) { /* Make sure it ends with "/" */
  662.     if (ckrchar(k_info_dir) != '/') {
  663. char xbuf[CKMAXPATH+32];
  664. sprintf(xbuf,"%s/",k_info_dir);
  665. makestr(&k_info_dir,xbuf);
  666.     }
  667. }
  668.     }
  669. #else
  670. #ifdef OS2
  671.     {
  672. char xdir[CKMAXPATH+8], *s = "";
  673.         extern char startupdir[];
  674. xdir[0] = NUL;
  675. if (ckrchar(startupdir) != '/')
  676.   s = "/";
  677.         if (strlen(s) + strlen(startupdir) + 5 < CKMAXPATH + 8 )
  678.   sprintf(xdir,"%s%sDOC/",s,startupdir);
  679.         makestr(&k_info_dir,xdir);
  680.     }
  681. #endif /* OS2 */
  682. #endif /* UNIX */
  683. #ifdef TTSPDLIST
  684.     if (!spdtab && (ss = ttspdlist())) { /* Get speed list if necessary */
  685. int j, k, m = 0, n; /* Create sorted keyword table */
  686. char buf[16];
  687. char * p;
  688. if ((spdtab =
  689.      (struct keytab *) malloc(sizeof(struct keytab) * ss[0]))) {
  690.     for (i = 1; i <= ss[0]; i++) { /* ss[0] = number of elements */
  691. if (ss[i] < 1L) break;    /* Shouldn't happen */
  692. buf[0] = NUL;    /* Make string */
  693. sprintf(buf,"%ld",ss[i]);
  694. if (ss[i] == 8880L)
  695.   strcpy(buf,"75/1200");
  696. if (ss[i] == 134L)
  697.   strcat(buf,".5");
  698. n = strlen(buf);
  699. if ((n > 0) && (p = (char *)malloc(n+1))) {
  700.     if (m > 0) { /* Have at least one in list */
  701. for (j = 0; /* Find slot */
  702.      j < m && strcmp(buf,spdtab[j].kwd) > 0;
  703.      j++
  704.      )
  705.   ;
  706. if (j < m) { /* Must insert */
  707.     for (k = m-1; k >= j; k--) { /* Move others down */
  708. spdtab[k+1].kwd = spdtab[k].kwd;
  709. spdtab[k+1].flgs = spdtab[k].flgs;
  710. spdtab[k+1].kwval = spdtab[k].kwval;
  711.     }
  712. }
  713.     } else /* First one */
  714.       j = 0;
  715.     strcpy(p,buf); /* Add new speed */
  716.     spdtab[j].kwd = p;
  717.     spdtab[j].flgs = 0;
  718.     spdtab[j].kwval = (int) ss[i] / 10;
  719.     m++; /* Count this one */
  720. }
  721.     }
  722. }
  723. nspd = m;
  724.     }
  725. #endif /* TTSPDLIST */
  726. #ifndef NOSPL
  727.     /* Allocate INPUT command buffer */
  728.     if (!inpbuf) {
  729. if (!(inpbuf = (char *) malloc(INPBUFSIZ+1)))
  730.   fatal("cmdini: no memory for INPUT buffer");
  731.     }
  732.     for (x = 0; x < INPBUFSIZ; x++) /* Initialize it */
  733.       inpbuf[x] = NUL;
  734.     inpbp = inpbuf; /* Initialize pointer */
  735.     inbufsize = INPBUFSIZ; /* and size. */
  736. #endif /* NOSPL */
  737. #ifdef DCMDBUF
  738.     if (cmsetup() < 0) fatal("Can't allocate command buffers!");
  739. #ifndef NOSPL
  740.     /* Allocate command stack allowing command parser to call itself */
  741.     if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL)))
  742.       fatal("cmdini: no memory for cmdstk");
  743.     if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL)))
  744.       fatal("cmdini: no memory for ifcmd");
  745.     if (!(count = (int *) malloc(sizeof(int)*CMDSTKL)))
  746.       fatal("cmdini: no memory for count");
  747.     if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL)))
  748.       fatal("cmdini: no memory for iftest");
  749.     if (!(intime = (int *) malloc(sizeof(int)*CMDSTKL)))
  750.       fatal("cmdini: no memory for intime");
  751.     if (!(inpcas = (int *) malloc(sizeof(int)*CMDSTKL)))
  752.       fatal("cmdini: no memory for inpcas");
  753.     if (!(takerr = (int *) malloc(sizeof(int)*CMDSTKL)))
  754.       fatal("cmdini: no memory for takerr");
  755.     if (!(merror = (int *) malloc(sizeof(int)*CMDSTKL)))
  756.       fatal("cmdini: no memory for merror");
  757.     if (!(xquiet = (int *) malloc(sizeof(int)*CMDSTKL)))
  758.       fatal("cmdini: no memory for xquiet");
  759.     if (!kermrc)
  760.       if (!(kermrc = (char *) malloc(KERMRCL+1)))
  761. fatal("cmdini: no memory for kermrc");
  762. #ifdef CK_APC
  763. /* Application Program Command buffer */
  764.     if (!(apcbuf = malloc(APCBUFLEN + 1)))
  765. fatal("cmdini: no memory for apcbuf");
  766. #endif /* CK_APC */
  767. #endif /* NOSPL */
  768. /* line[] and tmpbuf[] are the two string buffers used by the command parser */
  769.     if (!(line = malloc(LINBUFSIZ + 1)))
  770. fatal("cmdini: no memory for line");
  771.     if (!(tmpbuf = malloc(LINBUFSIZ + 1)))
  772. fatal("cmdini: no memory for tmpbuf");
  773. #endif /* DCMDBUF */
  774. #ifndef NOSPL
  775. #ifdef CK_MINPUT
  776.     { /* Initialize MINPUT pointers */
  777. int i;
  778. extern char *ms[];
  779. for (i = 0; i < MINPMAX; i++)
  780.   ms[i] = NULL;
  781.     }
  782. #endif /* CK_MINPUT */
  783.     if (macini() < 0) /* Allocate macro buffers */
  784.       fatal("Can't allocate macro buffers!");
  785.     ifcmd[0] = 0; /* Command-level related variables. */
  786.     iftest[0] = 0; /* Initialize variables at top level */
  787.     count[0] = 0; /* of stack... */
  788.     intime[0] = 0;
  789.     inpcas[0] = 0;
  790.     takerr[0] = 0;
  791.     merror[0] = 0;
  792.     xquiet[0] = quiet;
  793. #endif /* NOSPL */
  794. #ifndef NOSPL
  795.     cmdlvl = 0; /* Initialize the command stack */
  796.     cmdstk[cmdlvl].src = CMD_KB; /* Source is console */
  797.     cmdstk[cmdlvl].lvl = 0; /* Level is 0 */
  798.     cmdstk[cmdlvl].ccflgs = 0; /* No flags */
  799. #endif /* NOSPL */
  800.     tlevel = -1; /* Take file level = keyboard */
  801.     for (i = 0; i < MAXTAKE; i++) /* Initialize command file names */
  802.       tfnam[i] = NULL;
  803.     cmsetp(ckprompt);  /* Set up C-Kermit's prompt */
  804.                                         /* Can't set IKSD prompt here since */
  805.                                         /* we do not yet know if we are IKSD */
  806. #ifndef NOSPL
  807.     initmac(); /* Initialize macro table */
  808. /* Predefine built-in one-line macros */
  809.     addmac("ibm-linemode",m_ibm); /* IBM-LINEMODE */
  810.     addmac("fatal",m_fat); /* FATAL macro */
  811.     y = addmac("fast",m_fast); /* FAST macro */
  812.     addmac("cautious",m_cautious); /* CAUTIOUS macro */
  813.     addmac("robust",m_robust); /* ROBUST macro */
  814. #ifdef OS2
  815.     addmac("manual",m_manual);          /* MANUAL macro */
  816. #endif /* OS2 */
  817. #ifdef VMS
  818.     addmac("purge",m_purge); /* PURGE macro */
  819. #endif /* VMS */
  820. /*
  821.   Predefine built-in multiline macros; these are top-level commands
  822.   that are implemented internally as macros.  NOTE: When adding a new
  823.   one of these, remember to update the END and RETURN commands to
  824.   account for it, or else END and RETURN from within it won't work right.
  825. */
  826.     x = addmmac("_forx",for_def); /* FOR macro */
  827.     if (x > -1) mactab[x].flgs = CM_INV;
  828.     x = addmmac("_xif",xif_def); /* XIF macro */
  829.     if (x > -1) mactab[x].flgs = CM_INV;
  830.     x = addmmac("_while",whil_def); /* WHILE macro */
  831.     if (x > -1) mactab[x].flgs = CM_INV;
  832.     x = addmmac("_switx",sw_def); /* SWITCH macro */
  833.     if (x > -1) mactab[x].flgs = CM_INV;
  834. /* Fill in command-line argument vector */
  835.     sprintf(vnambuf,"\&@[%d]",xargs);  /* Command line argument vector */
  836.     if (inserver) { /* (except in IKSD) */
  837. y = -1;
  838. xargs = 0;
  839.     } else
  840.       y = arraynam(vnambuf,&x,&z); /* goes in array &@[] */
  841.     if (y > -1) {
  842. int j = -1;
  843. int yy = 0;
  844. dclarray((char)x,z); /* Declare the array */
  845. #ifndef NOTAKEARGS
  846. sprintf(vnambuf,"\&_[%d]",z);  /* Macro argument vector */
  847. yy = arraynam(vnambuf,&x,&z); /* goes in array &_[] */
  848. if (yy > -1) /* Name is OK */
  849.   dclarray((char)x,z); /* Declare the array */
  850. #endif /* NOTAKEARGS */
  851. skip = 0;
  852. for (i = 0; i < xargs; i++) { /* Fill the arrays */
  853.     sprintf(vnambuf,"\&@[%d]",i);
  854.     addmac(vnambuf,xargv[i]);
  855.     if (cfilef && i == 0)
  856.       continue;
  857. #ifdef KERBANG
  858.     if (skip) {
  859. j = 0;
  860. skip = 0;
  861. continue;
  862.     }
  863. #endif /* KERBANG */
  864.     if (j < 0 && /* Assign items after "=" or "--"*/
  865. (!strcmp(xargv[i],"=") || !strcmp(xargv[i],"--"))
  866. ) {
  867. j = 0; /* to %1..%9 */
  868. #ifdef KERBANG
  869.     } else if (j < 0 && !strcmp(xargv[i],"+")) {
  870. skip = 1;
  871. continue;
  872. #endif /* KERBANG */
  873.     } else if (j > -1) {
  874. j++;
  875. if (j <= 9) {
  876.     vnambuf[0] = '\';
  877.     vnambuf[1] = '%';
  878.     vnambuf[2] = (char)(j+'0');
  879.     vnambuf[3] = NUL;
  880.     addmac(vnambuf,xargv[i]);
  881. }
  882. if (yy > -1)
  883.   makestr(&(toparg[j]),xargv[i]);
  884.     }
  885. }
  886. if (cfilef) {
  887.     addmac("\%0",cmdfil);
  888.     if (yy > -1)
  889.       makestr(&(toparg[0]),cmdfil);
  890. } else {
  891.     addmac("\%0",xargv[0]);
  892.     if (yy > -1)
  893.       makestr(&(toparg[0]),xargv[0]);
  894. }
  895. if (yy > -1) {
  896.     topargc = (j < 0) ? 1 : j + 1;
  897.     topxarg = toparg;
  898. } else {
  899.     topargc = 0;
  900.     topxarg = NULL;
  901. }
  902. a_dim[0] = topargc - 1;
  903. a_ptr[0] = topxarg;
  904.     }
  905.     *vnambuf = NUL;
  906. #endif /* NOSPL */
  907. /* Get our home directory now.  This needed in lots of places. */
  908.     homdir = zhome();
  909.     cmdinited = 1;
  910. }
  911. VOID
  912. doinit() {
  913.     int x = 0, ok = 0;
  914. #ifdef OS2
  915.     char * ptr = 0;
  916. #endif /* OS2 */
  917.     if (!cmdinited)
  918.       cmdini();
  919. #ifdef MAC
  920.     return; /* Mac Kermit has no init file */
  921. #else /* !MAC */
  922. /* If skipping init file ('-Y' on Kermit command line), return now. */
  923.     if (noinit) {
  924. kermrc[0] = '';
  925. inidir[0] = '';
  926. /*
  927.   But returning from here results in inidir[] never being set to anything.
  928.   Instead it should be set to wherever the init file *would* have been
  929.   executed from.  So this bit of code should be removed, and then we should
  930.   sprinkle "if (noinit)" tests throughout the following code until we have
  931.   set inidir[], and then return without actually taking the init file.
  932. */
  933. return;
  934.     }
  935. #ifdef OS2
  936. /*
  937.   The -y init file must be fully specified or in the current directory.
  938.   KERMRC is looked for via INIT, DPATH and PATH in that order.  Finally, our
  939.   own executable file path is taken and the .EXE suffix is replaced by .INI
  940.   and this is tried as the initialization file.
  941. */
  942.     if (rcflag) {
  943. ckstrncpy(line,kermrc,LINBUFSIZ+1);
  944.     } else {
  945.         char * env = 0;
  946. #ifdef NT
  947. env = getenv("K95.KSC");
  948. #else
  949. env = getenv("K2.KSC");
  950. #endif /* NT */
  951.         if (!env) {
  952. #ifdef NT
  953.             env = getenv("K95.INI");
  954. #else
  955.             env = getenv("K2.INI");
  956. #endif /* NT */
  957.         }
  958. if (!env)
  959.   env = getenv("CKERMIT.INI");
  960. if (!env)
  961.   env = getenv("CKERMIT_INI");
  962.         line[0] = '';
  963. if (env)
  964.   ckstrncpy(line,env,LINBUFSIZ+1);
  965. if (line[0] == 0)
  966.   _searchenv(kermrc,"INIT",line);
  967. if (line[0] == 0)
  968.   _searchenv(kermrc,"DPATH",line);
  969. if (line[0] == 0)
  970.   _searchenv(kermrc,"PATH",line);
  971. if (line[0] == 0) {
  972.     char *pgmptr = GetLoadPath();
  973.     if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) {
  974. lp = strrchr(pgmptr, '\');
  975.                 if (lp) {
  976.                     strncpy(line, pgmptr, lp - pgmptr);
  977. #ifdef NT
  978.                     strcpy(line + (lp - pgmptr), "\k95.ini");
  979. #else /* NT */
  980.                     strcpy(line + (lp - pgmptr), "\k2.ini");
  981. #endif /* NT */
  982.                 } else {
  983.                     lp = strrchr(pgmptr, '.');
  984.                     if (lp) {
  985.                         strncpy(line, pgmptr, lp - pgmptr);
  986.                         strcpy(line + (lp - pgmptr), ".ini");
  987.                     }
  988.                 }
  989.     }
  990. }
  991.     }
  992.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  993. ok = 1;
  994.         tlevel = 0;
  995. tfline[tlevel] = 0;
  996. if (tfnam[tlevel] = malloc(strlen(line)+1))
  997.   strcpy(tfnam[tlevel],line);
  998. #ifndef NOSPL
  999. cmdlvl++;
  1000. cmdstk[cmdlvl].src = CMD_TF;
  1001. cmdstk[cmdlvl].lvl = tlevel;
  1002. cmdstk[cmdlvl].ccflgs = 0;
  1003. ifcmd[cmdlvl] = 0;
  1004. iftest[cmdlvl] = 0;
  1005. count[cmdlvl] =  count[cmdlvl-1]; /* Inherit from previous level */
  1006. intime[cmdlvl] = intime[cmdlvl-1];
  1007. inpcas[cmdlvl] = inpcas[cmdlvl-1];
  1008. takerr[cmdlvl] = takerr[cmdlvl-1];
  1009. merror[cmdlvl] = merror[cmdlvl-1];
  1010. xquiet[cmdlvl] = quiet;
  1011. #endif /* NOSPL */
  1012.         debug(F110,"doinit init file",line,0);
  1013.     } else {
  1014.         debug(F100,"doinit no init file","",0);
  1015.     }
  1016.     ckstrncpy(kermrc,line,KERMRCL);
  1017.     for (ptr = kermrc; *ptr; ptr++) /* Convert backslashes to slashes */
  1018.        if (*ptr == '\')
  1019.          *ptr = '/';
  1020. #else /* not OS2 */
  1021.     lp = line;
  1022.     lp[0] = '';
  1023.     debug(F101,"doinit rcflag","",rcflag);
  1024. #ifdef GEMDOS
  1025.     zkermini(line, rcflag, kermrc);
  1026. #else
  1027. #ifdef VMS
  1028.     zkermini(line,LINBUFSIZ,kermrc);
  1029. #else /* not VMS */
  1030. #ifdef CK_LOGIN
  1031.     debug(F101,"doinit isguest","",isguest);
  1032.     if (isguest)
  1033.       strcpy(lp, anonfile ? anonfile : kermrc);
  1034.     else
  1035. #endif /* CK_LOGIN */
  1036.       if (rcflag) { /* If init file name from cmd line */
  1037.   strcpy(lp,kermrc); /* use it, */
  1038.       } else { /* otherwise... */
  1039. #ifdef CK_INI_A /* If we've a system-wide init file */
  1040.   /* And it takes precedence over the user's... */
  1041.   ckstrncpy(lp,CK_SYSINI,KERMRCL); /* Use it */
  1042.   if (zchki(lp) < 0) { /* (if it exists...) */
  1043. #endif /* CK_INI_A */
  1044.       line[0] = NUL;
  1045.       if (homdir) { /* Home directory for init file. */
  1046.   strcpy(lp,homdir);
  1047. #ifdef STRATUS
  1048.   strcat(lp,">"); /* VOS separates dirs with >'s */
  1049. #else
  1050.   if (lp[0] == '/') strcat(lp,"/");
  1051. #endif /* STRATUS */
  1052.       }
  1053.       strcat(lp,kermrc); /* Append the default file name */
  1054. #ifdef CK_INI_A
  1055.   }
  1056. #endif /* CK_INI_A */
  1057.       }
  1058. #ifdef CK_INI_B /* System-wide init defined? */
  1059.     /* But user's ini file takes precedence */
  1060.     if (zchki(lp) < 0) /* If user doesn't have her own, */
  1061.       ckstrncpy(lp,CK_SYSINI,KERMRCL); /* use system-wide one. */
  1062. #endif /* CK_INI_B */
  1063. #endif /* VMS */
  1064. #endif /* GEMDOS */
  1065. #ifdef AMIGA
  1066.     reqoff(); /* Disable requestors */
  1067. #endif /* AMIGA */
  1068.     debug(F110,"doinit ini file is",line,0);
  1069.     if ((tfile[0] = fopen(line,"r")) != NULL) { /* Try to open init file. */
  1070. ok = 1;
  1071. tlevel = 0;
  1072. tfline[tlevel] = 0;
  1073. if (tfnam[tlevel] = malloc(strlen(line)+1))
  1074.   strcpy(tfnam[tlevel],line);
  1075. ckstrncpy(kermrc,line,KERMRCL);
  1076. #ifndef NOSPL
  1077. cmdlvl++;
  1078. ifcmd[cmdlvl] = 0;
  1079. iftest[cmdlvl] = 0;
  1080. count[cmdlvl] =  count[cmdlvl-1]; /* Inherit from previous level */
  1081. intime[cmdlvl] = intime[cmdlvl-1];
  1082. inpcas[cmdlvl] = inpcas[cmdlvl-1];
  1083. takerr[cmdlvl] = takerr[cmdlvl-1];
  1084. merror[cmdlvl] = merror[cmdlvl-1];
  1085. xquiet[cmdlvl] = quiet;
  1086. debug(F101,"doinit open ok","",cmdlvl);
  1087. cmdstk[cmdlvl].src = CMD_TF;
  1088. cmdstk[cmdlvl].lvl = tlevel;
  1089. cmdstk[cmdlvl].ccflgs = 0;
  1090. #endif /* NOSPL */
  1091.     } else if (rcflag) {
  1092. /* Print an error message only if a specific file was asked for. */
  1093. printf("?%s - %sn", ck_errstr(), line);
  1094.     }
  1095. #ifdef datageneral
  1096. /* If CKERMIT.INI not found in home directory, look in searchlist */
  1097.     if (homdir && (tlevel < 0)) {
  1098.      strcpy(lp,kermrc);
  1099. if ((tfile[0] = fopen(line,"r")) != NULL) {
  1100.     ok = 1;
  1101.     tlevel = 0;
  1102.     tfline[tlevel] = 0;
  1103.     if (tfnam[tlevel] = malloc(strlen(line)+1))
  1104.       strcpy(tfnam[tlevel],line);
  1105. #ifndef NOSPL
  1106.     cmdlvl++;
  1107.     cmdstk[cmdlvl].src = CMD_TF;
  1108.     cmdstk[cmdlvl].lvl = tlevel;
  1109.     cmdstk[cmdlvl].ccflgs = 0;
  1110.     ifcmd[cmdlvl] = 0;
  1111.     iftest[cmdlvl] = 0;
  1112.     count[cmdlvl] =  count[cmdlvl-1]; /* Inherit from previous level */
  1113.     intime[cmdlvl] = intime[cmdlvl-1];
  1114.     inpcas[cmdlvl] = inpcas[cmdlvl-1];
  1115.     takerr[cmdlvl] = takerr[cmdlvl-1];
  1116.     merror[cmdlvl] = merror[cmdlvl-1];
  1117.     xquiet[cmdlvl] = quiet;
  1118. #endif /* NOSPL */
  1119. }
  1120.     }
  1121. #endif /* datageneral */
  1122. #ifdef AMIGA /* Amiga... */
  1123.     reqpop(); /* Restore requestors */
  1124. #endif /* AMIGA */
  1125. #endif /* OS2 */
  1126. #endif /* MAC */
  1127.     /* Assign value to inidir */
  1128.     if (!ok) {
  1129. inidir[0] = NUL;
  1130.     } else {
  1131. strcpy(inidir, kermrc);
  1132. x = strlen(inidir);
  1133. if (x > 0) {
  1134.     int i;
  1135.     for (i = x - 1; i > 0; i-- ) {
  1136. if (inidir[i] ==
  1137. #ifdef MAC
  1138.     ':'
  1139. #else
  1140. #ifdef UNIX
  1141.     '/'
  1142. #else
  1143. #ifdef OSK
  1144.     '/'
  1145. #else
  1146. #ifdef STRATUS
  1147.     '>'
  1148. #else
  1149. #ifdef VMS
  1150.     ']' || inidir[i] == ':'
  1151. #else
  1152. #ifdef datageneral
  1153.     ':'
  1154. #else
  1155. #ifdef OS2
  1156.     '/' || inidir[i+1] == '\'
  1157. #else
  1158. #ifdef AMIGA
  1159.     '/' || inidir[i+1] == ':'
  1160. #endif /* AMIGA */
  1161. #endif /* OS2 */
  1162. #endif /* datageneral */
  1163. #endif /* VMS */
  1164. #endif /* STRATUS */
  1165. #endif /* OSK */
  1166. #endif /* UNIX */
  1167. #endif /* MAC */
  1168.     ) {
  1169.     inidir[i+1] = NUL;
  1170.     break;
  1171. }
  1172.     }
  1173. }
  1174.     }
  1175. }
  1176. VOID
  1177. doiksdinit() {
  1178. #ifdef CK_SSL
  1179.     /* IKSD doesn't request client certs */
  1180.     ssl_verify_flag = SSL_VERIFY_NONE;
  1181. #endif /* CK_SSL */
  1182.     if (!cmdinited)
  1183.       cmdini();
  1184. #ifdef IKSDCONF
  1185. #ifdef OS2
  1186.     line[0] = '';
  1187.     _searchenv(iksdconf,"INIT",line);
  1188.     if (line[0] == 0)
  1189.       _searchenv(iksdconf,"DPATH",line);
  1190.     if (line[0] == 0)
  1191.       _searchenv(iksdconf,"PATH",line);
  1192.     if (line[0] == 0) {
  1193.         char *pgmptr = GetLoadPath();
  1194.         if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) {
  1195.             lp = strrchr(pgmptr, '\');
  1196.             if (lp) {
  1197.                 strncpy(line, pgmptr, lp - pgmptr);
  1198.                 strcpy(line + (lp - pgmptr + 1), "\");
  1199.                 strcpy(line + (lp - pgmptr + 1), iksdconf);
  1200.             } else {
  1201.                 lp = strrchr(pgmptr, '.');
  1202.                 if (lp) {
  1203.                     strncpy(line, pgmptr, lp - pgmptr);
  1204.                     strcpy(line + (lp - pgmptr), ".ksc");
  1205.                 }
  1206.             }
  1207.         }
  1208.     }
  1209.     debug(F110,"doiksdinit() line",line,0);
  1210.     tfile[0] = fopen(line,"r");
  1211. #else /* OS2 */
  1212.     tfile[0] = fopen(iksdconf,"r");
  1213. #endif /* OS2 */
  1214.     if (tfile[0] != NULL) {
  1215.         tlevel = 0;
  1216. tfline[tlevel] = 0;
  1217. if (tfnam[tlevel] = malloc(strlen(line)+1))
  1218.   strcpy(tfnam[tlevel],iksdconf);
  1219. #ifndef NOSPL
  1220. cmdlvl++;
  1221. cmdstk[cmdlvl].src = CMD_TF;
  1222. cmdstk[cmdlvl].lvl = tlevel;
  1223. cmdstk[cmdlvl].ccflgs = 0;
  1224. ifcmd[cmdlvl]  = 0;
  1225. iftest[cmdlvl] = 0;
  1226. count[cmdlvl]  = count[cmdlvl-1]; /* Inherit from previous level */
  1227. intime[cmdlvl] = intime[cmdlvl-1];
  1228. inpcas[cmdlvl] = inpcas[cmdlvl-1];
  1229. takerr[cmdlvl] = takerr[cmdlvl-1];
  1230. merror[cmdlvl] = merror[cmdlvl-1];
  1231. xquiet[cmdlvl] = quiet;
  1232. #endif /* NOSPL */
  1233.         debug(F110,"doiksdinit file ok",iksdconf,0);
  1234.     } else {
  1235.         debug(F110,"doiksdinit open failed",iksdconf,0);
  1236.     }
  1237. #endif /* IKSDCONF */
  1238. }
  1239. #ifndef NOSPL
  1240. /*
  1241.   G E T N C M
  1242.   Get next command from current macro definition.  Command is copied
  1243.   into string pointed to by argument s, max length n.   Returns:
  1244.    0 if a string was copied;
  1245.   -1 if there was no string to copy.
  1246. */
  1247. int
  1248. getncm(s,n) char *s; int n; {
  1249.     int y, /* Character counter */
  1250. #ifdef COMMENT
  1251.     quote = 0,
  1252. #endif /* COMMENT */
  1253.     kp = 0, /* Brace up-down counter */
  1254.     pp = 0; /* Parenthesis up-down counter */
  1255.     char *s2; /* Copy of destination pointer */
  1256.     s2 = s; /* Initialize string pointers */
  1257.     *s = NUL; /* and destination buffer */
  1258.     debug(F101,"getncm dest length","",n);
  1259.     for (y = 0; /* Loop for n bytes max */
  1260.    macp[maclvl] && *macp[maclvl] && y < n;
  1261.  y++, s++, macp[maclvl]++) {
  1262. *s = *macp[maclvl]; /* Get next char from macro def */
  1263. /* debug(F000,"char","",*s); */
  1264. #ifdef COMMENT
  1265. /*
  1266.   The intention here was to allow quoting of commas, braces, etc,
  1267.   in macro definitions, e.g. "define rows mode co80,%1".  And it
  1268.   works, but it breaks just about everything else.
  1269. */
  1270. if (*s == CMDQ && quote == 0) { /* Allow for quoting of */
  1271.     quote = 1; /* braces, commas, etc. */
  1272.     continue;
  1273. }
  1274. #endif /* COMMENT */
  1275. /*
  1276.   Allow braces around macro definition to prevent commas from being turned to
  1277.   end-of-lines and also treat any commas within parens as text so that
  1278.   multiple-argument functions won't cause the command to break prematurely.
  1279. */
  1280. #ifdef COMMENT
  1281. if (!quote) {
  1282. #endif /* COMMENT */
  1283.     if (*s == '{') kp++; /* Count braces */
  1284.     if (*s == '}') kp--;
  1285.     if (*s == '(') pp++; /* Count parentheses. */
  1286.     if (*s == ')') pp--;
  1287.     if (*s == ',' && pp <= 0 && kp <= 0) {
  1288. macp[maclvl]++; /* Comma not in {} or () */
  1289. debug(F110,"next cmd",s,0);
  1290. kp = pp = 0; /* so we have the next command */
  1291. break;
  1292.     }
  1293. #ifdef COMMENT
  1294. }
  1295. #endif /* COMMENT */
  1296.     } /* Reached end. */
  1297.     if (*s2 == NUL) { /* If nothing was copied, */
  1298. debug(F100,"getncm eom","",0);
  1299. popclvl(); /* pop command level. */
  1300. return(-1);
  1301.     } else { /* otherwise, tack CR onto end */
  1302. *s++ = CR;
  1303. *s = '';
  1304. if (mecho && pflag) /* If MACRO ECHO ON, echo the cmd */
  1305.   printf("%sn",s2);
  1306. debug(F110,"getncm returns ptr to",s2,0);
  1307.     }
  1308.     return(0);
  1309. }
  1310. /*  D O M A C  --  Define and then execute a macro */
  1311. int
  1312. domac(name, def, flags) char *name, *def; int flags; {
  1313.     int x, m;
  1314. #ifdef OS2
  1315.     extern int term_io;
  1316.     int term_io_sav = term_io;
  1317.     term_io = 0; /* Disable Terminal Emulator I/O */
  1318. #endif /* OS2 */
  1319.     m = maclvl; /* Current macro stack level */
  1320.     debug(F101,"domac entry maclvl","",maclvl);
  1321.     x = addmac(name, def); /* Define a new macro */
  1322.     if (x > -1) { /* If successful, */
  1323. dodo(x,NULL,flags); /* start it (increments maclvl). */
  1324. while (maclvl > m) { /* Keep going till done with it, */
  1325.     debug(F101,"domac loop maclvl 1","",maclvl);
  1326.     sstate = (CHAR) parser(1); /* parsing & executing each command, */
  1327.     debug(F101,"domac loop maclvl 2","",maclvl);
  1328.     if (sstate) proto(); /* including protocol commands. */
  1329. }
  1330. debug(F101,"domac loop exit maclvl","",maclvl);
  1331.     }
  1332. #ifdef OS2
  1333.     term_io = term_io_sav;
  1334. #endif /* OS2 */
  1335.     return(success);
  1336. }
  1337. #endif /* NOSPL */
  1338. /*
  1339.   G E T N C T
  1340.   Get next command from TAKE (command) file.
  1341.   Call with:
  1342.    s     Pointer to buffer to read into
  1343.    n     Length of buffer
  1344.    f     File descriptor of file to read from
  1345.    flag  0 == keep line terminator on and allow continuation
  1346.          1 == discard line terminator and don't allow continuation
  1347.   Call with flag == 0 to read a command from a TAKE file;
  1348.   Call with flag != 0 to read a line from a dialing or network directory.
  1349.   In both cases, trailing comments and/or trailing whitespace is/are stripped.
  1350.   If flag == 0, continued lines are combined into one line.  A continued line
  1351.   is one that ends in hypen, or any line in a "block", which starts with "{"
  1352.   at the end of a line and ends with a matching "}" at the beginning of a
  1353.   subsequent line; blocks may be nested.
  1354.   Returns:
  1355.    0 if a string was copied,
  1356.   -1 on EOF,
  1357.   -2 on malloc failure
  1358.   -3 if line is not properly terminated
  1359.   -4 if (possibly continued) line is too long.
  1360. */
  1361. static char * lpx = NULL;
  1362. static int lpxlen = 0;
  1363. int
  1364. getnct(s,n,f,flag) char *s; int n; FILE *f; int flag; {
  1365.     int i = 0, len = 0, buflen = 0;
  1366.     char c = NUL, cc = NUL, ccl = NUL, ccx = NUL, *s2 = NULL;
  1367.     char *lp = NULL, *lpx = NULL, *lp2 = NULL, *lp3 = NULL, *lastcomma = NULL;
  1368.     int bc = 0; /* Block counter */
  1369.     s2 = s; /* Remember original pointer */
  1370.     buflen = n; /* Remember original buffer length */
  1371.     debug(F101,"getnct","",n);
  1372.     if (n < 0)
  1373.         return(-2);
  1374.     /* Allocate a line buffer only if we don't have one that's big enough */
  1375.     if (lpx && (n > lpxlen)) { /* Have one already */
  1376. free(lpx); /* But it's not big enough */
  1377. lpx = NULL; /* Free current one */
  1378. lpxlen = 0;
  1379.     }
  1380.     if (!lpx) { /* Get new one */
  1381. if (!(lpx = (char *) malloc(n))) {
  1382.     debug(F101,"getnct malloc failure","",0);
  1383.     printf("?Memory allocation failure [getnct]n");
  1384.     return(-2);
  1385. }
  1386. lpxlen = n;
  1387.     }
  1388.     lp2 = lpx;
  1389. #define KLUDGE /* See below */
  1390. #ifdef KLUDGE
  1391.     lp2++;
  1392. #endif /* KLUDGE */
  1393.     while (1) { /* Loop to read lines from file */
  1394. if (fgets(lp2,n,f) == NULL) { /* Read a line into lp2 */
  1395.     debug(F100,"getnct fgets EOF","",0); /* EOF */
  1396.     free(lpx); /* Free temporary storage */
  1397.     lpx = NULL;
  1398.     *s = NUL; /* Make destination be empty */
  1399.     return(-1); /* Return failure code */
  1400. }
  1401. #ifndef NODIAL
  1402. if (flag) /* Count this line */
  1403.   dirline++;
  1404. else
  1405. #endif /* NODIAL */
  1406.   tfline[tlevel]++;
  1407. len = strlen(lp2) - 1; /* Position of line terminator */
  1408. debug(F111,"getnct fgets ok",lp2,len);
  1409. if (len == 0 && lp2[0] != 'n') { /* Last line in file has one char */
  1410.     lp2[++len] = 'n'; /* that is not a newline */
  1411.     lp2[len] = NUL;
  1412. }
  1413. if (len < 0)
  1414.   len = 0;
  1415. if (techo && pflag) /* If TAKE ECHO ON, */
  1416.   printf("%3d. %s", /* echo it this line. */
  1417. #ifndef NODIAL
  1418.  flag ? dirline :
  1419. #endif /* NODIAL */
  1420.  tfline[tlevel],
  1421.  lp2
  1422.  );
  1423.         lp3 = lp2; /* Working pointer */
  1424. i = len; /* Get first nonwhitespace character */
  1425. while (i > 0 && *lp3 == SP || *lp3 == HT) {
  1426.     i--;
  1427.     lp3++;
  1428. }
  1429. if (i == 0 && bc > 0) /* Blank line in {...} block */
  1430.   continue;
  1431. /* Isolate, remove, and check terminator */
  1432. c = lp2[len]; /* Value of line terminator */
  1433. debug(F101,"getnct terminator","",c);
  1434. if (c < LF || c > CR) { /* It's not a terminator */
  1435.     debug(F111,"getnct bad line",lp2,c);
  1436.     if (feof(f) && len > 0 && len < n) {
  1437. /* Kludge Alert... */
  1438. if (!quiet)
  1439.   printf("WARNING: Last line of %s lacks terminatorn",
  1440.  s2 == cmdbuf ? "command file" : "directory file");
  1441. c = lp2[++len] = 'n'; /* No big deal - supply one. */
  1442.     } else { /* Something's wrong, fail. */
  1443. free(lpx);
  1444. lpx = NULL;
  1445. return(-3);
  1446.     }
  1447. }
  1448. /* Trim trailing whitespace */
  1449. for (i = len - 1; i > -1 && lp2[i] <= SP; i--) /* Trim */
  1450.   ;
  1451. debug(F101,"getnct i","",i);
  1452. lp2[i+1] = NUL; /* Terminate the string */
  1453. debug(F110,"getnct lp2",lp2,0);
  1454. lp = lp2; /* Make a working pointer */
  1455. /* Remove trailing or full-line comment */
  1456. while (cc = *lp) {
  1457.     if (cc == ';' || cc == '#') { /* Comment introducer? */
  1458. if (lp == lp2) { /* First char on line */
  1459.     *lp = NUL;
  1460.     break;
  1461. } else if (*(lp - 1) == SP || *(lp - 1) == HT) {
  1462.     lp--;
  1463.     *lp = NUL; /* Or preceded by whitespace */
  1464.     break;
  1465. }
  1466.     }
  1467.     lp++;
  1468. }
  1469. if (lp > lp2)
  1470.   lp--; /* Back up over the NUL */
  1471. /* Now trim any space that preceded the comment */
  1472. while ((*lp == SP || *lp == HT) && lp >= lp2) {
  1473.     *lp = NUL;
  1474.     if (lp <= lp2)
  1475.       break;
  1476.     lp--;
  1477. }
  1478. debug(F110,"getnct comment trimmed",lp2,0);
  1479. len = strlen(lp2); /* Length after trimming */
  1480. if (n - len < 2) { /* Check remaining space */
  1481.     debug(F111,"getnct command too long",s2,buflen);
  1482.     printf("?Line too long, maximum length: %d.n",buflen);
  1483.     free(lpx);
  1484.     return(-4);
  1485. }
  1486. ccl = (len > 0) ? lp2[len-1] : 0;     /* Last character in line */
  1487. ccx = (len > 1) ? lp2[len-2] : 0;     /* Penultimate char in line */
  1488. #ifdef KLUDGE
  1489. /*
  1490.   If it is a command and it begins with a token (like ! or .) that is not
  1491.   followed by a space, insert a space now; otherwise cmkey() can get might
  1492.   confused.
  1493. */
  1494. if (s == s2 && !flag) {
  1495.     char *p = toktab;
  1496.     while (*p) {
  1497. if (*p == *lp3 && *(p+1) != SP) {
  1498.     *lp3-- = SP;
  1499.     *lp3 = *p;
  1500.     if (lp3 < lp2) {
  1501. lp2--;
  1502. len++;
  1503.     }
  1504.     break;
  1505. } else
  1506.   p++;
  1507.     }
  1508. }
  1509. #endif /* KLUDGE */
  1510. lp = lp2;
  1511. while (*s++ = *lp++) /* Copy result to target buffer */
  1512.   n--; /* accounting for length */
  1513. s--; /* Back up over the NUL */
  1514. /* Check whether this line is continued */
  1515.         if (flag) /* No line continuation when flag=1 */
  1516.   break; /* So break out of read-lines loop */
  1517. debug(F000,"getnct first char","",*lp3);
  1518. debug(F000,"getnct last char","",ccl);
  1519. debug(F000,"getnct next-to-last char","",ccx);
  1520. if (bc > 0 && *lp3 == '}') /* First char on line is '}' */
  1521.   bc--; /* Decrement block counter */
  1522. if (bc == 0 && /* Line is continued if bc > 0 */
  1523. #ifdef COMMENT
  1524.     /* Not supported as of C-Kermit 6.0 */
  1525.     ccl != CMDQ && /* or line ends with CMDQ */
  1526. #endif /* COMMENT */
  1527.     ccl != '-'  && /* or line ends with dash */
  1528.     ccl != '{') /* or line ends with opening brace */
  1529.   break; /* None of those, we're done. */
  1530. if (ccl == '-' || ccl == '{') /* Continuation character */
  1531.   if (ccx == CMDQ) /* But it's quoted */
  1532.     break; /* so ignore it */
  1533. if (ccl == '{') { /* Last char on line is '{'? */
  1534.     bc++; /* Count the block opener. */
  1535. } else if (ccl == '-' /* Explicit continue? */
  1536. #ifdef COMMENT
  1537. /* Not supported as of C-Kermit 6.0. */
  1538.    || ccl == CMDQ
  1539. #endif /* COMMENT */
  1540.    ) {
  1541.     char c, * ss;
  1542.     int state = 0, nn;
  1543.     s--; /* Yes, back up over terminators */
  1544.     n++; /* and over continuation character */
  1545.     nn = n; /* Save current count */
  1546.     ss = s; /* and pointer */
  1547.     s--; /* Back up over dash */
  1548.     n++;
  1549.     debug(F110,"XXX lp2 A",s2,0);
  1550.     while (state < 2 && s >= s2) { /* Check for "{,-" */
  1551. n++;
  1552. c = *s--;
  1553. debug(F000,"XXX c","",c);
  1554. if (c <= SP)
  1555.   continue;
  1556. if (c != ',' && c != '{')
  1557.   break;
  1558. switch (state) {
  1559.   case 0: /* Looking for comma */
  1560.     if (c == ',')
  1561.       state = 1;
  1562.     break;
  1563.   case 1: /* Looking for left brace */
  1564.     if (c == '{') {
  1565. state = 2;
  1566. s += 2;
  1567. *s = NUL;
  1568. bc++;
  1569.     }
  1570.     break;
  1571. }
  1572.     }
  1573.     if (state != 2) { s = ss; n = nn; }
  1574.     debug(F110,"XXX lp2 B",s2,0);
  1575. } else { /* None of those but (bc > 0) */
  1576.     lastcomma = s;
  1577.     *s++ = ','; /* and insert a comma */
  1578.     n--;
  1579. }
  1580. debug(F101,"getnct bc","",bc);
  1581. debug(F100,"getnct continued","",0);
  1582.     } /* read-lines while loop */
  1583.     if (lastcomma)
  1584.       *lastcomma = SP;
  1585.     if (!flag) /* Tack line terminator back on */
  1586.       *s++ = c;
  1587.     *s++ = NUL; /* Terminate the string */
  1588.     untab(s2); /* Done, convert tabs to spaces */
  1589.     debug(F110,"getnct return",s2,0);
  1590.     free(lpx); /* Free temporary storage */
  1591.     return(0); /* Return success */
  1592. }
  1593. VOID
  1594. shostack() { /* Dump the command stack */
  1595.     int i;
  1596.     char *p;
  1597. #ifndef NOSPL
  1598.     for (i = cmdlvl; i > 0; i--) {
  1599. if (cmdstk[i].src == CMD_TF) {
  1600.     p = tfnam[cmdstk[i].lvl];
  1601.     if (zfnqfp(p,TMPBUFSIZ,tmpbuf))
  1602.       p = tmpbuf;
  1603.     printf(" %2d. File  : %s (line %d)n",
  1604.    i,
  1605.    p,
  1606.    tfline[cmdstk[i].lvl]
  1607.    );
  1608. } else if (cmdstk[i].src == CMD_MD) {
  1609.     char * m;
  1610.     m = m_arg[cmdstk[i].lvl][0]; /* Name of this macro */
  1611.     if (i > 0) {  /* Special handling for 2-level */
  1612. char *s;  /* built-in macros... */
  1613. s = m_arg[cmdstk[i-1].lvl][0]; /* Name next level up */
  1614. if (s && cmdstk[i-1].src == CMD_MD) {
  1615.     if (!strcmp(s,"_forx"))
  1616.       m = "FOR";
  1617.     else if (!strcmp(s,"_xif"))
  1618.       m = "XIF";
  1619.     else if (!strcmp(s,"_while"))
  1620.       m = "WHILE";
  1621.     else if (!strcmp(s,"_switx"))
  1622.       m = "SWITCH";
  1623. }
  1624.     }
  1625.     printf(" %2d. Macro : %sn",i,m);
  1626. } else {
  1627.     printf(" 00. ERROR : Command source unknownn");
  1628. }
  1629.     }
  1630. #else
  1631.     for (i = tlevel; i > -1; i--) {
  1632. p = tfnam[i];
  1633. if (zfnqfp(p,TMPBUFSIZ,tmpbuf))
  1634.   p = tmpbuf;
  1635. printf(" %2d. File  : %s (line %d)n",
  1636.        i,
  1637.        p,
  1638.        tfline[i]
  1639.        );
  1640.     }
  1641. #endif /* NOSPL */
  1642.     if (i == 0)
  1643.       printf(" %2d. Prompt: (top level)n",0);
  1644. }
  1645. /*  P A R S E R  --  Top-level interactive command parser.  */
  1646. /*
  1647.   Call with:
  1648.     m = 0 for normal behavior: keep parsing and executing commands
  1649.           until an action command is parsed, then return with a
  1650.           Kermit start-state as the value of this function.
  1651.     m = 1 to parse only one command, can also be used to call parser()
  1652.           recursively.
  1653.     m = 2 to read but do not execute one command.
  1654.   In all cases, parser() returns:
  1655.     0     if no Kermit protocol action required
  1656.     > 0   with a Kermit protocol start-state.
  1657.     < 0   upon error.
  1658. */
  1659. int
  1660. parser(m) int m; {
  1661.     int tfcode, xx, yy, zz; /* Workers */
  1662.     int is_tn = 0;
  1663. #ifndef NOSPL
  1664.     int inlevel; /* Level we were called at */
  1665.     extern int askflag;
  1666. #endif /* NOSPL */
  1667.     char *cbp; /* Command buffer pointer */
  1668. #ifdef MAC
  1669.     extern char *lfiles; /* Fake extern cast */
  1670. #endif /* MAC */
  1671. #ifndef NOXFER
  1672.     extern int sndcmd, getcmd, interrupted, fatalio, clearrq;
  1673. #endif /* NOXFER */
  1674. #ifdef AMIGA
  1675.     reqres(); /* Restore AmigaDOS requestors */
  1676. #endif /* AMIGA */
  1677. #ifdef OS2
  1678.     if (cursor_save > -1) { /* Restore cursor if it was */
  1679. cursorena[VCMD] = cursor_save; /* turned off during file transfer */
  1680. cursor_save = -1;
  1681.     }
  1682. #endif /* OS2 */
  1683.     what = W_COMMAND; /* Now we're parsing commands. */
  1684. #ifdef IKSDB
  1685.     if (ikdbopen) slotstate(what,"COMMAND PROMPT","",""); /* IKSD database */
  1686. #endif /* IKSDB */
  1687.     is_tn = (local && network && ttnproto == NP_TELNET) ||
  1688.       (!local && sstelnet);
  1689.     if (!cmdsrc()) /* If at top (interactive) level ... */
  1690.       concb((char)escape); /* put console in 'cbreak' mode. */
  1691. #ifdef CK_TMPDIR
  1692. /* If we were cd'd temporarily to another device or directory ... */
  1693.     if (f_tmpdir) {
  1694. int x;
  1695. x = zchdir((char *) savdir); /* ... restore previous directory */
  1696. f_tmpdir = 0; /* and remember we did it. */
  1697. debug(F111,"parser tmpdir restoring",savdir,x);
  1698.     }
  1699. #endif /* CK_TMPDIR */
  1700. #ifndef NOSPL
  1701.     inlevel = cmdlvl; /* Current macro level */
  1702. #ifdef DEBUG
  1703.     if (deblog) {
  1704. debug(F101,"&parser entry maclvl","",maclvl);
  1705. debug(F101,"&parser entry inlevel","",inlevel);
  1706. debug(F101,"&parser entry tlevel","",tlevel);
  1707. debug(F101,"&parser entry cmdlvl","",cmdlvl);
  1708. debug(F101,"&parser entry m","",m);
  1709.     }
  1710. #endif /* DEBUG */
  1711. #endif /* NOSPL */
  1712. #ifndef NOXFER
  1713.     ftreset(); /* Reset global file-xfer settings */
  1714. #endif /* NOXFER */
  1715. /*
  1716.   sstate becomes nonzero when a command has been parsed that requires some
  1717.   action from the protocol module.  Any non-protocol actions, such as local
  1718.   directory listing or terminal emulation, are invoked directly from below.
  1719. */
  1720.     sstate = 0; /* Start with no start state. */
  1721. #ifndef NOXFER
  1722. #ifndef NOSPL
  1723.     query = 0; /* QUERY not active */
  1724. #endif /* NOSPL */
  1725. #ifndef NOHINTS
  1726.     if (sndcmd && !success && hints && !interrupted && !fatalio && !cmdsrc()) {
  1727. int x = 0;
  1728.         printf("n*************************n");
  1729. printf("SEND-class command failed.n");
  1730. printf(" Packets sent: %dn", spackets);
  1731. printf(" Retransmissions: %dn",retrans);
  1732. printf(" Timeouts: %dn", timeouts);
  1733. if (epktrcvd) {
  1734.     printf(" Transfer canceled by receiver.n");
  1735.     printf(" Receiver's message: "%s"n",(char *)epktmsg);
  1736. }
  1737. printf(" Most recent local error: "%s"n",ck_errstr());
  1738. printf(
  1739.    "nHINTS... If the preceding error message%s not explain the failure:n",
  1740.        epktrcvd ? "s do" : " does"
  1741.        );
  1742. #ifndef NOLOCAL
  1743. if (local) {
  1744.     if (rpackets == 0)
  1745.       printf(" . Did you start a Kermit receiver on the far end?n");
  1746.     else
  1747.       printf(
  1748.       " . Try changing the remote Kermit's FLOW-CONTROL setting.n");
  1749. } else if (rpackets > 0) {
  1750.     if (flow == FLO_NONE)
  1751.      printf(" . Give me a SET FLOW XON/XOFF command and try again.n");
  1752.     else
  1753.      printf(" . Give me a SET FLOW NONE command and try again.n");
  1754. }
  1755. x++;
  1756. #endif /* NOLOCAL */
  1757. #ifdef CK_SPEED
  1758. if (prefixing != PX_ALL && rpackets > 2) {
  1759.     printf(" . Try it again with SET PREFIXING ALL.n");
  1760.     x++;
  1761. }
  1762. #endif /* CK_SPEED */
  1763. #ifdef STREAMING
  1764. if (streamed) {
  1765.     printf(" . Try it again with SET STREAMING OFF.n");
  1766.     x++;
  1767. } else if (reliable) {
  1768.     printf(" . Try it again with SET RELIABLE OFF.n");
  1769.     x++;
  1770. }
  1771. #endif /* STREAMING */
  1772.         if (clearrq > 0 && prefixing == PX_NON) {
  1773.     printf(" . Try it again with SET CLEAR-CHANNEL OFF.n");
  1774.     x++;
  1775.         }
  1776. if (!parity) {
  1777.     printf(" . Try it again with SET PARITY SPACE.n");
  1778.     x++;
  1779. }
  1780. printf(" . %sive a ROBUST command and try again.n",
  1781.        (x > 0) ? "As a last resort, g" : "G"
  1782.        );
  1783. printf("Also:n");
  1784.         printf(" . Be sure the source file has read permission.n");
  1785. printf(" . Be sure the target directory has write permission.n");
  1786. printf("(Use SET HINTS OFF to suppress hints.)n");
  1787. printf("*************************nn");
  1788.     }
  1789.     if (getcmd && !success && hints && !interrupted && !fatalio && !cmdsrc()) {
  1790. int x = 0;
  1791. extern int urpsiz, wslotr;
  1792.         printf("n*************************n");
  1793. printf("RECEIVE- or GET-class command failed.n");
  1794. printf(" Packets received: %dn", rpackets);
  1795. printf(" Damaged packets: %dn", crunched);
  1796. printf(" Timeouts: %dn", timeouts);
  1797. if (rpackets > 0)
  1798.   printf(" Packet length: %dn", urpsiz);
  1799. if (epktrcvd) {
  1800.     printf(" Transfer canceled by sender.n");
  1801.     printf(" Sender's message: "%s"n",(char *)epktmsg);
  1802. }
  1803. printf(" Most recent local error: "%s"n",ck_errstr());
  1804. printf(
  1805.    "nHINTS... If the preceding error message%s not explain the failure:n",
  1806.        epktrcvd ? "s do" : " does"
  1807.        );
  1808. #ifndef NOLOCAL
  1809. if (local) {
  1810.     if (rpackets == 0)
  1811.       printf(" . Did you start a Kermit sender on the far end?n");
  1812.     else
  1813.       printf(
  1814.       " . Choose a different FLOW-CONTROL setting and try again.n");
  1815. }
  1816. if (rpackets > 0 && urpsiz > 90)
  1817.   printf(" . Try smaller packets (SET RECEIVE PACKET-LENGH).n");
  1818. if (rpackets > 0 && wslotr > 1 && !streamed)
  1819.   printf(" . Try a smaller window size (SET WINDOW).n");
  1820. if (!local && rpackets > 0) {
  1821.     if (flow == FLO_NONE)
  1822.      printf(" . Give me a SET FLOW XON/XOFF command and try again.n");
  1823.     else
  1824.      printf(" . Give me a SET FLOW NONE command and try again.n");
  1825. }
  1826. x++;
  1827. #endif /* NOLOCAL */
  1828. #ifdef STREAMING
  1829. if (streamed) {
  1830.     printf(" . Try it again with SET STREAMING OFF.n");
  1831.     x++;
  1832. } else if (reliable && local) {
  1833.     printf(" . Try it again with SET RELIABLE OFF.n");
  1834.     x++;
  1835.         } else
  1836. #endif /* STREAMING */
  1837. if (!parity) {
  1838.     printf(" . Try it again with SET PARITY SPACE.n");
  1839.     x++;
  1840. }
  1841. printf((x > 0) ?
  1842.        " . As a last resort, give a ROBUST command and try again.n" :
  1843.        " . Give a ROBUST command and try again.n"
  1844.        );
  1845. printf("Also:n");
  1846. printf(" . Be sure the target directory has write permission.n");
  1847.         printf(" . Try telling sender to SET PREFIXING ALL.n");
  1848. printf(" . Try giving a ROBUST command to the sender.n");
  1849. printf("(Use SET HINTS OFF to suppress hints.)n");
  1850. printf("*************************nn");
  1851.     }
  1852. #endif /* NOHINTS */
  1853.     getcmd = 0;
  1854.     sndcmd = 0;
  1855.     interrupted = 0;
  1856. #endif /* NOXFER */
  1857.     while (sstate == 0) { /* Parse cmds until action requested */
  1858. debug(F100,"parse top","",0);
  1859. #ifdef IKS_OPTION
  1860.         if ((local &&
  1861.      !cmdsrc() &&
  1862.      is_tn &&
  1863.      TELOPT_ME(TELOPT_KERMIT) &&
  1864.      TELOPT_SB(TELOPT_KERMIT).kermit.me_start) ||
  1865.     (!local &&
  1866.      !cmdadl &&
  1867.      TELOPT_ME(TELOPT_KERMIT) &&
  1868.      TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
  1869.     ) {
  1870.             tn_siks(KERMIT_STOP);
  1871.         }
  1872. #endif /* IKS_OPTION */
  1873. #ifndef NOXFER
  1874. if (autopath) {
  1875.     fnrpath = PATH_AUTO;
  1876.     autopath = 0;
  1877. }
  1878. remfile = 0; /* Clear these in case REMOTE */
  1879. remappd = 0; /* command was interrupted... */
  1880. rempipe = 0;
  1881. makestr(&snd_move,g_snd_move); /* Restore these */
  1882. makestr(&rcv_move,g_rcv_move);
  1883. makestr(&snd_rename,g_snd_rename);
  1884. makestr(&rcv_rename,g_rcv_rename);
  1885. #endif /* NOXFER */
  1886. diractive = 0;
  1887. #ifndef NOSPL
  1888. askflag = 0;
  1889. #endif /* NOSPL */
  1890.     /* Take requested action if there was an error in the previous command */
  1891. setint();
  1892. debug(F101,"parser tlevel","",tlevel);
  1893. debug(F101,"parser cmd_rows","",cmd_rows);
  1894. #ifndef NOLOCAL
  1895. if (wasclosed) { /* If connection was just closed */
  1896. #ifndef NOSPL
  1897.     int k;
  1898.     k = mlook(mactab,"on_close",nmac); /* Look up "on_close" */
  1899.     if (k >= 0) { /* If found, */
  1900. /* printf("ON_CLOSE CMD LOOPn"); */
  1901. dodo(k,ckitoa(whyclosed),0); /* Set it up */
  1902.     }
  1903. #endif /* NOSPL */
  1904.     whyclosed = WC_REMO;
  1905.     wasclosed = 0;
  1906.         }
  1907. #endif /* NOLOCAL */
  1908. #ifndef NOSPL
  1909. xxdot = 0; /* Clear this... */
  1910. if (success == 0) {
  1911.     if (cmdstk[cmdlvl].src == CMD_TF && takerr[cmdlvl]) {
  1912. printf("Command file terminated by error.n");
  1913. popclvl();
  1914. if (cmdlvl == 0) return(0);
  1915.     }
  1916.     if (cmdstk[cmdlvl].src == CMD_MD && merror[cmdlvl]) {
  1917. printf("Command error: macro terminated.n");
  1918. popclvl();
  1919. if (m && (cmdlvl < inlevel))
  1920.   return((int) sstate);
  1921.     }
  1922. }
  1923. nulcmd = (m == 2);
  1924. #else
  1925. if (success == 0 && tlevel > -1 && takerr[tlevel]) {
  1926.     printf("Command file terminated by error.n");
  1927.     popclvl();
  1928.     cmini(ckxech); /* Clear the cmd buffer. */
  1929.     if (tlevel < 0)  /* Just popped out of cmd files? */
  1930.       return(0); /* End of init file or whatever. */
  1931. }
  1932. #endif /* NOSPL */
  1933. #ifdef MAC
  1934. /* Check for TAKE initiated by menu. */
  1935. if ((tlevel == -1) && lfiles)
  1936.     startlfile();
  1937. #endif /* MAC */
  1938.         /* If in TAKE file, check for EOF */
  1939. #ifndef NOSPL
  1940. #ifdef MAC
  1941. if
  1942. #else
  1943. while
  1944. #endif /* MAC */
  1945.   ((cmdstk[cmdlvl].src == CMD_TF)  /* If end of take file */
  1946.        && (tlevel > -1)
  1947.        && feof(tfile[tlevel])) {
  1948.     popclvl(); /* pop command level */
  1949.     cmini(ckxech); /* and clear the cmd buffer. */
  1950.     if (cmdlvl == 0) { /* Just popped out of all cmd files? */
  1951. return(0); /* End of init file or whatever. */
  1952.     }
  1953. }
  1954. #ifdef MAC
  1955. miniparser(1);
  1956. if (sstate == 'a') { /* if cmd-. cancel */
  1957.     debug(F100, "parser: cancel take due to sstate", "", sstate);
  1958.     sstate = '';
  1959.     dostop();
  1960.     return(0); /* End of init file or whatever. */
  1961. }
  1962. #endif /*  MAC */
  1963. #else /* NOSPL */
  1964. if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */
  1965.     popclvl(); /* Pop up one level. */
  1966.     cmini(ckxech); /* and clear the cmd buffer. */
  1967.     if (tlevel < 0)  /* Just popped out of cmd files? */
  1968.       return(0); /* End of init file or whatever. */
  1969.   }
  1970. #endif /* NOSPL */
  1971. #ifndef NOSPL
  1972.         if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
  1973.     debug(F100,"parser macro","",0);
  1974.     maclvl = cmdstk[cmdlvl].lvl; /* Get current level */
  1975.     debug(F101,"parser maclvl","",maclvl);
  1976.     cbp = cmdbuf; /* Copy next cmd to command buffer. */
  1977.     *cbp = NUL;
  1978.     if (*savbuf) { /* In case then-part of 'if' command */
  1979. strcpy(cbp,savbuf); /* was saved, restore it. */
  1980. *savbuf = '';
  1981.     } else { /* Else get next cmd from macro def */
  1982. if (getncm(cbp,CMDBL) < 0) {
  1983.     if (m && (cmdlvl < inlevel))
  1984.       return((int) sstate);
  1985.     else /* if (!m) */ continue;
  1986. }
  1987.     }
  1988.     debug(F110,"cmdbuf from macro",cmdbuf,0);
  1989. } else if (cmdstk[cmdlvl].src == CMD_TF)
  1990. #else
  1991.   if (tlevel > -1)
  1992. #endif /* NOSPL */
  1993.   {
  1994. #ifndef NOSPL
  1995.     if (*savbuf) { /* In case THEN-part of IF command */
  1996. strcpy(cmdbuf,savbuf); /* was saved, restore it. */
  1997. *savbuf = '';
  1998.     } else
  1999. #endif /* NOSPL */
  2000.       /* Get next line from TAKE file */
  2001.       if ((tfcode = getnct(cmdbuf,CMDBL,tfile[tlevel],0)) < 0) {
  2002.   if (tfcode < -1) { /* Error */
  2003.       printf("?Error in TAKE command file: %sn",
  2004.      (tfcode == -2) ? "Memory allocation failure" :
  2005.      "Line too long or contains NUL characters"
  2006.      );
  2007.       dostop();
  2008.   }
  2009.   continue; /* -1 means EOF */
  2010.       }
  2011.         /* If interactive, get next command from user. */
  2012. } else { /* User types it in. */
  2013.     if (pflag) prompt(xxstring);
  2014.     cmini(ckxech);
  2015.      }
  2016.     /* Now we know where next command is coming from. Parse and execute it. */
  2017. repars = 1; /* 1 = command needs parsing */
  2018. #ifndef NOXFER
  2019. displa = 0; /* Assume no file transfer display */
  2020. #endif /* NOXFER */
  2021. while (repars) { /* Parse this cmd until entered. */
  2022.     debug(F101,"parser top of while loop","",0);
  2023.     /* In case of "send /recursive ./?<Ctrl-U>" etc */
  2024. #ifdef RECURSIVE
  2025.     recursive = 0; /* This is never sticky */
  2026. #endif /* RECURSIVE */
  2027.     /* This might have been changed by a switch */
  2028.     if (g_matchdot > -1) {
  2029. matchdot = g_matchdot;
  2030. g_matchdot = -1;
  2031.     }
  2032.     if (saveask > -1) {
  2033. xaskmore = saveask;
  2034. saveask = -1;
  2035.     }
  2036.     cmres(); /* Reset buffer pointers. */
  2037. #ifdef OS2
  2038. #ifdef COMMENT
  2039.     /* we check to see if a macro is waiting to be executed */
  2040.     /* if so, we call domac on it */
  2041.     if (cmdmac) {
  2042. ckstrncpy(cmdbuf, cmdmac, CMDBL);
  2043. free(cmdmac);
  2044. cmdmac = NULL;
  2045.     }
  2046. #endif /* COMMENT */
  2047. #endif /* OS2 */
  2048. #ifndef NOXFER
  2049.     bye_active = 0;
  2050. #endif /* NOXFER */
  2051.     xx = cmkey2(cmdtab,ncmd,"Command","",toktab,xxstring,1);
  2052.     debug(F101,"top-level cmkey2","",xx);
  2053.     if (xx == -5) {
  2054. yy = chktok(toktab);
  2055. debug(F101,"top-level cmkey token","",yy);
  2056. ungword();
  2057. switch (yy) {
  2058.   case '#': xx = XXCOM; break; /* Comment */
  2059.   case ';': xx = XXCOM; break; /* Comment */
  2060. #ifndef NOSPL
  2061.   case '.': xx = XXDEF; xxdot = 1; break; /* Assignment */
  2062.   case ':': xx = XXLBL; break; /* GOTO label */
  2063. #endif /* NOSPL */
  2064. #ifndef NOPUSH
  2065. #ifdef CK_REDIR
  2066.                   case '<':
  2067. #endif /* CK_REDIR */
  2068.                   case '@':
  2069.                   case '!':
  2070.     if (!nopush) {
  2071. switch(yy) {
  2072. #ifdef CK_REDIR
  2073.   case '<': xx = XXFUN; break; /* REDIRECT */
  2074. #endif /* CK_REDIR */
  2075.   case '@':
  2076.   case '!': xx = XXSHE; break; /* Shell escape */
  2077. }
  2078.     }
  2079.     break;
  2080. #endif /* NOPUSH */
  2081. #ifdef CK_RECALL
  2082.   case '^': xx = XXREDO; break;
  2083. #endif /* CK_RECALL */
  2084. #ifndef NOSPL
  2085.   case '{': xx = XXMACRO; break;
  2086. #endif /* NOSPL */
  2087.   default:
  2088.     if (!quiet) {
  2089. printf("n?Invalid - "%s"n",cmdbuf);
  2090. #ifdef COMMENT
  2091. #ifndef NOSPL
  2092. if (maclvl > -1 && cmdsrc() == 2)
  2093.   printf("Macro: %s; ",
  2094.  m_arg[maclvl][0] ?
  2095.  m_arg[maclvl][0] : "");
  2096. #endif /* NOSPL */
  2097. if (tlevel > -1) {
  2098.     printf("Command file: %s, line %dn",
  2099.    tfnam[tlevel] ? tfnam[tlevel] : "",
  2100.    tfline[tlevel]
  2101.    );
  2102. }
  2103. #else
  2104. if (cmdsrc() > 0) {
  2105.     printf("Command stack:n");
  2106.     shostack();
  2107. }
  2108. #endif /* COMMENT */
  2109.     }
  2110.     xx = -2;
  2111. }
  2112.     }
  2113.     topcmd = xx; /* Top-level command index */
  2114. #ifndef NOSPL
  2115.             /* Special handling for IF..ELSE */
  2116.     if (ifcmd[cmdlvl]) /* Count stmts after IF */
  2117.       ifcmd[cmdlvl]++;
  2118.     if (ifcmd[cmdlvl] > 2 && xx != XXELS && xx != XXCOM)
  2119.       ifcmd[cmdlvl] = 0;
  2120.     /* Execute the command and take action based on return code. */
  2121.     if (nulcmd) { /* Ignoring this command? */
  2122. xx = XXCOM; /* Make this command a comment. */
  2123.     }
  2124.     fnsuccess = 1; /* For catching function() errors */
  2125. #endif /* NOSPL */
  2126.     zz = docmd(xx); /* Parse rest of command & execute. */
  2127. #ifndef NOSPL
  2128.     if (fnerror && !fnsuccess)
  2129.       success = 0;
  2130. #endif /* NOSPL */
  2131.     debug(F101,"docmd returns","",zz);
  2132.     debug(F110,"cmdbuf",cmdbuf,"");
  2133.     debug(F110,"atmbuf",atmbuf,"");
  2134. #ifdef CK_RECALL
  2135.     if (zz < 0 && cmflgs == 1)
  2136.       addcmd(cmdbuf);
  2137. #endif /* CK_RECALL */
  2138. #ifdef MAC
  2139.     if (tlevel > -1) {
  2140. if (sstate == 'a') { /* if cmd-. cancel */
  2141.     debug(F110, "parser: cancel take, sstate:", "a", 0);
  2142.     sstate = '';
  2143.     dostop();
  2144.     return(0); /* End of init file or whatever. */
  2145. }
  2146.     }
  2147. #endif /* MAC */
  2148.     switch (zz) {
  2149.       case -4: /* EOF (e.g. on redirected stdin) */
  2150. doexit(GOOD_EXIT,xitsta); /* ...exit successfully */
  2151.       case -1: /* Reparse needed */
  2152. repars = 1; /* Just set reparse flag and... */
  2153. continue;
  2154. #ifdef OS2
  2155.       case -7: /* They typed a disk letter */
  2156. if (!zchdir((char *)cmdbuf)) {
  2157.     perror((char *)cmdbuf);
  2158.     success = 0;
  2159. } else success = 1;
  2160. repars = 0;
  2161. continue;
  2162. #endif /* OS2 */
  2163.       case -6: /* Invalid command given w/no args */
  2164.       case -2: /* Invalid command given w/args */
  2165. #ifdef COMMENT
  2166. #ifndef NOSPL
  2167.     /* This is going to be really ugly... */
  2168.     yy = mlook(mactab,atmbuf,nmac); /* Look in macro table */
  2169.     if (yy > -1) {             /* If it's there */
  2170. if (zz == -2) {             /* insert "do" */
  2171.     char *mp;
  2172.     mp = malloc((int)strlen(cmdbuf) + 5);
  2173.     if (!mp) {
  2174. printf("?malloc error 1n");
  2175. return(-2);
  2176.     }
  2177.     sprintf(mp,"do %s ",cmdbuf);
  2178.     strcpy(cmdbuf,mp);
  2179.     free(mp);
  2180.     mp = NULL;
  2181. } else sprintf(cmdbuf,"do %s %c",atmbuf, CR);
  2182. if (ifcmd[cmdlvl] == 2) /* This one doesn't count! */
  2183.   ifcmd[cmdlvl]--;
  2184. debug(F111,"stuff cmdbuf",cmdbuf,zz);
  2185. repars = 1; /* Go for reparse */
  2186. continue;
  2187.     } else {
  2188. char *p;
  2189. int n;
  2190. p = cmdbuf;
  2191. lp = line;
  2192. n = LINBUFSIZ;
  2193. if (cmflgs == 0) printf("n");
  2194. if (zzstring(p,&lp,&n) > -1)
  2195.   printf("?Invalid: %sn",line);
  2196. else
  2197.   printf("?Invalid: %sn",cmdbuf);
  2198.     } /* (fall thru...) */
  2199. #else
  2200.     printf("?Invalid: %sn",cmdbuf);
  2201. #endif /* NOSPL */
  2202. #else /* Not COMMENT */
  2203.     printf("?Invalid: %sn",cmdbuf);
  2204. #endif /* COMMENT */
  2205. case -9: /* Bad, error message already done */
  2206.     success = 0;
  2207.     debug(F110,"top-level cmkey failed",cmdbuf,0);
  2208.     /* If in background w/ commands coming stdin, terminate */
  2209.     if (pflag == 0 && tlevel < 0)
  2210.       fatal("Kermit command error in background execution");
  2211. /*
  2212.   Command retry feature, edit 190.  If we're at interactive prompting level,
  2213.   reprompt the user with as much of the command as didn't fail.
  2214. */
  2215. #ifdef CK_RECALL
  2216.     if (cm_retry && !cmdsrc()) { /* If at top level */
  2217. int len;
  2218. char *p, *s;
  2219. len = strlen(cmdbuf); /* Length of command buffer */
  2220. p = malloc(len + 1);  /* Allocate space for copy */
  2221. if (p) {       /* If we got the space */
  2222.     strcpy(p,cmdbuf); /* copy the command buffer. */
  2223.     /* Chop off final field, the one that failed. */
  2224.     s = p + len - 1;          /* Point to end */
  2225.     while (*s == SP && s > p) /* Trim blanks */
  2226.       s--;
  2227.     while (*s != SP && s > p) /* Trim last field */
  2228.       s--;
  2229.     if (s > p)        /* Keep the space */
  2230.       s++;       /* after last good field */
  2231.     if (s >= p)       /* Cut off remainder */
  2232.       *s = NUL;
  2233.     cmini(ckxech);    /* Reinitialize the parser */
  2234.     strcpy(cmdbuf,p); /* Copy truncated cmd back */
  2235.     free(p);          /* Free temporary storage */
  2236.     p = NULL;
  2237.     prompt(xxstring); /* Reprint the prompt */
  2238.     printf("%s",cmdbuf); /* Reprint partial command */
  2239.     repars = 1;          /* Force reparse */
  2240.     continue;
  2241. }
  2242.     } else
  2243. #endif /* CK_RECALL */
  2244.       if (!quiet) {
  2245. #ifdef COMMENT
  2246. #ifndef NOSPL
  2247.   if (maclvl > -1)
  2248.     printf("Macro: %s; ",
  2249.    m_arg[maclvl][0] ?
  2250.    m_arg[maclvl][0] : "");
  2251. #endif /* NOSPL */
  2252.   if (tlevel > -1)
  2253.     printf("Command file: %s, line %dn",
  2254.    tfnam[tlevel] ? tfnam[tlevel] : "",
  2255.    tfline[tlevel]
  2256.    );
  2257. #else
  2258.   if (cmdsrc() > 0) {
  2259.       printf("Command stack:n");
  2260.       shostack();
  2261.   }
  2262. #endif /* COMMENT */
  2263.       }
  2264.       cmini(ckxech); /* (fall thru) */
  2265.        case -3: /* Empty command OK at top level */
  2266.     repars = 0; /* Don't need to reparse. */
  2267.     continue; /* Go back and get another command. */
  2268. default: /* Command was successful. */
  2269. #ifndef NOSPL
  2270.     debug(F101,"parser preparing to continue","",maclvl);
  2271. #endif /* NOSPL */
  2272.     repars = 0; /* Don't need to reparse. */
  2273.     continue; /* Go back and get another command. */
  2274. }
  2275. }
  2276. #ifndef NOSPL
  2277. debug(F101,"parser breaks out of while loop","",maclvl);
  2278. if (m && (cmdlvl < inlevel))  return((int) sstate);
  2279. #endif /* NOSPL */
  2280.     }
  2281. /* Got an action command, return start state. */
  2282.     return((int) sstate);
  2283. }
  2284. #ifndef NOSPL
  2285. /*
  2286.   OUTPUT command.
  2287.   Buffering and pacing added by L.I. Kirby, 5A(189), June 1993.
  2288. */
  2289. #define OBSIZE 80 /* Size of local character buffer */
  2290. static int obn; /* Buffer offset (high water mark) */
  2291. static char obuf[OBSIZE+1]; /* OUTPUT buffer. */
  2292. static char *obp; /* Pointer to output buffer. */
  2293. _PROTOTYP( static int oboc, (char) );
  2294. _PROTOTYP( static int xxout, (char *, int) );
  2295. static int
  2296. #ifdef CK_ANSIC
  2297. xxout(char *obuf, int obsize)
  2298. #else
  2299. xxout(obuf, obsize) char *obuf; int obsize;
  2300. #endif /* CK_ANSIC */
  2301. /* xxout */ { /* OUTPUT command's output function */
  2302.     int i, rc;
  2303.     debug(F101,"xxout obsize","",obsize);
  2304.     debug(F101,"xxout pacing","",pacing);
  2305.     debug(F111,"xxout string",obuf,strlen(obuf));
  2306.     rc = 0; /* Initial return code. */
  2307.     if (!obuf || (obsize <= 0)) /* Nothing to output. */
  2308.       goto xxout_x; /* Return successfully */
  2309.     rc = -1;   /* Now assume failure */
  2310.     if (pacing == 0) {   /* Is pacing enabled? */
  2311. if ((local ?     /* No, write entire string at once */
  2312.      ttol((CHAR *)obuf, obsize) : /* to communications device */
  2313.      conxo(obsize, obuf))   /* or to console */
  2314.     != obsize)
  2315.   goto xxout_x;
  2316.     } else {
  2317. for (i = 0; i < obsize; i++) { /* Write individual chars */
  2318.     if ((local ? ttoc(obuf[i]) : conoc(obuf[i])) < 0)
  2319.       goto xxout_x;
  2320.     msleep(pacing);
  2321. }
  2322.     }
  2323.     if (duplex) {
  2324. #ifdef OS2
  2325.         if (inecho && local) {
  2326.             for (i = 0; i < obsize; i++) { /* Write to emulator */
  2327.                 scriptwrtbuf((USHORT)obuf[i]); /* which also logs session */
  2328.             }
  2329.             conxo(obsize,obuf);
  2330.         } else if (seslog) { /* or log session here */
  2331.             logstr((char *) obuf, obsize);
  2332.         }
  2333. #else /* OS2 */
  2334.         if (seslog) {
  2335.             logstr((char *) obuf, obsize);
  2336. }
  2337.         if (inecho && local) {
  2338.             conxo(obsize,obuf);
  2339.         }
  2340. #endif /* OS2 */
  2341.     }
  2342.     rc = 0; /* Success */
  2343.   xxout_x:
  2344.     obn = 0; /* Reset count */
  2345.     obp = obuf; /* and pointers */
  2346.     return(rc); /* return our return code */
  2347. }
  2348. #ifdef COMMENT
  2349. /*
  2350.   Macros for OUTPUT command execution, to make it go faster.
  2351. */
  2352. #define obfls() ((xxout(obuf,obn)<0)?-1:0)
  2353. #define oboc(c) ((*obp++=(char)(c)),*obp=0,(((++obn)>=OBSIZE)?obfls():0))
  2354. #else /* The macros cause some compilers to generate bad code. */
  2355. static int
  2356. #ifdef CK_ANSIC
  2357. oboc(char c)
  2358. #else
  2359. oboc(c) char c;
  2360. #endif /* CK_ANSIC */
  2361. /* oboc */ { /* OUTPUT command's output function */
  2362.     *obp++ = c; /* Deposit character */
  2363.     *obp = NUL; /* Flush buffer if it's now full */
  2364.     return(((++obn) >= OBSIZE) ? xxout(obuf,obn) : 0);
  2365. }
  2366. #endif /* COMMENT */
  2367. /*  Routines for handling local variables -- also see popclvl().  */
  2368. VOID
  2369. freelocal(m) int m; { /* Free local variables */
  2370.     struct localvar * v, * tv; /* at macro level m... */
  2371.     debug(F101,"freelocal level","",m);
  2372.     if (m < 0) return;
  2373.     v = localhead[m]; /* List head for level m */
  2374.     while (v) {
  2375. if (v->lv_name) /* Variable name */
  2376.   free(v->lv_name);
  2377. if (v->lv_value) /* Value */
  2378.   free(v->lv_value);
  2379. tv = v; /* Save pointer to this node */
  2380. v = v->lv_next; /* Get next one */
  2381. if (tv) /* Free this one */
  2382.   free(tv);
  2383.     }
  2384.     localhead[m] = (struct localvar *) NULL; /* Done, set list head to NULL */
  2385. }
  2386. #define MAXLOCALVAR 64
  2387. int
  2388. dolocal() { /* Do the LOCAL command */
  2389.     int i, x, z;
  2390.     char * s, * p;
  2391.     char * list[MAXLOCALVAR+2]; /* Up to 64 variables per line */
  2392.     int fe;
  2393.     struct localvar * v, *prev = (struct localvar *)NULL;
  2394.     extern int tra_asg; int tra_tmp;
  2395.     tra_tmp = tra_asg;
  2396.     if ((x = cmtxt("Variable name(s)","",&s,NULL)) < 0)
  2397.       return(x);
  2398.     xwords(s,MAXLOCALVAR,list,0); /* Break up line into "words" */
  2399. /*
  2400.   loop thru variable list.
  2401.   if variable is defined, allocate a node for it,
  2402.   copy its value to the node,
  2403.   and undefine it.
  2404. */
  2405.     if (v = localhead[cmdlvl]) { /* Already have some at this level? */
  2406. while (v) { /* Find end of list */
  2407.     prev = v;
  2408.     v = v->lv_next;
  2409. }
  2410.     }
  2411.     /* Note: Arrays do not use the localhead list, but have their own stack */
  2412.     for (i = 1; i < MAXLOCALVAR && list[i]; i++) { /* Go through the list */
  2413. p = list[i]; /* This element */
  2414. if (*p == CMDQ) { /* Starts with backslash? */
  2415.     int xx;
  2416.     if (*(p+1) == '&') { /* Array? */
  2417. xx = arraynam(p,&x,&z); /* Check name but not whether it */
  2418. if (xx < 0 && z != -17) /* is defined. */
  2419.   continue;
  2420. if (z == -17) z = 0; /* Secret code for empty brackets */
  2421. pusharray(x,z); /* It's an array name, push it */
  2422. continue;
  2423.     } else if (parsevar(p,&x,&z) < 0) /* Variable other than array */
  2424.       continue;
  2425.     sprintf(tmpbuf,"\fcontents(%s)",p); /* Get definition */
  2426. } else { /* Macro */
  2427.     sprintf(tmpbuf,"\fdefinition(%s)",p); /* Get def */
  2428. }
  2429. debug(F110,"dolocal tmpbuf",tmpbuf,0);
  2430. s = line; /* Point to destination buffer */
  2431. x = LINBUFSIZ; /* Length of destination buffer */
  2432. zzstring(tmpbuf,&s,&x); /* Get definition */
  2433. debug(F110,"dolocal line",line,0);
  2434. /* Name is in list[i], definition is in line[] */
  2435. v = (struct localvar *) malloc(sizeof(struct localvar));
  2436. if (!v) {
  2437.     printf("?Failure to allocate storage for local variables");
  2438.     return(-9);
  2439. }
  2440. if (!localhead[cmdlvl]) /* If first, set list head */
  2441.   localhead[cmdlvl] = v;
  2442. else /* Otherwise link previous to this */
  2443.   prev->lv_next = v;
  2444. prev = v; /* And make this previous */
  2445. v->lv_next = (struct localvar *) NULL; /* No next yet */
  2446. if (!(v->lv_name = (char *) malloc((int) strlen(list[i]) + 1)))
  2447.   goto localbad;
  2448. strcpy(v->lv_name, list[i]); /* Copy name into new node */
  2449. if (*line) {
  2450.     if (!(v->lv_value = (char *) malloc((int) strlen(line) + 1)))
  2451.       goto localbad;
  2452.     strcpy(v->lv_value, line); /* Copy value into new node */
  2453. } else
  2454.   v->lv_value = NULL;
  2455. tra_asg = 0;
  2456. delmac(list[i]); /* Delete the original macro */
  2457. tra_asg = tra_tmp;
  2458.     }
  2459.     return(success = 1);
  2460.   localbad:
  2461.     printf("?Failure to allocate storage for local variables");
  2462.     freelocal(cmdlvl);
  2463.     return(-9);
  2464. }
  2465. /*  D O O U T P U T  --  Returns 0 on failure, 1 on success */
  2466. #ifndef NOKVERBS
  2467. #define K_BUFLEN 30
  2468. #define SEND_BUFLEN 255
  2469. #define sendbufd(x) { osendbuf[sendndx++] = x;
  2470.  if (sendndx == SEND_BUFLEN) {dooutput(s,cx); sendndx = 0;}}
  2471. #endif /* NOKVERBS */
  2472. int outesc = 1; /* Process special OUTPUT escapes */
  2473. int
  2474. dooutput(s, cx) char *s; int cx; {
  2475.     int x, xx, y, quote; /* Workers */
  2476.     int is_tn = 0;
  2477.     is_tn = (local && network && ttnproto == NP_TELNET) ||
  2478.       (!local && sstelnet);
  2479.     debug(F111,"dooutput s",s,(int)strlen(s));
  2480.     if (local) { /* Condition external line */
  2481. #ifdef NOLOCAL
  2482. goto outerr;
  2483. #else
  2484. if (ttchk() < 0) {
  2485.     printf("?Connection %s %s is not open.n",
  2486.    network ? "to" : "on",
  2487.    ttname
  2488.    );
  2489.     return(0);
  2490. }
  2491. if (ttvt(speed,flow) < 0) {
  2492.     printf("?OUTPUT initialization errorn");
  2493.     return(0);
  2494. }
  2495. #endif /* NOLOCAL */
  2496.     }
  2497.     if (!cmdgquo()) { /* COMMAND QUOTING OFF */
  2498. x = strlen(s); /* Just send the string literally */
  2499. xx = local ? ttol((CHAR *)s,x) : conxo(x,s);
  2500. return(success = (xx == x) ? 1 : 0);
  2501.     }
  2502.     quote = 0; /* Initialize backslash () quote */
  2503.     obn = 0; /* Reset count */
  2504.     obp = obuf; /* and pointers */
  2505.   outagain:
  2506.     while (x = *s++) { /* Loop through the string */
  2507. y = 0; /* Error code, 0 = no error. */
  2508. debug(F000,"dooutput","",x);
  2509. if (quote) { /* This character is quoted */
  2510. #ifndef NOKVERBS
  2511.            if (x == 'k' || x == 'K') { /* k or K */
  2512.                extern struct keytab kverbs[];
  2513.                extern int nkverbs;
  2514.                extern char * keydefptr;
  2515.                extern int keymac;
  2516.                extern int keymacx;
  2517.                int x, y, brace = 0;
  2518.                int pause;
  2519.                char * p, * b;
  2520.                char kbuf[K_BUFLEN + 1]; /* Key verb name buffer */
  2521.        char osendbuf[SEND_BUFLEN +1];
  2522.                int  sendndx = 0;
  2523.        if (xxout(obuf,obn) < 0) /* Flush buffer */
  2524.  goto outerr;
  2525.        debug(F100,"OUTPUT KVERB","",0); /* Send a KVERB */
  2526.                { /* Have K verb? */
  2527.    if (!*s) {
  2528.                        break;
  2529.                    }
  2530. /*
  2531.   We assume that the verb name is {braced}, or it extends to the end of the
  2532.   string, s, or it ends with a space, control character, or backslash.
  2533. */
  2534.                    p = kbuf; /* Copy verb name into local buffer */
  2535.                    x = 0;
  2536.                    while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
  2537.                        if (brace && *s == '}') {
  2538.                            break;
  2539.                        }
  2540.                        *p++ = *s++;
  2541.                    }
  2542.                    if (*s && !brace) /* If we broke because of , etc, */
  2543.                      s--; /*  back up so we get another look. */
  2544.                    brace = 0;
  2545.                    *p = NUL; /* Terminate. */
  2546.                    p = kbuf; /* Point back to beginning */
  2547.                    debug(F110,"dooutput kverb",p,0);
  2548.                    y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
  2549.                    debug(F101,"dooutput lookup",0,y);
  2550.                    if (y > -1) {
  2551.                        if (sendndx) {
  2552.                            dooutput(osendbuf,cx);
  2553.                            sendndx = 0;
  2554.                        }
  2555.                        dokverb(VCMD,y);
  2556. #ifndef NOSPL
  2557.                    } else { /* Is it a macro? */
  2558.                        y = mxlook(mactab,p,nmac);
  2559.                        if (y > -1) {
  2560.                            cmpush();
  2561.                            keymac = 1; /* Flag for key macro active */
  2562.                            keymacx = y; /* Key macro index */
  2563.                            keydefptr = s; /* Where to resume next time */
  2564.                            debug(F111,"dooutput mxlook",keydefptr,y);
  2565.                            parser(1);
  2566.                            cmpop();
  2567.                        }
  2568. #endif /* NOSPL */
  2569.                    }
  2570.                }
  2571.                quote = 0;
  2572.        continue;
  2573.    } else
  2574. #endif /* NOKVERBS */
  2575.      if (outesc && (x == 'n' || x == 'N')) { /* n or N */
  2576.  if (xxout(obuf,obn) < 0) /* Flush buffer */
  2577.    goto outerr;
  2578.  debug(F100,"OUTPUT NUL","",0); /* Send a NUL */
  2579.  if (local)
  2580.    ttoc(NUL);
  2581.  else
  2582.    conoc(NUL);
  2583.  quote = 0;
  2584.  continue;
  2585.      } else if (outesc && (x == 'b' || x == 'B')) { /* b or B */
  2586. if (xxout(obuf,obn) < 0) /* Flush buffer first */
  2587.   goto outerr;
  2588. debug(F100,"OUTPUT BREAK","",0);
  2589. #ifndef NOLOCAL
  2590. ttsndb(); /* Send BREAK signal */
  2591. #else
  2592.  if (local)
  2593.    ttoc(NUL);
  2594.  else
  2595.    conoc(NUL);
  2596. #endif /* NOLOCAL */
  2597. quote = 0; /* Turn off quote flag */
  2598. continue; /* and not the b or B */
  2599. #ifdef CK_LBRK
  2600.      } else if (outesc && (x == 'l' || x == 'L')) { /* l or L */
  2601.  if (xxout(obuf,obn) < 0) /* Flush buffer first */
  2602.    goto outerr;
  2603.  debug(F100,"OUTPUT Long BREAK","",0);
  2604. #ifndef NOLOCAL
  2605.  ttsndlb(); /* Send Long BREAK signal */
  2606. #else
  2607.  if (local)
  2608.    ttoc(NUL);
  2609.  else
  2610.    conoc(NUL);
  2611. #endif /* NOLOCAL */
  2612.  quote = 0; /* Turn off quote flag */
  2613.  continue; /* and not the l or L */
  2614. #endif /* CK_LBRK */
  2615.      } else if (x == CMDQ) { /* Backslash itself */
  2616.  debug(F100,"OUTPUT CMDQ","",0);
  2617.  xx = oboc(dopar(CMDQ)); /* Output the backslash. */
  2618.  if (xx < 0)
  2619.    goto outerr;
  2620.  quote = 0;
  2621.  continue;
  2622.      } else { /* if  not followed by special esc */
  2623. /* Note: Atari ST compiler won't allow macro call in "if ()" */
  2624.  xx = oboc(dopar(CMDQ)); /* Output the backslash. */
  2625.  if (xx < 0)
  2626.    goto outerr;
  2627.  quote = 0; /* Turn off quote flag */
  2628.      }
  2629. } else if (x == CMDQ) { /* This is the quote character */
  2630.             quote = 1; /* Go back and get next character */
  2631.     continue; /* which is quoted */
  2632. }
  2633. xx = oboc(dopar((char)x)); /* Output this character */
  2634. debug(F111,"dooutput",obuf,obn);
  2635. if (xx < 0)
  2636.   goto outerr;
  2637. #ifdef COMMENT
  2638.         if (seslog && duplex) { /* Log the character if log is on */
  2639.             logchar((char)x);
  2640.         }
  2641. #endif /* COMMENT */
  2642. if (x == '15') { /* String contains carriage return */
  2643.     int stuff = -1, stuff2 = -1;
  2644.     if (tnlm) { /* TERMINAL NEWLINE ON */
  2645. stuff = LF; /* Stuff LF */
  2646.     }
  2647. #ifdef TNCODE
  2648.     /* TELNET NEWLINE ON/OFF/RAW */
  2649.     if (is_tn) {
  2650. switch (TELOPT_ME(TELOPT_BINARY) ? /* NVT or BINARY */
  2651. tn_b_nlm :
  2652. tn_nlm
  2653. ) {
  2654.   case TNL_CR:
  2655.                     break;
  2656.   case TNL_CRNUL:
  2657.                     stuff2 = stuff;
  2658.                     stuff  = NUL;
  2659.                     break;
  2660.   case TNL_CRLF:
  2661.                     stuff2 = stuff;
  2662.                     stuff = LF;
  2663.                     break;
  2664.                 }
  2665.          }
  2666. #endif /* TNCODE */
  2667.     if (stuff > -1) { /* Stuffing another character... */
  2668. xx = oboc(dopar((CHAR)stuff));
  2669. if (xx < 0)
  2670.   goto outerr;
  2671. #ifdef COMMENT
  2672. if (seslog && duplex) { /* Log stuffed char if appropriate */
  2673.                     logchar((char)stuff);
  2674.                 }
  2675. #endif /* COMMENT */
  2676.     }
  2677.     if (stuff2 > -1) { /* Stuffing another character... */
  2678. xx = oboc(dopar((CHAR)stuff2));
  2679. if (xx < 0)
  2680.   goto outerr;
  2681. #ifdef COMMENT
  2682. if (seslog && duplex) { /* Log stuffed char if appropriate */
  2683.                     logchar((char)stuff2);
  2684.                 }
  2685. #endif /* COMMENT */
  2686.     }
  2687.     if (xxout(obuf,obn) < 0) /* Flushing is required here! */
  2688.       goto outerr;
  2689. }
  2690.     }
  2691.     if (cx == XXLNOUT) {
  2692. s = "15";
  2693. cx = 0;
  2694. goto outagain;
  2695.     }
  2696.     if (quote == 1) /* String ended with backslash */
  2697.       xx = oboc(dopar(CMDQ));
  2698.     if (obn > 0) /* OUTPUT done */
  2699.       if (xxout(obuf,obn) < 0) /* Flush the buffer if necessary. */
  2700. goto outerr;
  2701.     return(1);
  2702. outerr: /* OUTPUT command error handler */
  2703.     if (msgflg) printf("?OUTPUT execution errorn");
  2704.     return(0);
  2705. /* Remove "local" OUTPUT macro defininitions */
  2706. #ifdef COMMENT
  2707. /* No more macros ... */
  2708. #undef oboc
  2709. #undef obfls
  2710. #endif /* COMMENT */
  2711. }
  2712. #endif /* NOSPL */
  2713. /* Display version herald and initial prompt */
  2714. VOID
  2715. herald() {
  2716.     int x = 0, i;
  2717.     extern int srvcdmsg;
  2718.     extern char * cdmsgfile[];
  2719. #ifndef NOCMDL
  2720.     extern char * bannerfile;
  2721.     if (bannerfile) {
  2722. concb((char)escape);
  2723. if (dotype(bannerfile,1,0,0,NULL,0,NULL) > 0) {
  2724.     if (srvcdmsg) {
  2725. for (i = 0; i < 8; i++) {
  2726.     if (zchki(cdmsgfile[i]) > -1) {
  2727. printf("n");
  2728. dotype(cdmsgfile[i],xaskmore,0,0,NULL,0,NULL);
  2729. break;
  2730.     }
  2731. }
  2732.     }
  2733.             return;
  2734.         }
  2735.     }
  2736. #endif /* NOCMDL */
  2737. #ifdef COMMENT
  2738.     /* The following generates bad code in SCO compilers. */
  2739.     /* Observed in both OSR5 and Unixware 2 -- after executing this */
  2740.     /* statement when all conditions are false, x has a value of -32. */
  2741.     if (noherald || bgset > 0 || (bgset != 0 && backgrd != 0)) x = 1;
  2742. #else
  2743.     x = 0;
  2744.     if (noherald)
  2745.       x = 1;
  2746.     else if (bgset > 0)
  2747.       x = 1;
  2748.     else if (bgset < 0 && backgrd > 0)
  2749.       x = 1;
  2750. #endif /* COMMENT */
  2751.     if (x == 0) {
  2752. #ifdef datageneral
  2753. printf("%s, for%sn",versio,ckxsys);
  2754. #else
  2755. #ifdef OSK
  2756. printf("%s, for%sn",versio,ckxsys);
  2757. #else
  2758. printf("%s, for%snr",versio,ckxsys);
  2759. #endif /* OSK */
  2760. #endif /* datageneral */
  2761. printf(" Copyright (C) 1985, 2000,n");
  2762. printf("  Trustees of Columbia University in the City of New York.n");
  2763. #ifdef OS2
  2764.        shoreg();
  2765. #endif /* OS2 */
  2766. if (!quiet && !backgrd) {
  2767. #ifdef COMMENT
  2768. /* "Default file-transfer mode is AUTOMATIC" is useless information... */
  2769.     char * s;
  2770.     extern int xfermode;
  2771. #ifdef VMS
  2772.     s = "AUTOMATIC";
  2773. #else
  2774.     if (xfermode == XMODE_A) {
  2775. s = "AUTOMATIC";
  2776.     } else {
  2777. s = gfmode(binary,1);
  2778.     }
  2779.     if (!s) s = "";
  2780. #endif /* VMS */
  2781.     if (*s)
  2782.       printf("Default file-transfer mode is %sn", s);
  2783. #endif /* COMMENT */
  2784.     if (srvcdmsg) {
  2785. for (i = 0; i < 8; i++) {
  2786.     if (zchki(cdmsgfile[i]) > -1) {
  2787. printf("n");
  2788. dotype(cdmsgfile[i],xaskmore,0,0,NULL,0,NULL);
  2789. break;
  2790.     }
  2791. }
  2792.     }
  2793.     printf("Type ? or HELP for help.n");
  2794. }
  2795.     }
  2796. }
  2797. /*  G F M O D E  --  Get File (transfer) Mode  */
  2798. char *
  2799. gfmode(binary,upcase) int binary, upcase; {
  2800.     char * s;
  2801.     switch (binary) {
  2802.       case XYFT_T: s = upcase ? "TEXT" : "text"; break;
  2803. #ifdef VMS
  2804.       case XYFT_B: s = upcase ? "BINARY FIXED" : "binary fixed"; break;
  2805.       case XYFT_I: s = upcase ? "IMAGE" : "image"; break;
  2806.       case XYFT_L: s = upcase ? "LABELED" : "labeled"; break;
  2807.       case XYFT_U: s = upcase ? "BINARY UNDEF" : "binary undef"; break;
  2808. #else
  2809. #ifdef MAC
  2810.       case XYFT_B: s = upcase ? "BINARY" : "binary"; break;
  2811.       case XYFT_M: s = upcase ? "MACBINARY" : "macbinary"; break;
  2812. #else
  2813.       case XYFT_B: s = upcase ? "BINARY" : "binary"; break;
  2814. #ifdef CK_LABELED
  2815.       case XYFT_L: s = upcase ? "LABELED" : "labeled"; break;
  2816. #endif /* CK_LABELED */
  2817. #endif /* MAC */
  2818. #endif /* VMS */
  2819.       default: s = "";
  2820.     }
  2821.     return(s);
  2822. }
  2823. #ifndef NOSPL
  2824. static int
  2825. isaa(s) char * s; { /* Is associative array */
  2826.     char c;
  2827.     int x;
  2828.     if (!s) s = "";
  2829.     if (!*s) return(0);
  2830.     s++;
  2831.     while (c = *s++) {
  2832. if (c == '<') {
  2833.     x = strlen(s);
  2834.     return ((*(s+x-1) == '>') ? 1 : 0);
  2835. }
  2836.     }
  2837.     return(0);
  2838. }
  2839. /*  M L O O K  --  Lookup the macro name in the macro table  */
  2840. /*
  2841.  Call this way:  v = mlook(table,word,n);
  2842.    table - a 'struct mtab' table.
  2843.    word  - the target string to look up in the table.
  2844.    n     - the number of elements in the table.
  2845.  The keyword table must be arranged in ascending alphabetical order, and
  2846.  all letters must be lowercase.
  2847.  Returns the table index, 0 or greater, if the name was found, or:
  2848.   -3 if nothing to look up (target was null),
  2849.   -2 if ambiguous,
  2850.   -1 if not found.
  2851.  A match is successful if the target matches a keyword exactly, or if
  2852.  the target is a prefix of exactly one keyword.  It is ambiguous if the
  2853.  target matches two or more keywords from the table.
  2854. */
  2855. int
  2856. mlook(table,cmd,n) struct mtab table[]; char *cmd; int n; {
  2857.     int x, i, v, cmdlen;
  2858. /* Lowercase & get length of target, if it's null return code -3. */
  2859.     if ((((cmdlen = cklower(cmd))) == 0) || (n < 1)) return(-3);
  2860. /* Not null, look it up */
  2861.     for (i = 0; i < n-1; i++) {
  2862.         if (!strcmp(table[i].kwd,cmd) ||
  2863.            ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
  2864.              strncmp(table[i+1].kwd,cmd,cmdlen))) {
  2865.                 return(i);
  2866.              }
  2867.         if (v) return(-2);
  2868.     }
  2869. /* Last (or only) element */
  2870.     if (!strncmp(table[n-1].kwd,cmd,cmdlen)) {
  2871.         return(n-1);
  2872.     } else return(-1);
  2873. }
  2874. /* mxlook is like mlook, but an exact full-length match is required */
  2875. int
  2876. mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
  2877.     int i, cmdlen;
  2878.     if ((((cmdlen = cklower(cmd))) == 0) || (n < 1)) return(-3);
  2879.     /* debug(F111,"mxlook target",cmd,n); */
  2880.     for (i = 0; i < n; i++) {
  2881. /* debug(F111,"mxlook",table[i].kwd,i); */
  2882. if (((int)strlen(table[i].kwd) == cmdlen) &&
  2883.     (!strncmp(table[i].kwd,cmd,cmdlen))) return(i);
  2884.     }
  2885.     return(-1);
  2886. }
  2887. /* mxxlook is like mxlook, but but case-sensitive */
  2888. int
  2889. mxxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
  2890.     int i, cmdlen;
  2891.     if (!cmd) cmd = "";
  2892.     if (((cmdlen = strlen(cmd)) < 1) || (n < 1)) return(-3);
  2893.     /* debug(F111,"mxxlook target",cmd,n); */
  2894.     for (i = 0; i < n; i++) {
  2895. if (((int)strlen(table[i].kwd) == cmdlen) &&
  2896.     (!strncmp(table[i].kwd,cmd,cmdlen))) return(i);
  2897.     }
  2898.     return(-1);
  2899. }
  2900. static int
  2901. traceval(nam, val) char * nam, * val; { /* For TRACE command */
  2902.     if (val)
  2903.       printf(">>> %s: "%s"n", nam, val);
  2904.     else
  2905.       printf(">>> %s: (undef)n", nam);
  2906.     return(0);
  2907. }
  2908. /*
  2909.   This routine is for the benefit of those compilers that can't handle
  2910.   long string constants or continued lines within them.  Long predefined
  2911.   macros like FOR, WHILE, and XIF have their contents broken up into
  2912.   arrays of string pointers.  This routine concatenates them back into a
  2913.   single string again, and then calls the real addmac() routine to enter
  2914.   the definition into the macro table.
  2915. */
  2916. int
  2917. addmmac(nam,s) char *nam, *s[]; { /* Add a multiline macro definition */
  2918.     int i, x, y; char *p;
  2919.     x = 0; /* Length counter */
  2920.     for (i = 0; (y = (int)strlen(s[i])) > 0; i++) { /* Add up total length */
  2921.      debug(F111,"addmmac line",s[i],y);
  2922. x += y;
  2923.     }
  2924.     debug(F101,"addmmac lines","",i);
  2925.     debug(F101,"addmmac loop exit","",y);
  2926.     debug(F111,"addmmac length",nam,x);
  2927.     if (x < 0) return(-1);
  2928.     p = malloc(x+1); /* Allocate space for all of it. */
  2929.     if (!p) {
  2930. printf("?addmmac malloc error: %sn",nam);
  2931. debug(F110,"addmmac malloc error",nam,0);
  2932. return(-1);
  2933.     }
  2934.     *p = ''; /* Start off with null string. */
  2935.     for (i = 0; *s[i]; i++) /* Concatenate them all together. */
  2936.       strcat(p,s[i]);
  2937.     y = (int)strlen(p); /* Final precaution. */
  2938.     debug(F111,"addmmac constructed string",p,y);
  2939.     if (y == x) {
  2940. y = addmac(nam,p); /* Add result to the macro table. */
  2941.     } else {
  2942. debug(F100,"addmmac length mismatch","",0);
  2943. printf("n!addmmac internal error!n");
  2944. y = -1;
  2945.     }
  2946.     free(p); /* Free the temporary copy. */
  2947.     return(y);
  2948. }
  2949. /* Here is the real addmac routine. */
  2950. /* Returns -1 on failure, macro table index >= 0 on success. */