4 /* C K U U S 6 -- "User Interface" for Unix Kermit (Part 6) */
8 Frank da Cruz <fdc@columbia.edu>,
9 The Kermit Project, Columbia University, New York City
10 Jeffrey E Altman <jaltman@secure-endpoints.com>
11 Secure Endpoints Inc., New York City
13 Copyright (C) 1985, 2004,
14 Trustees of Columbia University in the City of New York.
15 All rights reserved. See the C-Kermit COPYING.TXT file or the
16 copyright text in the ckcmai.c module for disclaimer and permissions.
26 #include "ckcnet.h" /* Network symbols */
32 #endif /* TCPSOCKET */
36 #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
37 #endif /* datageneral */
40 #define readblock kreadblock
43 /* External Kermit Variables, see ckmain.c for description. */
45 extern xx_strp xxstring;
47 extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
48 turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
49 zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive;
51 extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive,
52 xcmdsrc, nscanfile, reliable, nolinks;
55 extern int zgfs_dir, zgfs_link;
56 #endif /* VMSORUNIX */
63 extern int StartedFromDialer ;
68 #define INCL_VIO /* Needed for ckocon.h */
80 extern long vernum, speed;
81 extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
82 extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
83 extern char *foz_def[];
84 extern char *ckxsys, *ckzsys;
91 extern char ttname[], filnam[];
92 extern CHAR sstate, feol;
96 extern char ** mtchs; /* zxpand() file list */
100 extern int oopts, omode, oname, opath; /* O-Packet options */
102 extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
103 stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
104 atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
105 fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
106 g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
107 g_fnspath, g_fnrpath, xfrxla, g_xfrxla;
109 extern char *cmarg, *cmarg2;
111 #ifndef NOMSEND /* Multiple SEND */
112 extern char *msfiles[];
114 extern char fspec[]; /* Most recent filespec */
118 extern int f_tmpdir; /* Directory changed temporarily */
119 extern char savdir[]; /* For saving current directory */
120 #endif /* CK_TMPDIR */
122 extern struct keytab protos[]; /* File transfer protocols */
123 extern struct ck_p ptab[NPROTOS];
126 #ifdef DCMDBUF /* Declarations from cmd package */
127 extern char *cmdbuf, *atmbuf; /* Command buffers */
129 extern char cmdbuf[], atmbuf[]; /* Command buffers */
135 int askflag = 0; /* ASK-class command active */
136 extern char **a_ptr[];
138 extern char **m_xarg[];
140 extern struct mtab *mactab;
142 extern long ck_alarm;
143 extern char alrm_date[], alrm_time[];
147 extern int inserver; /* I am IKSD */
148 extern int backgrd; /* Kermit executing in background */
149 extern char psave[]; /* For saving & restoring prompt */
150 extern char *tp; /* Temporary buffer */
152 int readblock = 4096; /* READ buffer size */
153 CHAR * readbuf = NULL; /* Pointer to read buffer */
154 int readsize = 0; /* Number of chars actually read */
155 int getcmd = 0; /* GET-class command was given */
157 extern int zchkod, zchkid;
159 struct keytab deltab[] = { /* DELETE Command Options */
160 { "/all", DEL_ALL, CM_INV },
161 { "/after", DEL_AFT, CM_ARG },
162 { "/ask", DEL_ASK, 0 },
163 { "/before", DEL_BEF, CM_ARG },
164 { "/directories", DEL_DIR, 0 },
165 { "/dotfiles", DEL_DOT, 0 },
166 { "/except", DEL_EXC, CM_ARG },
167 { "/heading", DEL_HDG, 0 },
168 { "/l", DEL_LIS, CM_INV|CM_ABR },
169 { "/larger-than", DEL_LAR, CM_ARG },
170 { "/list", DEL_LIS, 0 },
171 { "/log", DEL_LIS, CM_INV },
172 { "/noask", DEL_NAS, 0 },
173 { "/nodotfiles", DEL_NOD, 0 },
174 { "/noheading", DEL_NOH, 0 },
175 { "/nol", DEL_NOL, CM_INV|CM_ABR },
176 { "/nolist", DEL_NOL, 0 },
177 { "/nolog", DEL_NOL, CM_INV },
178 { "/nopage", DEL_NOP, 0 },
179 { "/not-after", DEL_NAF, CM_ARG },
180 { "/not-before", DEL_NBF, CM_ARG },
181 { "/not-since", DEL_NAF, CM_INV|CM_ARG },
182 { "/page", DEL_PAG, 0 },
183 { "/quiet", DEL_QUI, CM_INV },
184 { "/recursive", DEL_REC, 0 },
185 { "/simulate", DEL_SIM, 0 },
186 { "/since", DEL_AFT, CM_ARG|CM_INV },
187 { "/smaller-than", DEL_SMA, CM_ARG },
188 { "/summary", DEL_SUM, 0 },
189 { "/tree", DEL_ALL, 0 },
190 { "/type", DEL_TYP, CM_ARG },
191 { "/verbose", DEL_VRB, CM_INV }
193 int ndeltab = sizeof(deltab)/sizeof(struct keytab);
195 /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
197 struct keytab qvswtab[] = {
198 { "/l", DEL_LIS, CM_INV|CM_ABR },
199 { "/list", DEL_LIS, 0 },
200 { "/log", DEL_LIS, CM_INV },
201 { "/nol", DEL_NOL, CM_INV|CM_ABR },
202 { "/nolist", DEL_NOL, 0 },
203 { "/nolog", DEL_NOL, CM_INV },
204 { "/quiet", DEL_QUI, CM_INV },
205 { "/verbose", DEL_VRB, CM_INV }
207 int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
209 struct keytab copytab[] = {
210 { "/append", 998, 0 },
212 { "/fromb64", 997, 0 },
214 { "/l", DEL_LIS, CM_INV|CM_ABR },
215 { "/list", DEL_LIS, 0 },
216 { "/log", DEL_LIS, CM_INV },
217 { "/nol", DEL_NOL, CM_INV|CM_ABR },
218 { "/nolist", DEL_NOL, 0 },
219 { "/nolog", DEL_NOL, CM_INV },
220 { "/quiet", DEL_QUI, CM_INV },
221 { "/swap-bytes", 999, 0 },
223 { "/tob64", 996, 0 },
225 { "/verbose", DEL_VRB, CM_INV }
227 int ncopytab = sizeof(copytab)/sizeof(struct keytab);
230 static struct keytab gettab[] = { /* GET options */
231 { "/as-name", SND_ASN, CM_ARG },
232 { "/binary", SND_BIN, 0 },
234 { "/calibrate", SND_CAL, CM_INV },
235 #endif /* CALIBRATE */
237 { "/command", SND_CMD, CM_PSH },
238 #endif /* PIPESEND */
239 { "/delete", SND_DEL, 0 },
240 { "/except", SND_EXC, CM_ARG },
241 { "/filenames", SND_NAM, CM_ARG },
243 { "/filter", SND_FLT, CM_ARG|CM_PSH },
244 #endif /* PIPESEND */
246 { "/image", SND_IMG, 0 },
247 { "/labeled", SND_LBL, 0 },
249 { "/image", SND_BIN, CM_INV },
252 { "/move-to", SND_MOV, CM_ARG },
253 #endif /* CK_TMPDIR */
254 { "/pathnames", SND_PTH, CM_ARG },
255 { "/pipes", SND_PIP, CM_ARG|CM_PSH },
256 { "/quiet", SND_SHH, 0 },
258 { "/recover", SND_RES, 0 },
259 #endif /* CK_RESEND */
260 { "/recursive", SND_REC, 0 },
261 { "/rename-to", SND_REN, CM_ARG },
263 { "/smaller-than", SND_SMA, CM_ARG },
265 { "/subdirectories", SND_REC, CM_INV },
266 { "/text", SND_TXT, 0 },
267 { "/transparent", SND_XPA, 0 }
269 #define NGETTAB sizeof(gettab)/sizeof(struct keytab)
270 static int ngettab = NGETTAB;
272 static struct keytab rcvtab[] = { /* RECEIVE options */
273 { "/as-name", SND_ASN, CM_ARG },
274 { "/binary", SND_BIN, 0 },
276 { "/calibrate", SND_CAL, CM_INV },
277 #endif /* CALIBRATE */
279 { "/command", SND_CMD, CM_PSH },
280 #endif /* PIPESEND */
281 { "/except", SND_EXC, CM_ARG },
282 { "/filenames", SND_NAM, CM_ARG },
284 { "/filter", SND_FLT, CM_ARG|CM_PSH },
285 #endif /* PIPESEND */
287 { "/image", SND_IMG, 0 },
288 { "/labeled", SND_LBL, 0 },
290 { "/image", SND_BIN, CM_INV },
293 { "/move-to", SND_MOV, CM_ARG },
294 #endif /* CK_TMPDIR */
295 { "/pathnames", SND_PTH, CM_ARG },
296 { "/pipes", SND_PIP, CM_ARG|CM_PSH },
298 { "/protocol", SND_PRO, CM_ARG },
300 { "/protocol", SND_PRO, CM_ARG|CM_INV },
302 { "/quiet", SND_SHH, 0 },
303 { "/recursive", SND_REC, 0 },
304 { "/rename-to", SND_REN, CM_ARG },
305 { "/text", SND_TXT, 0 },
306 { "/transparent", SND_XPA, 0 }
308 #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
309 static int nrcvtab = NRCVTAB;
317 struct keytab waittab[] = {
318 { "cd", BM_DCD, CM_INV }, /* (Carrier Detect) */
319 { "cts", BM_CTS, CM_INV }, /* (Clear To Send) */
320 { "dsr", BM_DSR, CM_INV }, /* (Data Set Ready) */
321 { "file", WAIT_FIL, 0 }, /* New category selector keywords */
322 { "modem-signals", WAIT_MDM, 0 }, /* ... */
323 { "ri", BM_RNG, CM_INV } /* (Ring Indicator) */
325 int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
327 /* Modem signal table */
329 struct keytab mstab[] = {
330 { "cd", BM_DCD, 0 }, /* Carrier Detect */
331 { "cts", BM_CTS, 0 }, /* Clear To Send */
332 { "dsr", BM_DSR, 0 }, /* Data Set Ready */
333 { "ri", BM_RNG, 0 } /* Ring Indicator */
335 int nms = (sizeof(mstab) / sizeof(struct keytab));
341 struct keytab wfswi[] = { /* WAIT FILE switches */
342 { "creation", WF_CRE, 0 }, /* Wait for file to be created */
343 { "deletion", WF_DEL, 0 }, /* Wait for file to be deleted */
344 { "modification", WF_MOD, 0 } /* Wait for file to be modified */
346 int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
349 struct keytab asgtab[] = { /* Assignment operators for "." */
350 { "::=", 2, 0 }, /* ASSIGN and EVALUATE */
351 { ":=", 1, 0 }, /* ASSIGN */
352 { "=", 0, 0 } /* DEFINE */
354 int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
356 struct keytab opntab[] = {
358 { "!read", OPN_PI_R, CM_INV },
359 { "!write", OPN_PI_W, CM_INV },
361 { "append", OPN_FI_A, 0 },
362 { "host", OPN_NET, 0 },
364 { "line", OPN_SER, CM_INV },
365 { "port", OPN_SER, 0 },
367 { "line", OPN_SER, 0 },
368 { "port", OPN_SER, CM_INV },
370 { "read", OPN_FI_R, 0 },
371 { "write", OPN_FI_W, 0 }
373 int nopn = (sizeof(opntab) / sizeof(struct keytab));
377 #define XXIFCO 0 /* IF COUNT */
378 #define XXIFER 1 /* IF ERRORLEVEL */
379 #define XXIFEX 2 /* IF EXIST */
380 #define XXIFFA 3 /* IF FAILURE */
381 #define XXIFSU 4 /* IF SUCCESS */
382 #define XXIFNO 5 /* IF NOT */
383 #define XXIFDE 6 /* IF DEFINED */
384 #define XXIFEQ 7 /* IF EQUAL (strings) */
385 #define XXIFAE 8 /* IF = (numbers) */
386 #define XXIFLT 9 /* IF < (numbers) */
387 #define XXIFGT 10 /* IF > (numbers) */
388 #define XXIFLL 11 /* IF Lexically Less Than (strings) */
389 #define XXIFLG 12 /* IF Lexically Greater Than (strings) */
390 #define XXIFEO 13 /* IF EOF (READ file) */
391 #define XXIFBG 14 /* IF BACKGROUND */
392 #define XXIFNU 15 /* IF NUMERIC */
393 #define XXIFFG 16 /* IF FOREGROUND */
394 #define XXIFDI 17 /* IF DIRECTORY */
395 #define XXIFNE 18 /* IF NEWER */
396 #define XXIFRO 19 /* IF REMOTE-ONLY */
397 #define XXIFAL 20 /* IF ALARM */
398 #define XXIFSD 21 /* IF STARTED-FROM-DIALER */
399 #define XXIFTR 22 /* IF TRUE */
400 #define XXIFNT 23 /* IF FALSE */
401 #define XXIFTM 24 /* IF TERMINAL-MACRO */
402 #define XXIFEM 25 /* IF EMULATION */
403 #define XXIFOP 26 /* IF OPEN */
404 #define XXIFLE 27 /* IF <= */
405 #define XXIFGE 28 /* IF >= */
406 #define XXIFIP 29 /* IF INPATH */
407 #define XXIFTA 30 /* IF TAPI */
408 #define XXIFMA 31 /* IF MATCH */
409 #define XXIFFL 32 /* IF FLAG */
410 #define XXIFAB 33 /* IF ABSOLUTE */
411 #define XXIFAV 34 /* IF AVAILABLE */
412 #define XXIFAT 35 /* IF ASKTIMEOUT */
413 #define XXIFRD 36 /* IF READABLE */
414 #define XXIFWR 37 /* IF WRITEABLE */
415 #define XXIFAN 38 /* IF ... AND ... */
416 #define XXIFOR 39 /* IF ... OR ... */
417 #define XXIFLP 40 /* IF left parenthesis */
418 #define XXIFRP 41 /* IF right parenthesis */
419 #define XXIFNQ 42 /* IF != (== "NOT =") */
420 #define XXIFQU 43 /* IF QUIET */
421 #define XXIFCK 44 /* IF C-KERMIT */
422 #define XXIFK9 45 /* IF K-95 */
423 #define XXIFMS 46 /* IF MS-KERMIT */
424 #define XXIFWI 47 /* IF WILD */
425 #define XXIFLO 48 /* IF LOCAL */
426 #define XXIFCM 49 /* IF COMMAND */
427 #define XXIFFP 50 /* IF FLOAT */
428 #define XXIFIK 51 /* IF IKS */
429 #define XXIFKB 52 /* IF KBHIT */
430 #define XXIFKG 53 /* IF KERBANG */
431 #define XXIFVE 54 /* IF VERSION */
432 #define XXIFDC 55 /* IF DECLARED */
433 #define XXIFGU 56 /* IF GUI */
435 struct keytab iftab[] = { /* IF commands */
444 { "==", XXIFAE, CM_INV },
447 { "absolute", XXIFAB, 0 },
448 { "alarm", XXIFAL, 0 },
449 { "and", XXIFAN, 0 },
450 { "asktimeout", XXIFAT, 0 },
451 { "available", XXIFAV, 0 },
452 { "background", XXIFBG, 0 },
453 { "c-kermit", XXIFCK, 0 },
454 { "command", XXIFCM, 0 },
455 { "count", XXIFCO, 0 },
456 { "dcl", XXIFDC, CM_INV },
457 { "declared", XXIFDC, 0 },
458 { "defined", XXIFDE, 0 },
460 { "directory", XXIFDI, 0 },
461 #endif /* CK_TMPDIR */
462 { "emulation", XXIFEM, 0 },
464 { "eof", XXIFEO, 0 },
466 { "equal", XXIFEQ, 0 },
467 { "error", XXIFFA, CM_INV },
468 { "exist", XXIFEX, 0 },
469 { "failure", XXIFFA, 0 },
470 { "false", XXIFNT, 0 },
471 { "flag", XXIFFL, 0 },
473 { "float", XXIFFP, 0 },
475 { "foreground", XXIFFG, 0 },
477 { "gui", XXIFGU, 0 },
479 { "gui", XXIFGU, CM_INV },
482 { "iksd", XXIFIK, 0 },
484 { "iksd", XXIFIK, CM_INV },
486 { "integer", XXIFNU, CM_INV },
487 { "k-95", XXIFK9, 0 },
488 { "kbhit", XXIFKB, 0 },
490 { "kerbang", XXIFKG, 0 },
492 { "kerbang", XXIFKG, CM_INV },
494 { "lgt", XXIFLG, 0 },
495 { "llt", XXIFLL, 0 },
496 { "local", XXIFLO, 0 },
497 { "match", XXIFMA, 0 },
498 { "ms-kermit", XXIFMS, CM_INV },
500 { "newer", XXIFNE, 0 },
502 { "not", XXIFNO, 0 },
503 { "numeric", XXIFNU, 0 },
504 { "ok", XXIFSU, CM_INV },
505 { "open", XXIFOP, 0 },
507 { "quiet", XXIFQU, 0 },
508 { "readable", XXIFRD, 0 },
509 { "remote-only",XXIFRO, 0 },
510 { "started-from-dialer",XXIFSD, CM_INV },
511 { "success", XXIFSU, 0 },
512 { "tapi", XXIFTA, 0 },
514 { "terminal-macro", XXIFTM, 0 },
516 { "terminal-macro", XXIFTM, CM_INV },
518 { "true", XXIFTR, 0 },
519 { "version", XXIFVE, 0 },
520 { "wild", XXIFWI, 0 },
521 { "writeable", XXIFWR, 0 },
525 int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
527 struct keytab iotab[] = { /* Keywords for IF OPEN */
528 { "!read-file", ZRFILE, CM_INV },
529 { "!write-file", ZWFILE, CM_INV },
530 { "append-file", ZWFILE, CM_INV },
531 { "connection", 8888, 0 },
533 { "cx-log", 7777, 0 },
534 #endif /* CKLOGDIAL */
535 { "debug-log", ZDFILE, 0 },
536 { "error", 9999, 0 },
537 { "packet-log", ZPFILE, 0 },
538 { "read-file", ZRFILE, 0 },
539 { "screen", ZSTDIO, 0 },
540 { "session-log", ZSFILE, 0 },
541 { "transaction-log", ZTFILE, 0 },
542 { "write-file", ZWFILE, 0 }
544 int niot = (sizeof(iotab) / sizeof(struct keytab));
547 /* Variables and prototypes */
550 extern int nnetdir; /* How many network directories */
553 _PROTOTYP(int ck_krb4_is_installed,(void));
554 _PROTOTYP(int ck_krb5_is_installed,(void));
555 _PROTOTYP(int ck_ntlm_is_installed,(void));
556 _PROTOTYP(int ck_srp_is_installed,(void));
557 _PROTOTYP(int ck_ssleay_is_installed,(void));
558 _PROTOTYP(int ck_ssh_is_installed,(void));
559 _PROTOTYP(int ck_crypt_is_installed,(void));
561 #define ck_krb4_is_installed() (0)
562 #define ck_krb5_is_installed() (0)
563 #define ck_ntlm_is_installed() (0)
564 #define ck_srp_is_installed() (0)
565 #define ck_ssleay_is_installed() (0)
566 #define ck_ssh_is_installed() (0)
567 #define ck_crypt_is_installed() (0)
568 #endif /* CK_SECURITY */
578 struct keytab availtab[] = { /* Available authentication types */
579 { "crypto", AV_CRYPTO, CM_INV }, /* and encryption */
580 { "encryption", AV_CRYPTO, 0 },
581 { "k4", AV_KRB4, CM_INV },
582 { "k5", AV_KRB5, CM_INV },
583 { "kerberos4", AV_KRB4, 0 },
584 { "kerberos5", AV_KRB5, 0 },
585 { "krb4", AV_KRB4, CM_INV },
586 { "krb5", AV_KRB5, CM_INV },
587 { "ntlm", AV_NTLM, 0 },
588 { "srp", AV_SRP, 0 },
589 { "ssh", AV_SSH, 0 },
590 { "ssl", AV_SSL, 0 },
591 { "tls", AV_SSL, 0 },
594 int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
597 _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
598 _PROTOTYP(static int dncvt, (int, int, int, int) );
599 _PROTOTYP(char * getdname, (void) );
601 static int partial = 0; /* For partial dial */
602 static char *dscopy = NULL;
605 char *dialnum = (char *)0; /* Remember DIAL number for REDIAL */
606 int dirline = 0; /* Dial directory line number */
607 extern char * dialdir[]; /* Dial directory file names */
608 extern int dialdpy; /* DIAL DISPLAY on/off */
609 extern int ndialdir; /* How many dial directories */
610 extern int ntollfree; /* Toll-free call info */
611 extern int ndialpxx; /* List of PBX exchanges */
612 extern char *dialtfc[];
613 char * matchpxx = NULL; /* PBX exchange that matched */
614 extern int nlocalac; /* Local area-code list */
615 extern char * diallcac[];
618 extern int tapiconv; /* TAPI Conversions */
619 extern int tapipass; /* TAPI Passthrough */
622 extern char * dialnpr, * dialsfx;
623 extern char * dialixp, * dialixs, * dialmac;
624 extern char * dialldp, * diallds, * dialtfp;
625 extern char * dialpxi, * dialpxo, * diallac;
626 extern char * diallcp, * diallcs, * diallcc;
627 extern char * dialpxx[];
629 extern int dialcnf; /* DIAL CONFIRMATION */
630 int dialfld = 0; /* DIAL FORCE-LONG-DISTANCE */
631 int dialsrt = 1; /* DIAL SORT ON */
632 int dialrstr = 6; /* DIAL RESTRICTION */
633 int dialtest = 0; /* DIAL TEST */
634 int dialcount = 0; /* \v(dialcount) */
636 extern int dialsta; /* Dial status */
637 int dialrtr = -1, /* Dial retries */
638 dialint = 10; /* Dial retry interval */
639 extern long dialcapas; /* Modem capabilities */
640 extern int dialcvt; /* DIAL CONVERT-DIRECTORY */
644 #define IFCONDLEN 256
645 int ifc, /* IF case */
646 not = 0, /* Flag for IF NOT */
647 ifargs = 0; /* Count of IF condition words */
648 char ifcond[IFCONDLEN]; /* IF condition text */
649 char *ifcp; /* Pointer to IF condition text */
652 *ifcmd, *count, *iftest, *intime,
653 *inpcas, *takerr, *merror, *xquiet;
655 extern int ifcmd[]; /* Last command was IF */
656 extern int iftest[]; /* Last IF was true */
657 extern int count[]; /* For IF COUNT, one for each cmdlvl */
658 extern int intime[]; /* Ditto for other stackables... */
669 extern char *line; /* Character buffer for anything */
672 extern char line[], tmpbuf[];
674 extern char *lp; /* Pointer to line buffer */
676 int cwdf = 0; /* CWD has been done */
678 /* Flags for ENABLE/DISABLE */
679 extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
680 en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
681 en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
683 extern FILE *tfile[]; /* File pointers for TAKE command */
684 extern char *tfnam[]; /* Names of TAKE files */
685 extern int tfline[]; /* TAKE-file line number */
687 extern int success; /* Command success/failure flag */
688 extern int cmdlvl; /* Current position in command stack */
691 extern int maclvl; /* Macro to execute */
692 extern char *macx[]; /* Index of current macro */
693 extern char *mrval[]; /* Macro return value */
694 extern char *macp[]; /* Pointer to macro */
695 extern int macargc[]; /* ARGC from macro invocation */
698 extern char *m_line[];
701 extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */
702 extern char *g_var[]; /* Global variables %a, %b, etc */
705 extern struct cmdptr *cmdstk; /* The command stack itself */
707 extern struct cmdptr cmdstk[]; /* The command stack itself */
711 #define xsystem(s) zsyscmd(s)
713 static int x, y, z = 0;
717 _PROTOTYP( int os2settitle, (char *, int) );
720 extern struct keytab yesno[], onoff[], fntab[];
721 extern int nyesno, nfntab;
725 /* Do the ASK, ASKQ, GETOK, and READ commands */
735 static struct keytab asktab[] = {
736 { "/default", ASK_DEF, CM_ARG },
751 { "/quiet", ASK_QUI, 0 },
752 { "/timeout", ASK_TMO, CM_ARG },
755 static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1;
759 extern int cmflgs, asktimer, timelimit;
761 extern int on_recall;
762 #endif /* CK_RECALL */
768 extern int apcactive, apcstatus;
771 char dfbuf[1024]; /* Buffer for default answer */
772 char * dfanswer = NULL; /* Pointer to it */
774 char vnambuf[VNAML+1]; /* Buffer for variable names */
775 char *vnp = NULL; /* Pointer to same */
781 if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
786 mytimer = asktimer; /* Inherit global ASK timer */
788 if (cx == XXASK || cx == XXASKQ) {
792 if (cx == XXASKQ) /* Don't log ASKQ response */
794 cmfdbi(&sw, /* First FDB - command switches */
796 "Variable name or switch",
798 "", /* addtl string data */
799 nasktab, /* addtl numeric data 1: tbl size */
800 4, /* addtl numeric data 2: 4 = cmswi */
801 xxstring, /* Processing function */
802 asktab, /* Keyword table */
803 &fl /* Pointer to next FDB */
805 cmfdbi(&fl, /* Anything that doesn't match */
809 "", /* addtl string data */
810 0, /* addtl numeric data 1 */
811 0, /* addtl numeric data 2 */
816 while (1) { /* Parse 0 or more switches */
817 x = cmfdb(&sw); /* Parse something */
820 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
823 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
824 printf("?This switch does not take an argument\n");
827 if (!getval && (cmgkwflgs() & CM_ARG)) {
828 printf("?This switch requires an argument\n");
831 switch (cmresult.nresult) {
842 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
850 if ((y = cmfld("Text to supply if reply is empty",
851 "",&s,xxstring)) < 0)
853 ckstrncpy(dfbuf,s,1024);
860 /* Have variable name, make copy. */
861 ckstrncpy(vnambuf,cmresult.sresult,VNAML);
863 if (vnambuf[0] == CMDQ &&
864 (vnambuf[1] == '%' || vnambuf[1] == '&'))
867 if (*vnp == '%' || *vnp == '&') {
868 if ((y = parsevar(vnp,&x,&z)) < 0)
871 } else if (cx != XXGOK && cx != XXRDBL) { /* Get variable name */
872 if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
874 printf("?Variable name required\n");
878 ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */
880 if (vnambuf[0] == CMDQ &&
881 (vnambuf[1] == '%' || vnambuf[1] == '&'))
884 if (*vnp == '%' || *vnp == '&') {
885 if ((y = parsevar(vnp,&x,&z)) < 0)
889 if (cx == XXREA || cx == XXRDBL) { /* READ or READBLOCK command */
890 if ((y = cmcfm()) < 0) /* Get confirmation */
892 if (chkfn(ZRFILE) < 1) { /* File open? */
893 printf("?Read file not open\n");
896 if (!(s = (char *)readbuf)) { /* Where to read into. */
897 printf("?Oops, no READ buffer!\n");
900 y = zsinl(ZRFILE, s, readblock); /* Read a line. */
901 debug(F111,"read zsinl",s,y);
902 if (y < 0) { /* On EOF or other error, */
903 zclose(ZRFILE); /* close the file, */
904 delmac(vnp,0); /* delete the variable, */
905 return(success = 0); /* and return failure. */
906 } else { /* Read was OK. */
907 readsize = (int) strlen(s);
908 success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
909 debug(F111,"read addmac",vnp,success);
910 return(success); /* Return success. */
914 /* ASK, ASKQ, GETOK, or GETC */
916 if (cx == XXGOK) { /* GETOK can take switches */
920 cmfdbi(&sw, /* First FDB - command switches */
922 "Variable name or question prompt",
924 "", /* addtl string data */
925 nasktab, /* addtl numeric data 1: tbl size */
926 4, /* addtl numeric data 2: 4 = cmswi */
927 xxstring, /* Processing function */
928 asktab, /* Keyword table */
929 &fl /* Pointer to next FDB */
931 cmfdbi(&fl, /* Anything that doesn't match */
935 "", /* addtl string data */
936 0, /* addtl numeric data 1 */
937 0, /* addtl numeric data 2 */
942 while (1) { /* Parse 0 or more switches */
943 x = cmfdb(&sw); /* Parse something */
946 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
949 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
950 printf("?This switch does not take an argument\n");
953 if (!getval && (cmgkwflgs() & CM_ARG)) {
954 printf("?This switch requires an argument\n");
957 switch (cmresult.nresult) {
965 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
973 if ((y = cmfld("Text to supply if reply is empty",
974 "",&s,xxstring)) < 0)
976 ckstrncpy(dfbuf,s,1024);
986 p = cmresult.sresult;
990 enclose in { braces } or \" quotes \" to preserve leading and trailing\n\
991 spaces, precede question mark with backslash (\\).",
992 "",&p,xxstring)) < 0)
998 if (popupflg) { /* Popup requested */
1000 ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
1002 if (cx == XXASK || cx == XXASKQ) {
1004 len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1006 len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1007 asktimedout = ( len < 0 && mytimer );
1008 } else if (cx == XXGOK) {
1009 printf("?Sorry, GETOK /POPUP not implemented yet\n");
1014 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1015 } else if ( asktimedout && dfanswer ) {
1016 y = addmac(vnp,dfanswer); /* Add it to the macro table. */
1021 return(success = ((len >= 0) && (y >= 0)) && !asktimedout);
1024 if (guiflg) { /* GUI requested */
1029 zzstring(brstrip(p),&s1,&n);
1031 if (cx == XXASK || cx == XXASKQ) {
1032 rc = gui_txt_dialog(NULL,p,(cx == XXASK),
1033 line,LINBUFSIZ,dfanswer,mytimer);
1034 asktimedout = (rc == -1 && mytimer);
1036 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1037 } else if ( asktimedout && dfanswer ) {
1038 y = addmac(vnp,dfanswer); /* Add default to macro table. */
1043 return(success = (rc == 1 && (y >= 0)) && !asktimedout);
1044 } else if (cx == XXGOK) {
1046 x = lookup(yesno,dfanswer,nyesno,NULL);
1048 rc = uq_ok(NULL, p, 3, NULL, x);
1049 return(success = (rc == 1));
1054 #endif /* NOLOCAL */
1056 concb((char)escape); /* Enter CBREAK mode */
1057 cmsavp(psave,PROMPTL); /* Save old prompt */
1058 cmsetp(brstrip(p)); /* Make new prompt */
1060 if (cx == XXASKQ) { /* For ASKQ, */
1061 cmini(0); /* no-echo mode. */
1062 } else { /* For others, regular echoing. */
1066 x = -1; /* This means to reparse. */
1069 prompt(xxstring); /* Issue prompt. */
1071 asktimedout = 0; /* Handle timed responses. */
1072 timelimit = mytimer;
1075 if (cx == XXGOK) { /* GETOK */
1078 #endif /* CK_RECALL */
1080 /* GETOK uses keyword table */
1081 x = cmkey(yesno,nyesno,"",dfanswer,xxstring);
1082 if (x < 0) { /* Parse error */
1085 ds = dfanswer ? dfanswer : "No";
1087 printf("?Timed out, assuming \"%s\"",ds);
1090 x = lookup(yesno,ds,nyesno,NULL);
1093 } else if (x == -3) { /* No answer? */
1094 printf("Please respond Yes or No\n"); /* Make them answer */
1097 } else if (x == -1) {
1102 if (cmcfm() < 0) /* Get confirmation */
1106 cmsetp(psave); /* Restore prompt */
1108 if (cmdlvl > 0) /* In VMS and not at top level, */
1109 conres(); /* restore console again. */
1112 return(x); /* Return success or failure */
1113 } else if (cx == XXGETC /* GETC */
1115 || cx == XXGETK /* or GETKEYCODE */
1119 conbin((char)escape); /* Put keyboard in raw mode */
1122 if (cx == XXGETK) { /* GETKEYCODE */
1125 t = os2gks; /* Turn off kverb recognition */
1127 x = congks(timelimit); /* Read a key event, blocking */
1128 os2gks = t; /* Put back kverb recognition */
1131 #endif /* NOSETKEY */
1133 debug(F101,"GETC conchk","",conchk());
1134 x = coninc(timelimit); /* Just read one character */
1135 debug(F101,"GETC coninc","",x);
1137 concb((char)escape); /* Put keyboard back in cbreak mode */
1142 if (cx == XXGETK) { /* GETKEYCODE */
1143 sprintf(tmp,"%d",x); /* SAFE */
1146 tmp[0] = (char) (x & 0xff);
1151 y = addmac(vnp,tmp); /* Add it to the macro table. */
1152 debug(F111,"getc/getk addmac",vnp,y);
1154 cmsetp(psave); /* Restore old prompt. */
1157 if (!quiet && !nomsg)
1158 printf("?Timed out");
1162 return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0)));
1163 } else { /* ASK or ASKQ */
1166 #endif /* CK_RECALL */
1167 y = cmdgquo(); /* Get current quoting */
1168 cmdsquo(0); /* Turn off quoting */
1169 while (x == -1) { /* Prompt till they answer */
1170 x = cmtxt("Please respond.",dfanswer,&s,NULL);
1171 debug(F111,"ASK cmtxt",s,x);
1174 cmdsquo(y); /* Restore previous quoting */
1175 if (cx == XXASKQ) /* ASKQ must echo CRLF here */
1177 if (x == -10 && dfanswer) { /* Don't fail on timeout if */
1178 s = dfanswer; /* a default was specified */
1179 asktimedout = 0; /* and don't fail */
1182 if (x < 0) { /* If cmtxt parse error, */
1183 cmsetp(psave); /* restore original prompt */
1185 if (cmdlvl > 0) /* In VMS and not at top level, */
1186 conres(); /* restore console again. */
1188 if (x == -10) { /* Timed out with no response */
1190 printf("?Timed out");
1193 if (dfanswer) /* Supply default answer if any */
1195 success = x = 0; /* (was "x = -9;") */
1198 return(x); /* and return cmtxt's error code. */
1200 if (!s || *s == NUL) { /* If user typed a bare CR, */
1201 cmsetp(psave); /* Restore old prompt, */
1202 delmac(vnp,0); /* delete variable if it exists, */
1204 if (cmdlvl > 0) /* In VMS and not at top level, */
1205 conres(); /* restore console again. */
1208 return(success = 1); /* and return. */
1210 y = addmac(vnp,s); /* Add it to the macro table. */
1211 debug(F111,"ask addmac",vnp,y);
1212 cmsetp(psave); /* Restore old prompt. */
1214 if (cmdlvl > 0) /* In VMS and not at top level, */
1215 conres(); /* restore console again. */
1218 return(success = (y < 0 ? 0 : 1) && (asktimedout == 0));
1225 doincr(cx) int cx; { /* INCREMENT, DECREMENT */
1226 char vnambuf[VNAML+1]; /* Buffer for variable names */
1228 eval = (cx == XX_DECR || cx == XX_INCR);
1230 if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
1232 printf("?Variable name required\n");
1236 ckstrncpy(vnambuf,s,VNAML);
1237 if ((y = cmnum("by amount","1",10,&x,xxstring)) < 0)
1239 if ((y = cmcfm()) < 0)
1242 z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */
1244 if (incvar(vnambuf,x,z) < 0) {
1245 printf("?Variable %s not defined or not numeric\n",vnambuf);
1246 return(success = 0);
1248 return(success = 1);
1251 /* Used by doundef() */
1253 xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
1256 if (*s == CMDQ && *(s+1) == '%') {
1257 char c = *(s+2), * p = NULL;
1258 if (c >= '0' && c <= '9') {
1262 p = m_arg[maclvl][c - '0'];
1264 if (isupper(c)) c += ('a'-'A');
1265 if (c >= 'a' && c <= 'z')
1273 printf("(SELECTED)\n");
1274 } else if ((x = delmac(s,1)) > -1) { /* Full name required */
1276 if (verbose) printf("(OK)\n");
1278 printf("(FAILED)\n");
1282 /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
1289 static struct keytab undefswi[] = {
1290 { "/list", UND_VRB, 0 },
1292 { "/except", UND_EXC, CM_ARG },
1293 #endif /* COMMENT */
1294 { "/matching", UND_MAT, 0 },
1295 { "/simulate", UND_SIM, 0 },
1296 { "/verbose", UND_VRB, CM_INV }
1298 static int nundefswi = sizeof(undefswi) / sizeof(struct keytab);
1301 static char ** undeflist = NULL;
1303 doundef(cx) int cx; { /* UNDEF, _UNDEF */
1304 int i, j, n, rc = 0, arraymsg = 0;
1305 int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0;
1306 char *vnp, vnbuf[4];
1308 char *except = NULL;
1309 #endif /* COMMENT */
1314 if (!undeflist) { /* Allocate list if necessary */
1315 undeflist = (char **)malloc(UNDEFMAX * sizeof(char *));
1317 printf("?Memory allocation failure\n");
1320 for (i = 0; i < UNDEFMAX; i++)
1321 undeflist[i] = NULL;
1323 cmfdbi(&sw, /* First FDB - command switches */
1325 "Variable name or switch",
1327 "", /* addtl string data */
1328 nundefswi, /* addtl numeric data 1: tbl size */
1329 4, /* addtl numeric data 2: 4 = cmswi */
1330 xxstring, /* Processing function */
1331 undefswi, /* Keyword table */
1332 &fl /* Pointer to next FDB */
1334 cmfdbi(&fl, /* Anything that doesn't match */
1338 "", /* addtl string data */
1339 0, /* addtl numeric data 1 */
1340 0, /* addtl numeric data 2 */
1341 (cx == XXUNDEF) ? NULL : xxstring,
1345 while (1) { /* Parse 0 or more switches */
1346 x = cmfdb(&sw); /* Parse something */
1349 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
1352 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1353 printf("?This switch does not take an argument\n");
1356 switch (cmresult.nresult) {
1357 case UND_MAT: domatch = 1; break;
1358 case UND_SIM: simulate = 1; /* fall thru on purpose */
1359 case UND_VRB: verbose = 1; break;
1364 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
1366 printf("?Pattern required\n");
1371 makestr(&except,cmresult.sresult);
1373 #endif /* COMMENT */
1380 makestr(&(undeflist[n++]),cmresult.sresult);
1381 for (i = 1; i < UNDEFMAX; i++) {
1382 x = cmfld("Macro or variable name","",&s,
1383 ((cx == XXUNDEF) ? NULL : xxstring)
1386 if ((y = cmcfm()) < 0)
1392 makestr(&(undeflist[n++]),s);
1394 /* Now we have a list of n variables or patterns to undefine */
1396 for (i = 0; i < n; i++) {
1398 if (!(vnp = undeflist[i]))
1400 if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) {
1404 if (!domatch) { /* Pattern match not requested */
1406 if ((y = parsevar(vnp,&x,&z)) < 0) {
1408 if (verbose) printf(" %s...error\n",vnp);
1413 x = xxundef(vnp,verbose,simulate);
1415 if (!x && !simulate) errors++;
1420 /* Pattern match requested */
1422 if (!flag) { /* It's a macro */
1423 for (j = 0; j < nmac; j++) {
1424 if (ckmatch(vnp,mactab[j].kwd,0,1)) {
1425 x = xxundef(mactab[j].kwd,verbose,simulate);
1431 j--; /* Because mactab shifted up */
1434 } else if (vnp[0] == '%') { /* It's a \%x variable */
1438 for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */
1440 if (ckmatch(vnp,&vnbuf[1],0,1)) {
1441 x = xxundef(vnbuf,verbose,simulate);
1447 if (j == '9') j = (int)'a' - 1; /* 9 -> a */
1449 } else if (vnp[0] == '&') {
1450 if (!arraymsg && !quiet) {
1451 printf("?UNDEFINE /MATCH can't be used with arrays.\n");
1452 printf("(Type HELP ARRAY to see other methods.)\n");
1459 printf("undefined: %d, errors: %d\n",rc,errors);
1461 for (i = 0; i < UNDEFMAX; i++) { /* Check them all */
1462 if (undeflist[i]) { /* in case we were interrupted */
1463 free(undeflist[i]); /* previously... */
1464 undeflist[i] = NULL;
1467 return(success = (errors == 0) ? 1 : 0);
1473 extern char ppvnambuf[];
1475 char vnambuf[VNAML+1]; /* Buffer for variable names */
1476 char *vnp; /* Pointer to same */
1478 mydot = xxdot; /* Copy */
1479 xxdot = 0; /* and reset */
1481 In case we got here from a command that begins like ".\%a", cmkey() has
1482 already evaluated \%a, but we don't want that, so we retrieve the variable
1483 name from a special pre-evaluation buffer in the command module, and we
1484 undo the "unget word" that would be done because of the token, because if
1485 the variable was defined, it will unget its value rather than its name.
1489 if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
1494 if (cx == XXDFX || cx == XXASX)
1495 /* Evaluate variable name */
1496 y = cmfld("Macro or variable name","",&s,xxstring);
1498 /* Don't evaluate the variable name */
1499 y = cmfld("Macro or variable name","",&s,NULL);
1502 printf("?Variable name required\n");
1509 printf("?Name too long: \"%s\"\n",s);
1512 ckstrncpy(vnambuf,s,VNAML);
1513 vnambuf[VNAML] = NUL;
1515 if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
1516 if (*vnp == '%' || *vnp == '&') {
1517 if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
1519 if (cx == XXUNDEF) { /* Undefine */
1520 if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1522 return(success = 1);
1524 #endif /* COMMENT */
1525 debug(F101,"dodef parsevar x","",x);
1527 if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1529 if (doeval > 0) /* Type of assignment */
1532 if (y == 1) { /* Simple variable */
1533 if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
1536 debug(F110,"xxdef var name",vnp,0);
1537 debug(F110,"xxdef var def",s,0);
1538 } else if (y == 2) { /* Array element */
1539 if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
1541 printf("?Argument vector array is read-only\n");
1544 if (chkarray(x,z) < 0) return(-2);
1545 if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
1547 debug(F110,"xxdef array ref",vnp,0);
1548 debug(F110,"xxdef array def",s,0);
1550 } else { /* Macro */
1552 if (cx == XXUNDEF) { /* Undefine */
1553 if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1555 return(success = 1);
1557 #endif /* COMMENT */
1559 if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1564 if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
1567 debug(F110,"xxdef macro name",vnp,0);
1568 debug(F010,"xxdef macro def",s,0);
1573 if (*s == NUL) { /* No arg given, undefine */
1574 delmac(vnp,1); /* silently... */
1575 return(success = 1); /* even if it doesn't exist... */
1577 /* Defining a new macro or variable */
1579 if (cx == XXASS || cx == XXASX) { /* ASSIGN rather than DEFINE? */
1582 lp = line; /* If so, expand its value now */
1586 if (doeval == 2) { /* Arithmetic evaluation wanted too? */
1587 ckstrncpy(line,evala(s),LINBUFSIZ);
1588 line[LINBUFSIZ] = NUL;
1590 /* debug(F111,"calling addmac",s,(int)strlen(s)); */
1592 y = addmac(vnp,s); /* Add it to the appropriate table. */
1594 printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
1595 "ASSIGN" : "DEFINE");
1596 return(success = 0);
1597 } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
1598 return(1); /* don't change success variable */
1600 return(success = 1);
1607 L U D I A L -- Lookup up dialing directory entry.
1609 Call with string to look up and file descriptor of open dialing directory
1610 file. On success, returns number of matches found, with numbers stored
1611 in an array accessible via getdnum().
1613 static char *dn_p[MAXDNUMS + 1]; /* Dial Number pointers */
1614 static char *dn_p2[MAXDNUMS + 1]; /* Converted dial number pointers */
1615 static int dn_x[MAXDNUMS + 1]; /* Type of call */
1616 static int dncount = 0;
1617 char * d_name = NULL; /* Dial name pointer */
1619 char * /* Get dial directory entry name */
1621 return(d_name ? d_name : "");
1625 getdnum(n) int n; { /* Get dial number n from directory */
1626 if (n < 0 || n > dncount || n > MAXDNUMS)
1632 char * /* Check area code for spurious leading digit */
1633 chk_ac(i,buf) int i; char buf[]; {
1637 p = (char *) buf; /* Country we are calling: */
1638 if (i == 44 || /* UK */
1639 i == 49 || /* Germany */
1640 i == 39 || /* Italy */
1641 i == 31 || /* Netherlands */
1642 i == 351 || /* Portugal */
1643 i == 55 || /* Brazil */
1644 i == 972 || /* Israel */
1645 i == 41 || /* Switzerland */
1646 i == 43 || /* Austria */
1647 i == 42 || /* Czech Republic */
1648 i == 36 || /* Hungary */
1649 i == 30 || /* Greece */
1650 i == 352 || /* Luxembourg */
1651 i == 48 || /* Poland */
1652 i == 27 || /* South Africa */
1653 i == 33 || /* France (as of 1997) */
1654 i == 358 /* Finland (ditto) */
1662 /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
1664 src = area code of caller
1665 dest = area code of callee
1668 1 if call is long distance
1669 2 if call is local but area code must be dialed anyway
1672 callisld(src, dest) char * src, * dest; {
1674 if (dialfld) /* Force long distance? */
1676 if (!strcmp(src,dest)) { /* Area codes are the same */
1677 for (i = 0; i < nlocalac; i++) /* Is AC in the lc-area-codes list? */
1678 if (!strcmp(src,diallcac[i]))
1679 return(2); /* Yes so must be dialed */
1680 return(0); /* No so don't dial it. */
1682 for (i = 0; i < nlocalac; i++) /* ACs not the same so look in list */
1683 if (!strcmp(dest,diallcac[i])) /* Match */
1684 return(2); /* So local call with area code */
1685 return(1); /* Not local so long-distance */
1688 char pdsfx[64] = { NUL, NUL };
1692 xdial(s) char *s; { /* Run dial string thru macro */
1694 if (!dialmac) /* Dial macro name given? */
1696 if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
1699 x = dodo(x,s,0); /* Set up the macro */
1701 while (maclvl > m) /* Execute the parser */
1703 return(mrval[maclvl+1]); /* Return the result */
1710 dncvt(k,cx, prefix, suffix)
1711 int k, cx, prefix, suffix; { /* Dial Number Convert */
1712 int i, j, n, what; /* cx is top-level command index */
1713 char *ss; /* prefix - add prefixes? */
1714 char *p, *p2, *pxo; /* suffix - add suffixes? */
1725 First pass for strict (punctuation-based) interpretation.
1726 If it fails, we try the looser (length-based) one.
1729 what = 0; /* Type of call */
1730 s = dn_p[k]; /* Number to be converted. */
1731 debug(F111,"dncvt",s,k);
1737 printf("Error - No phone number to convert\n");
1740 if ((int)strlen(s) > 200) {
1741 ckstrncpy(outbuf,s,40);
1742 printf("?Too long: \"%s...\"\n",outbuf);
1745 npr = (prefix && dialnpr) ? dialnpr : "";
1746 sfx = (suffix && dialsfx) ? dialsfx : "";
1747 /* if (partial) psfx = dialsfx ? dialsfx : ""; */
1748 pxo = (prefix && dialpxo) ? dialpxo : "";
1749 lac = diallac ? diallac : ""; /* Local area code */
1751 outbuf[0] = NUL; /* Initialize conversion buffer */
1752 ss = s; /* Remember original string */
1754 if (*s != '+') { /* Literal number */
1755 dn_x[k] = DN_UNK; /* Sort key is "unknown". */
1756 ckmakmsg(outbuf,256, /* Sandwich it between */
1757 pxo,npr,s,sfx /* DIAL PREFIX and SUFFIX */
1760 if (tttapi && /* TAPI does its own conversions */
1761 !tapipass && /* if not in passthru mode */
1762 tapiconv == CK_AUTO || /* and TAPI conversions are AUTO */
1763 tapiconv == CK_ON /* OR if TAPI conversions are ON */
1767 if (!cktapiConvertPhoneNumber(dn_p[k], &p))
1769 makestr(&dn_p2[k], p);
1773 #endif /* CK_TAPI */
1774 makestr(&dn_p2[k], outbuf); /* Not TAPI */
1776 return(0); /* Done. */
1778 i = 0; /* Portable number */
1779 s++; /* Tiptoe past the plus sign */
1780 ccbuf[0] = NUL; /* Do country code first */
1782 if (!diallcc) { /* Do we know our own? */
1784 printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
1788 /* Parse the number */
1790 while (1) { /* Get the country code */
1791 while (*s == HT || *s == SP)
1793 if (!s) /* Not in standard format */
1795 if (*s == '(') { /* Beginning of area code */
1796 s++; /* Skip past parenthesis */
1797 ccbuf[i] = NUL; /* End of country code */
1798 if (!s) { /* Check for end of string */
1799 printf("Error - phone number ends prematurely: \"%s\"\n",ss);
1803 } else { /* Collect country code */
1805 ccbuf[i++] = *s; /* copy this character */
1807 if (!*s || i > 127) /* watch out for memory leak */
1811 cc = atoi(ccbuf); /* Numeric version of country code */
1813 i = 0; /* Now get area code */
1814 acbuf[0] = NUL; /* Initialize area-code buffer */
1815 acptr = acbuf; /* and pointer. */
1817 while (*s == HT || *s == SP) /* Ignore whitespace */
1819 if (!s) /* String finished */
1821 if (*s == ')') { /* End of area code */
1822 s++; /* Skip past parenthesis */
1823 acbuf[i] = NUL; /* Terminate area-code buffer */
1825 } else { /* Part of area code */
1826 if (isdigit(*s)) /* If it's a digit, */
1827 acbuf[i++] = *s; /* copy this character */
1828 s++; /* Point to next */
1829 if (!*s || i > 23) /* Watch out for overflow */
1835 Here we strip any leading 0 for countries that we know have
1836 0 as a long-distance prefix and do not have any area codes that
1837 start with 0 (formerly also ditto for "9" in Finland...)
1840 acptr = chk_ac(i,acbuf);
1842 while (*s == HT || *s == SP) /* Skip whitespace */
1845 /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
1847 if (*s && *acptr) { /* Area code was delimited */
1849 while (*s == '-' || *s == '.') /* Skip past gratuitious punctuation */
1851 if (!*s) s--; /* But not to end of string */
1853 if (strcmp(diallcc,ccbuf)) { /* Out of country? */
1854 if (!dialixp) { /* Need intl-prefix */
1856 printf("Error - No international dialing prefix defined\n");
1859 what = dn_x[k] = DN_INTL;
1860 p = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
1861 p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
1863 /* Form the final phone number */
1865 sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */
1868 pxo,npr,p,ccbuf,acptr,s,p2,sfx
1871 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
1872 ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx,
1873 NULL,NULL,NULL,NULL);
1874 #endif /* COMMENT */
1876 } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
1877 if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
1879 printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
1881 if (x == 2) { /* Local call with area code */
1882 what = dn_x[k] = DN_LOCAL; /* Local-call */
1883 p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
1884 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
1886 what = dn_x[k] = DN_LONG; /* Long-distance */
1887 for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
1888 if (!strcmp(acptr,dialtfc[i])) {
1889 what = dn_x[k] = DN_FREE;
1893 if (what == DN_FREE) { /* Toll-free call */
1894 p = (prefix && dialtfp) ? dialtfp :
1895 ((prefix && dialldp) ? dialldp : "");
1896 p2 = ""; /* no suffix */
1897 } else { /* normal long distance */
1898 p = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
1899 p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
1902 /* Form the number to be dialed */
1904 sprintf(outbuf,"%s%s%s%s%s%s%s",
1905 pxo,npr,p,acptr,s,p2,sfx
1907 sprintf(pdsfx,"%s%s",p2,sfx);
1909 ckmakxmsg(outbuf,256,
1910 pxo,npr,p,acptr,s,p2,sfx,
1911 NULL,NULL,NULL,NULL,NULL);
1912 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
1913 #endif /* COMMENT */
1914 } else { /* Same country, same area code */
1915 what = dn_x[k] = DN_LOCAL; /* So it's a local call. */
1916 if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
1917 p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
1918 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
1921 sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
1923 sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
1924 sprintf(pdsfx,"%s%s",p2,sfx);
1927 ckmakxmsg(outbuf,256,
1928 npr,p,acptr,s,p2,sfx,
1929 NULL,NULL,NULL,NULL,NULL,NULL);
1931 ckmakxmsg(outbuf,256,
1933 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
1934 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
1935 #endif /* COMMENT */
1937 } else { /* Dialing from a PBX and not TAPI */
1938 if (ndialpxx) { /* Is it internal? */
1940 i = (int) strlen(dialpxx);
1941 j = (int) strlen(s);
1944 x = ckstrcmp(dialpxx,s,i,0);
1948 j = (int) strlen(s);
1949 for (kx = 0; kx < ndialpxx; kx++) {
1950 i = (int) strlen(dialpxx[kx]);
1952 if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
1955 #endif /* COMMENT */
1957 char * icp, buf[32];
1958 makestr(&matchpxx,dialpxx[kx]);
1959 debug(F111,"dncvt matchpxx",matchpxx,kx);
1960 what = dn_x[kx] = DN_INTERN; /* Internal call. */
1962 /* Internal-call prefix */
1970 if (isupper(c)) c = tolower(c);
1971 if (c == 'v' || c == 'f') {
1974 zzstring(icp,&bp,&n);
1980 p = (prefix && icp) ? icp : "";
1982 sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx);
1984 ckmakmsg(outbuf,256,npr,p,s,sfx);
1985 #endif /* COMMENT */
1986 } else { /* External local call */
1988 p = (prefix && diallcp) ? diallcp : "";
1990 p2 = (prefix && diallcs) ? diallcs : "";
1993 sprintf(outbuf,"%s%s%s%s%s%s%s",
1994 dialpxo ? dialpxo : "",
1995 npr,p,acptr,s,p2,sfx);
1999 dialpxo ? dialpxo : "",
2004 ckmakxmsg(outbuf, 256,
2005 dialpxo ? dialpxo : "",
2006 npr,p,acptr,s,p2,sfx,
2007 NULL,NULL,NULL,NULL,NULL);
2009 ckmakxmsg(outbuf, 256,
2010 dialpxo ? dialpxo : "",
2012 NULL,NULL,NULL,NULL,NULL,NULL);
2013 #endif /* COMMENT */
2019 } else { /* Area code was not delimited */
2021 char xbuf[256]; /* Comparison based only on length */
2027 for (i = 0; i < 255; i++) {
2029 while (!isdigit(*s)) { /* Pay attention only to digits */
2037 x = 1; /* Assume LD */
2039 if (!dialfld) { /* If LD not forced */
2040 for (j = 0; j < nlocalac; j++) { /* check local AC list? */
2041 ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL);
2042 n = (int) strlen(ybuf);
2043 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
2048 if (x == 1) { /* Or exact match with local CC+AC? */
2049 ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL);
2050 n = (int) strlen(ybuf);
2051 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
2055 if (x == 0 || x == 2) { /* Local call */
2056 int xx,kx; /* Begin 1 Dec 2001... */
2057 /* Account for PBX internal calls */
2060 j = (int) strlen(ybuf);
2061 for (kx = 0; kx < ndialpxx; kx++) {
2062 i = (int) strlen(dialpxx[kx]);
2064 if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0)))
2069 char * icp, buf[32];
2070 makestr(&matchpxx,dialpxx[kx]);
2071 debug(F111,"dncvt matchpxx",matchpxx,kx);
2072 what = dn_x[kx] = DN_INTERN; /* Internal call. */
2074 icp = dialpxi; /* Internal-call prefix */
2081 if (isupper(c)) c = tolower(c);
2082 if (c == 'v' || c == 'f') {
2085 zzstring(icp,&bp,&n);
2091 p = (prefix && icp) ? icp : "";
2092 ckmakmsg(outbuf,256,npr,p,s,sfx);
2093 /* End 1 Dec 2001... */
2095 } else { /* Not PBX internal */
2098 p = (prefix && diallcp) ? diallcp : "";
2099 p2 = (suffix && diallcs) ? diallcs : "";
2100 s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
2101 ckmakxmsg(outbuf,256,
2103 NULL,NULL,NULL,NULL,NULL,NULL);
2104 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2106 } else { /* Not local */
2107 n = ckstrncpy(ybuf,diallcc,256);
2108 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
2110 p = (prefix && dialldp) ? dialldp : "";
2111 p2 = (suffix && diallds) ? diallds : "";
2113 while (*s == '-' || *s == '.')
2116 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
2117 sprintf(pdsfx,"%s%s",p2,sfx);
2119 ckmakxmsg(outbuf,256,
2121 NULL,NULL,NULL,NULL,NULL,NULL);
2122 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2123 #endif /* COMMENT */
2125 dn_x[k] = DN_INTL; /* International */
2129 "Error - No international dialing prefix defined\n"
2134 p = (prefix && dialixp) ? dialixp : "";
2135 p2 = (suffix && dialixs) ? dialixs : "";
2137 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
2138 sprintf(pdsfx,"%s%s",p2,sfx);
2140 ckmakxmsg(outbuf,256,
2141 pxo,npr,p,xbuf,p2,sfx,
2142 NULL,NULL,NULL,NULL,NULL,NULL);
2143 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2144 #endif /* COMMENT */
2149 if (tttapi && /* TAPI performs the conversions */
2151 tapiconv == CK_AUTO ||
2156 if (!cktapiConvertPhoneNumber(dn_p[k],&p))
2158 makestr(&dn_p2[k], p);
2162 #endif /* CK_TAPI */
2163 makestr(&dn_p2[k], outbuf);
2166 #endif /* CK_TAPI */
2172 ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
2173 char linebuf[1024], *s2; /* Buffers and pointers */
2177 char *info[8]; /* Pointers to words from entry */
2182 debug(F110,"ddcvt file",s,0);
2184 if (!s || !f) /* No filename or file */
2189 znewn(s,&s2); /* s2 = address of static buffer */
2190 debug(F110,"ddcvt newname",s2,0);
2193 /* In VMS, znewn() returns the same file name with a new version number */
2194 makestr(&temp,s); /* Swap - otherwise the new */
2195 s = s2; /* version has the older version */
2196 s2 = temp; /* number... */
2197 debug(F110,"ddcvt after swap s",s,0);
2198 debug(F110,"ddcvt after swap s2",s2,0);
2199 makestr(&(dialdir[n]),s); /* New file gets new version number */
2200 debug(F110,"ddcvt after makestr s2",s2,0);
2201 debug(F111,"ddcvt dialdir[n]",dialdir[n],n);
2203 if (zrename(s,s2) < 0) { /* Not VMS - rename old file */
2204 perror(s2); /* to new (wierd) name. */
2208 debug(F110,"ddcvt s2 (old)",s2,0);
2209 if ((f = fopen(s2,"r")) == NULL) { /* Reopen old file with wierd name */
2210 debug(F110,"ddcvt s2 open error",ck_errstr(),0);
2211 dirline = 0; /* (or in VMS, old version) */
2215 debug(F110,"ddcvt fopen(s2) OK",s2,0);
2217 debug(F110,"ddcvt s (new)",s,0);
2218 if ((f2 = fopen(s,"w")) == NULL) { /* Create new file with old name */
2219 debug(F110,"ddcvt s open error",ck_errstr(),0);
2220 perror(s); /* (or in VMS, new version) */
2223 debug(F110,"ddcvt fopen(s) OK",s,0);
2225 printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
2226 fprintf(f2,"; %s - Kermit dialing directory\n", s);
2227 fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
2228 "; Name","Number","Speed","Parity","Comment"
2232 linebuf[0] = NUL; /* Read a line */
2233 if (fgets(linebuf,1023,f) == NULL)
2235 debug(F110,"ddcvt linebuf",linebuf,0);
2236 if (!linebuf[0]) { /* Empty line */
2240 x = (int) strlen(linebuf); /* Strip line terminator, */
2241 while (x-- > 0) { /* if any. */
2242 if (linebuf[x] <= SP)
2247 xwords(linebuf,5,info,1); /* Parse it the old way */
2248 for (x = 1; x < 6; x++)
2249 if (!info[x]) info[x] = "";
2250 fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
2251 info[1],info[2],info[3],info[4],info[5]
2255 rc = 0; /* Success */
2260 if (temp) free(temp);
2265 int /* s = name to look up */
2266 #ifdef CK_ANSIC /* cx = index of command */
2267 ludial(char *s, int cx) /* (DIAL, LOOKUP, etc) */
2269 ludial(s, cx) char *s; int cx;
2270 #endif /* CK_ANSIC */
2273 int dd, n1, n2, n3, i, j, t; /* Workers */
2274 int olddir, newdir, oldentry, newentry;
2277 int ambiguous = 0; /* Flag for lookup was ambiguous */
2278 char *info[7]; /* Pointers to words from entry */
2279 char *pp; /* Pointer to element of array */
2281 char *line; /* File input buffer */
2283 /* #define LUDEBUG */
2287 #endif /* LUDEBUG */
2289 if (!s || ndialdir < 1) /* Validate arguments */
2292 if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */
2295 if (!(line = malloc(1024))) /* Allocate input buffer */
2299 if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
2300 #endif /* LUDEBUG */
2304 f = NULL; /* Dial directory file descriptor */
2305 t = dncount = 0; /* Dial-number match count */
2306 dd = 0; /* Directory counter */
2310 We need to recognize both old- and new-style directories.
2311 But we can't allow old-style and new-style entries in the same
2312 directory because there is no way to tell for sure the difference between
2313 an old-style entry like this:
2317 and a new-style literal entry like this:
2321 I.e. is the "9600" a speed, or part of the phone number?
2323 while (1) { /* We make one pass */
2324 if (!f) { /* Directory not open */
2325 if (dd >= ndialdir) /* No directories left? */
2327 debug(F111,"ludial dialdir[dd]",dialdir[dd],dd);
2328 if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
2329 perror(dialdir[dd]); /* Can't, print message saying why */
2334 dd++; /* Go on to next one, if any... */
2337 dirline = 0; /* Directory file line number */
2338 if (dialdpy && !pass)
2339 printf("Opening: %s...\n",dialdir[dd]);
2341 if (!oldflg) olddir = 0;
2347 if (getnct(line,1023,f,1) < 0) { /* Read a line */
2348 if (f) { /* f can be clobbered! */
2349 fclose(f); /* Close the file */
2350 f = NULL; /* Indicate next one needs opening */
2355 if (!line[0]) /* Empty line */
2358 if (zz) printf("LUDIAL 2 s[%s]\n",s);
2359 #endif /* LUDEBUG */
2361 /* Make a copy and parse it the old way */
2362 /* A copy is needed because xwords() pokes NULs into the string */
2364 if ((pp = malloc((int)strlen(line) + 1))) {
2365 strcpy(pp,line); /* safe */
2366 xwords(pp,5,info,0); /* Parse it the old way */
2369 if (zz) printf("LUDIAL 3 s[%s]\n",s);
2370 #endif /* LUDEBUG */
2374 if (*info[1] == ';') { /* If full-line comment, */
2375 newdir = 1; /* (only new directories have them) */
2376 continue; /* keep reading. */
2380 if (*info[2] == '+')
2383 if ((*info[4] == '=') ||
2384 !ckstrcmp(info[4],"none", 4,0) ||
2385 !ckstrcmp(info[4],"even", 4,0) ||
2386 !ckstrcmp(info[4],"space",5,0) ||
2387 !ckstrcmp(info[4],"mark", 4,0) ||
2388 !ckstrcmp(info[4],"odd", 3,0)
2398 /* Check consistency */
2400 if ((oldentry || olddir) && (newentry || newdir)) {
2402 "\nERROR: You seem to have old- and new-format entries mixed in your\n");
2404 "dialing directory. You'll have to edit it by hand to convert it to the\n");
2406 printf("new format. Type HELP DIAL for further information.\n\n");
2408 printf("new format.\n\n");
2416 if (!olddir && oldentry) {
2419 if (dialcvt == 2) { /* 2 == ASK */
2421 "WARNING: Old-style dialing directory detected:\n%s", line);
2422 convert = uq_ok(tmpbuf,
2423 "Shall I convert it for you? ",3,NULL,0);
2427 debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd);
2428 if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
2429 debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd);
2432 " Sorry, can't convert.");
2434 " Will ignore speed and parity fields, continuing...\n\n");
2436 olddir = newdir = 0;
2437 debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd);
2445 " OK, will ignore speed and parity fields, continuing...\n\n");
2451 if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
2452 #endif /* LUDEBUG */
2454 /* Now parse again for real */
2456 if (oldentry) /* Parse it the old way */
2457 xwords(line,5,info,0);
2458 else /* Parse it the new way */
2459 xwords(line,2,info,1);
2462 if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
2463 if (zz) printf("%s [%s]\n",info[1],info[2]);
2464 #endif /* LUDEBUG */
2466 if (info[1]) { /* First word is entry name */
2467 if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
2468 continue; /* If no first word, keep reading. */
2469 if (n3 < n1) /* Search name is longer */
2470 continue; /* Can't possibly match */
2471 if (ambiguous && n3 != n1)
2475 if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
2476 #endif /* LUDEBUG */
2478 if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
2482 if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
2483 #endif /* LUDEBUG */
2485 if (!info[2]) /* No phone number given */
2487 if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
2488 continue; /* Ignore empty phone numbers */
2492 if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
2493 printf("?internal error - ludial malloc 1\n");
2501 strcpy(pp,info[2]); /* safe */
2503 if (dncount > MAXDNUMS) {
2504 printf("Warning: %d matches found, %d max\n",
2511 dn_p[dncount++] = pp; /* Add pointer to array. */
2512 if (dncount == 1) { /* First one... */
2513 if (d_name) free(d_name);
2514 if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
2515 printf("?internal error - ludial malloc 2\n");
2523 t = n3; /* And its length */
2524 strcpy(d_name,info[1]); /* safe */
2525 } else { /* Second or subsequent one */
2529 printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
2530 #endif /* LUDEBUG */
2532 if ((int) strlen(info[1]) == t) /* Lengths compare */
2533 if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
2536 /* Name given by user matches entries with different names */
2538 if (ambiguous) /* Been here before */
2541 ambiguous = 1; /* Now an exact match is required */
2542 for (j = 0; j < dncount; j++) { /* Clean out previous list */
2548 pass++; /* Second pass... */
2549 goto lu_again; /* Do it all over again. */
2553 if (line) free(line);
2554 if (dncount == 0 && ambiguous) {
2555 printf(" Lookup: \"%s\" - ambiguous%s\n",
2557 cx == XXLOOK ? "" : " - dialing skipped"
2565 pncvt(s) char *s; { /* Phone number conversion */
2566 char *p = NULL; /* (just a wrapper for dncvt() */
2568 static char pnbuf[128];
2569 makestr(&p,dn_p[0]); /* Save these in case they are */
2570 makestr(&q,dn_p2[0]); /* being used */
2571 makestr(&dn_p[0],s); /* Copy the argument string to here */
2572 dncvt(0,XXLOOK,1,1); /* Convert it */
2573 if (!dn_p2[0]) /* Put result where can return it */
2576 ckstrncpy(pnbuf,dn_p2[0],127);
2577 makestr(&dn_p[0],p); /* Restore these */
2578 makestr(&dn_p2[0],q);
2579 makestr(&p,NULL); /* Free these */
2581 return((char *)pnbuf);
2585 dodial(cx) int cx; { /* DIAL or REDIAL */
2586 int i = 0, x = 0; /* Workers */
2587 int sparity = -1; /* For saving global parity value */
2592 int lufound = 0; /* Did any lookup succeed? */
2599 char *p = NULL, *s3 = NULL, * sav = NULL;
2600 int j = 0, t = 0, n = 0;
2603 debug(F101,"dodial cx","",cx);
2604 debug(F111,"dodial diallcc",diallcc,diallcc);
2606 xretries = dialrtr; /* If retries not set, */
2607 if (diallcc) { /* choose default based on */
2608 xlcc = atoi(diallcc); /* local country code. */
2611 case 1: xretries = 10; break; /* No restrictions in NANP */
2612 /* Add other country codes here */
2613 /* that are known to have no restrictions on redialing. */
2614 default: xretries = 1;
2618 if (cx == XXPDIA) { /* Shortcut... */
2621 debug(F100,"PDIAL sets partial=1","",0);
2622 postfix = 0; /* Do not add postfix */
2625 debug(F100,"DIAL sets partial=0","",0);
2627 previous = dialsta; /* Status of previous call, if any */
2628 if (previous == DIA_PART) {
2629 prefix = 0; /* do not add prefix */
2631 s = NULL; /* Initialize user's dial string */
2632 if (cx == XXRED) { /* REDIAL or... */
2633 if ((y = cmcfm()) < 0)
2635 } else if (cx == XXANSW) { /* ANSWER or ... */
2636 if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
2639 if ((y = cmcfm()) < 0)
2641 } else { /* DIAL or LOOKUP */
2643 s3 = "Number to dial or entry from dial directory";
2645 s3 = "Number to dial";
2646 if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
2649 len = (int) strlen(s);
2650 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
2652 if (len > 1) { /* Strip outer braces if given */
2654 if (s[len-1] == '}') {
2662 s = brstrip(s); /* Strip outer braces or quotes */
2663 #endif /* COMMENT */
2667 if (cx != XXLOOK) { /* Not LOOKUP */
2670 printf("Sorry, dialing is disabled.\r\n");
2671 return(success = 0);
2675 if (tttapi && !tapipass) {
2676 ; /* Skip the modem test if TAPI */
2678 #endif /* CK_TAPI */
2679 if (mdmtyp < 1 && !dialtest) {
2683 #endif /* TN_COMPORT */
2685 printf("Please SET HOST first, and then SET MODEM TYPE\n");
2687 printf("Sorry, you must SET MODEM TYPE first\n");
2689 return(success = 0);
2691 if (!local && !dialtest) {
2692 printf("Sorry, you must SET %s or SET HOST first\n",
2700 return(success = 0);
2705 #endif /* TN_COMPORT */
2709 #endif /* CK_TAPI */
2712 && (strcmp(ttname,"/dev/null"))
2715 && (strcmp(ttname,"/nil"))
2719 printf("\nSorry, you must SET SPEED first\n");
2721 return(success = 0);
2725 for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
2726 if (!dialnum) { /* First time dialing */
2727 dn_p[j] = NULL; /* initialize all pointers. */
2729 } else if (dn_p[j]) { /* Not the first time, */
2730 free(dn_p[j]); /* free previous, if any, */
2731 dn_p[j] = NULL; /* then set to NULL. */
2735 } else break; /* Already NULL */
2743 printf("?Lookup what?\n");
2745 printf("%s\n", (cx == XXRED) ?
2746 "?No DIAL command given yet" :
2747 "?You must specify a number to dial"
2752 /* Now we have the "raw" dial or lookup string and s is not NULL */
2754 makestr(&dscopy,s); /* Put it in a safe place */
2758 debug(F111,"dodial",s,ndialdir);
2763 if (ndialdir > 0) { /* Do we have a dialing directory? */
2764 n = ludial(s,cx); /* Look up what the user typed */
2766 printf(" Lookup: \"%s\" - not found%s\n",
2768 cx == XXLOOK ? "" : " - dialing as given\n"
2771 debug(F101,"dodial",s,n);
2772 if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
2773 if (n == -1) /* -2 means ludial already gave msg */
2774 printf(" Lookup: fatal error - dialing skipped\n");
2778 if (n > 0) /* A successful lookup */
2780 } else if (*s == '=') { /* If number starts with = sign */
2782 literal = 1; /* remember this */
2783 while (*s == SP) s++; /* and then also any leading spaces */
2784 } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
2785 makelist(tmpbuf,dn_p,MAXDNUMS);
2786 makestr(&dscopy,tmpbuf);
2788 for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
2789 if (!dn_p[n]) break;
2792 if (cx == XXLOOK && !wasalpha && !braces) {
2793 /* We've been told to lookup a number or a quoted name */
2796 p = literal ? s : pncvt(dscopy);
2799 printf("%s => %s\n", dscopy, p);
2800 return(success = 1);
2802 printf("?Bad phone number\n");
2803 return(success = 0);
2806 /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
2807 /* But don't save pieces of partial dial ... */
2809 debug(F101,"DIAL save dialnum partial","",partial);
2810 debug(F101,"DIAL save dialnum previous","",previous);
2811 if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
2812 (cx == XXLOOK && n > 0)) {
2813 makestr(&dialnum,dscopy);
2814 if (!quiet && dscopy && !dialnum)
2815 printf("WARNING - memory allocation failure: redial number\n");
2818 if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
2819 if (!strcmp(d_name,s))
2820 printf(" Lookup: \"%s\" - exact match\n",s);
2822 printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
2827 if ((cx == XXLOOK) ||
2828 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
2829 printf(" %d telephone number%sfound for \"%s\"%s\n",
2831 (n == 1) ? " " : "s ",
2837 for (i = 0; i < n; i++) { /* Convert */
2839 if (dncvt(i,cx,prefix,postfix) < 0) {
2846 if (dialsrt && n > 1) { /* Sort into optimal order */
2847 for (i = 0; i < n-1; i++) {
2848 for (j = i+1; j < n; j++) {
2849 if (dn_x[j] < dn_x[i]) {
2857 dn_p2[j] = dn_p2[i];
2863 if ((cx == XXLOOK) ||
2864 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
2870 if (n > 12) nn = 12;
2871 for (i = 0; i < nn; i++) {
2872 printf("%3d. %-12s %-20s => %-20s (%d)\n",i+1,
2874 dn_p2[i] ? dn_p2[i] : "(processing failed)",
2878 if (cx != XXLOOK && n != nn)
2879 printf("And %d more...\n", n - nn);
2881 } else if (n == 0) { /* Not found in directory */
2882 makestr(&(dn_p[0]),literal ? s : dscopy);
2883 makestr(&d_name,literal ? s : dscopy);
2886 if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
2887 dialsta = DIA_DIR; /* portable-format number ... */
2894 /* It's not good that the networks directory depends on NOT-NODIAL.. */
2895 if (cx == XXLOOK && dscopy) { /* Networks here too... */
2896 extern char *nh_p[], *nh_p2[], *n_name;
2897 extern char *nh_px[4][MAXDNUMS+1];
2899 if (nnetdir > 0) { /* Do we have a network directory? */
2901 n = lunet(dscopy); /* Look up what the user typed */
2905 if (n > 0) /* A successful lookup */
2907 if (cx == XXLOOK && n == 0)
2908 printf(" Lookup: \"%s\" - not found\n",dscopy);
2910 printf("%s %d network entr%s found for \"%s\"%s\n",
2911 cx == XXLOOK ? " Lookup:" : "",
2913 (n == 1) ? "y" : "ies",
2918 for (i = 0; i < n; i++) {
2920 printf("%3d. %-12s => %-9s %s",
2921 i+1,n_name,nh_p2[i],nh_p[i]);
2922 for (k = 0; k < 4; k++) {
2924 printf(" %s",nh_px[k][i]);
2932 #endif /* NETCONN */
2935 return(success = lufound);
2936 } /* cx != XXANSW */
2939 conres(); /* So Ctrl-C/Y will work */
2942 Some modems do not react well to parity. Also, if we are dialing through a
2943 TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
2946 This should work even if the user interrupts the DIAL command, because the
2947 DIAL module has its own interrupt handler. BUT... if, for some reason, a
2948 dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
2949 parity should be used), this might prevent successful dialing. For that
2950 reason, we don't do this for V.25bis modems.
2952 sparity = parity; /* Save current parity */
2953 if ((dialcapas & CKD_V25) == 0) /* If not V.25bis... */
2954 parity = 0; /* Set parity to NONE */
2958 These modems use some kind of screwy flow control while in command mode,
2959 and do not present CTS as they should. So if RTS/CTS is set (or even if
2960 it isn't) disable flow control during dialing.
2963 if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
2964 flow = FLO_NONE; /* This is not enough */
2966 ttsetflow(FLO_NONE); /* Really turn it off */
2967 #endif /* CK_TTSETFLOW */
2969 #endif /* MINIDIAL */
2973 #endif /* TN_COMPORT */
2976 if ((x = ttgmdm()) > -1) {
2979 "WARNING - No modem signals detected. Is your modem turned on? If not,\n\
2980 use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n",
2986 if (flow == FLO_RTSC) {
2987 if (!(x & BM_CTS)) {
2990 "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
2991 Disabling flow control temporarily %s...\n",
2993 "while waiting for call" :
3001 if (cx == XXANSW) { /* ANSWER */
3002 success = ckdial("",0,0,1,0);
3006 /* Edit 192 adds the ability to dial repeatedly. */
3011 if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
3014 /* And the ability to dial alternate numbers. */
3015 /* Loop to dial each in a list of numbers for the same name... */
3016 for (j = 0; j < n && !success; j++) { /* until one answers. */
3017 s = dn_p2[j]; /* Next number in list */
3018 if (dn_x[j] >= dialrstr) { /* Dial restriction */
3019 printf("Restricted: %s, skipping...\n",dn_p[j]);
3022 xredial = (i == 0 && j == 0) ? 0 : 1;
3023 if (!s) s = dn_p[j];
3027 p = xdial(s); /* Apply DIAL macro now */
3031 /* Dial confirmation */
3032 /* NOTE: the uq_xxx() calls allow for a GUI dialog */
3034 if (i == 0 && dialcnf) {
3036 ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL);
3037 x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0);
3041 x = uq_txt( /* Allow GUI dialog */
3043 " Please enter the correct number,\r\n or press Enter to skip.",
3045 " Please enter the correct number,\r\n or press Return to skip.",
3047 "Corrected phone number: ",
3055 if (x && atmbuf[0]) { /* They gave a new one */
3057 makestr(&(dn_p2[j]), s);
3063 extern int on_recall;
3064 #endif /* CK_RECALL */
3065 cmsavp(psave,PROMPTL);
3068 " Please enter the correct number,\r\n or press Enter to skip: "
3070 " Please enter the correct number,\r\n or press Return to skip: "
3075 if (pflag) prompt(NULL);
3078 #endif /* CK_RECALL */
3082 x = cmtxt("Corrected phone number","",&s,NULL);
3085 if ((int) strlen(s) < 1) {
3089 makestr(&(dn_p2[j]), s);
3092 #endif /* COMMENT */
3095 if (dialtest) { /* Just testing */
3097 printf("\nTESTING...\n");
3099 printf(" Number: \"%s\" => \"%s\"\n",sav,s);
3101 printf(" Number: \"%s\"\n",s);
3106 success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
3107 what &= ~(W_DIALING);
3109 if (dialsta < 8 || /* Break out if unrecoverable error */
3110 dialsta == DIA_INTR ||
3111 dialsta == DIA_ERR ||
3112 previous == DIA_PART
3118 if (success) /* Succeeded, leave the outer loop */
3120 if (dialsta < 8 || /* Break out if unrecoverable error */
3121 dialsta == DIA_INTR || /* Interrupted */
3122 dialsta == DIA_NODT || /* No dialtone */
3123 dialsta == DIA_NOAC || /* Access forbidden */
3124 dialsta == DIA_BLCK || /* Blacklisted */
3125 dialsta == DIA_DIR || /* Dialing directory error */
3126 dialsta == DIA_ERR || /* Modem command error */
3127 previous == DIA_PART)
3129 if (++i >= xretries) /* Break out if too many tries */
3131 if (!backgrd && !quiet) {
3134 "\nWill redial in %d second%s- press any key to redial immediately.\n",
3136 dialint == 1 ? " " : "s "
3138 printf("Ctrl-C to cancel...\n");
3140 x = dialint; /* Redial interval */
3142 if ((y = conchk()) > 0) { /* Did they type something? */
3143 while (y--) coninc(0); /* Yes, absorb it */
3144 break; /* And wake up */
3146 sleep(1); /* No interrupt, sleep a sec */
3154 bleep((short) BP_FAIL);
3156 bleep((short) BP_NOTE);
3158 setint(); /* Fix OS/2 interrupts */
3161 parity = sparity; /* Restore parity if we saved it */
3164 ttres(); /* Restore DIAL device */
3167 concb((char)escape); /* Restore console */
3170 { /* Set session title */
3171 char * p, name[72]; /* in window list. */
3174 q = "Incoming call";
3187 while (*p) { /* Uppercase it for emphasis. */
3194 os2settitle((char *) name, TRUE);
3200 if (reliable == SET_AUTO) { /* It's not a reliable connection. */
3202 debug(F101,"dodial reliable","",reliable);
3207 if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */
3208 extern int dialmhu, dialhng, dialdpy;
3209 extern char * dialmsg[];
3210 printf("\n*************************\n");
3211 printf("DIAL-class command failed.\n");
3212 printf("Modem type: %s\n", gmdmtyp());
3213 printf("Device: %s\n", ttname);
3214 printf("Speed: %ld\n", speed);
3215 printf("Dial status: %d",dialsta);
3216 if (dialsta < 35 && dialmsg[dialsta])
3217 printf(" [%s]",dialmsg[dialsta]);
3219 if (dialsta == DIA_TIMO ||
3220 dialsta == DIA_NRDY ||
3221 (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN)
3226 " . SET DIAL TIMEOUT to a greater value and try again.\n"
3233 " . Is the modem turned on?\n"
3236 " . Are you using the right communication port?\n"
3241 " . Is the modem connected to the telephone line?\n"
3244 if (mdmtyp == n_GENERIC) {
3246 " . Please choose a specific modem type with SET MODEM TYPE and try again.\n"
3249 " SET MODEM TYPE ? to see the list of known modem types.\n"
3253 " . Are you sure you have chosen the appropriate modem type?\n"
3256 if (speed > 19200L) {
3258 " . Maybe the interface speed (%ld) is too fast:\n", speed
3261 " SET SPEED to a lower speed and try again.\n"
3264 " SET SPEED ? to see the list of valid speeds.\n"
3270 " . SET MODEM HANGUP-METHOD RS232 and try again.\n"
3274 " . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n"
3277 " . If that doesn't work, try again with SET DIAL HANGUP OFF.\n"
3281 " . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n"
3286 " . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n"
3291 " . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n"
3297 " . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n"
3300 printf("(Use SET HINTS OFF to suppress future hints.)\n");
3301 printf("*************************\n\n");
3303 #endif /* NOHINTS */
3310 /* D O T Y P E -- Type (display) a file with various options... */
3313 #define TYPBUFL 16384
3316 #endif /* BIGBUFOK */
3318 int typ_lines = 0; /* \v(ty_ln) */
3319 int typ_mtchs = 0; /* \v(ty_lm) */
3320 static int typ_int = 0; /* Flag if TYPE interrupted */
3323 extern int fcharset, fileorder, byteorder, ucsorder;
3324 #define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4
3325 static char * mp = NULL;
3326 static char * mbuf = NULL;
3327 static long xn = 0L;
3333 storechar(c) char c;
3334 #endif /* CK_ANSIC */
3336 if (!mp) return(-1);
3337 if (++xn > TYPXBUFL)
3339 debug(F111,"storechar xn",ckitoa((int)c),xn);
3343 #endif /* UNICODE */
3345 static FILE * ofp = NULL; /* For /OUTPUT: file */
3348 typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
3351 debug(F011,"typeline buf",buf,len);
3352 /* debug(F101,"typeline outcs","",outcs); */
3357 /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */
3358 /* Len is its length in bytes. There is no line terminator. */
3359 /* outcs is the file character-set number (FC_xxx) of the target set */
3360 /* that was requested by the user. */
3361 if (!inserver && !k95stdout) {
3362 extern int wherex[], wherey[];
3363 extern unsigned char colorcmd;
3365 VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2,
3366 wherey[VCMD], wherex[VCMD], &colorcmd);
3370 #endif /* UNICODE */
3371 #endif /* NOLOCAL */
3374 /* In Unix, VMS, etc, the line has already been converted to the desired */
3375 /* character-set, if one was given. OR... on all platforms, including in */
3376 /* K95, we don't know the character set. In either case we dump the line */
3377 /* byte by byte in case it contains NULs (printf() would truncate). */
3380 for (i = 0; i < len; i++)
3383 for (i = 0; i < len; i++) {
3384 if (ofp == stdout) {
3390 #endif /* COMMENT */
3395 if (outcs == FC_UCS2) {
3396 if (ofp == stdout) {
3402 #endif /* UNICODE */
3403 if (ofp == stdout) {
3411 if (outcs == FC_UCS2) {
3412 if (ofp == stdout) {
3418 #endif /* UNICODE */
3419 if (ofp == stdout) {
3428 static int /* Get translated line */
3429 typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
3430 int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0;
3437 if (deblog && typ_lines == 0) {
3438 debug(F101,"typegetline incs","",incs);
3439 debug(F101,"typegetline outcs","",outcs);
3440 debug(F101,"typegetline feol","",feol);
3441 debug(F101,"typegetline byteorder","",byteorder);
3442 debug(F101,"typegetline ucsorder ","",ucsorder);
3443 debug(F111,"typegetline fileorder","1",fileorder);
3447 if (incs < 0) /* Shouldn't happen */
3450 if (outcs == -1) /* Can happen */
3453 if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */
3455 if (!mbuf) { /* Allocate buffer if not allocated */
3456 mbuf = (char *)malloc(TYPXBUFL+1); /* yet */
3458 printf("WARNING: Translation buffer allocation failure.\n");
3459 printf("Translation will be skipped...\n");
3464 if (xlate) { /* Translating... */
3465 mp = mbuf; /* Reset working buffer pointer */
3467 Here we call xgnbyte() in a loop, having it return UCS-2 bytes. In K95, we
3468 use UCS-2 directly. Elsewhere, we feed the UCS-2 bytes into xpnbyte() to
3469 convert them to the desired target character set. But since we are using
3470 UCS-2, we have several sources for confusion: (1) xgnbyte() might return in
3471 LE or BE byte order, with no explicit indication of what the order is; but
3472 (2) xpnbyte() wants BE; but (3) Windows wants LE.
3475 if (typ_int) /* Quit if interrupted */
3477 c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3478 debug(F000,"typegetline c0","",c0);
3479 if (c0 < 0) { /* EOF */
3483 c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3484 debug(F000,"typegetline c1","",c1);
3485 if (c1 < 0) { /* EOF */
3490 if (deblog && typ_lines == 0) {
3491 if (count == 0) /* Check fileorder after BOM */
3492 debug(F111,"typegetline fileorder","2",fileorder);
3497 /* Now we have the two UCS-2 bytes. Which order are they in? */
3499 if (fileorder > 0) { /* Little Endian */
3500 int t; /* So swap them */
3501 debug(F100,"typegetline swapping","",0);
3506 #endif /* COMMENT */
3507 if (c0 == 0 && c1 == 0x0D) /* Now see if we have EOL */
3510 if (c0 == 0 && c1 == 0x0A) /* Now see if we have EOL */
3513 count++; /* Count byte */
3515 /* Give the two bytes to xpnbyte() in BE order */
3517 if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1);
3518 if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1);
3520 if (xxn > -1) { /* Have end of line? */
3522 if (yyn == xxn - 2) /* Adjust for CRLF */
3524 break; /* And break out of loop. */
3528 if (xn > n) /* Can truncate here... */
3530 memcpy(buf,mbuf,xn);
3531 debug(F011,"typegetline xlate",buf,xn);
3532 return((eof && (xn == 0)) ? -1 : xn);
3534 #endif /* UNICODE */
3536 /* We can't use this because, stupidly, zsinl() doesn't return a length. */
3537 /* It could be changed but then we'd have to change all ck?fio.c modules */
3538 x = zsinl(ZIFILE,buf,n);
3540 /* So instead, we copy zsinl() to here... */
3541 /* But note: This does not necessarily handle UCS-2 alignment properly; */
3542 /* that's what the code in the first section of this routine is for. */
3543 /* But it does tolerate files that contain NULs. */
3549 a = -1; /* Current character, none yet. */
3550 debug(F101,"typegetline zsinl simulation","",n);
3551 while (n--) { /* Up to given length */
3554 if (feol) /* Previous character */
3556 #endif /* COMMENT */
3557 if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */
3558 debug(F101,"typegetline zchin fail","",count);
3560 x = -1; /* EOF or other error */
3564 if (feol) { /* Single-character line terminator */
3567 } else { /* CRLF line terminator */
3569 /* Debug log shows that in Windows, <CR><LF> is returned as <LF>. */
3570 /* Apparently we're not reading the file in binary mode. */
3572 if (a == '\015') /* CR, get next character */
3574 if (old == '\015') { /* Previous character was CR */
3575 if (a == '\012') { /* This one is LF, so we have a line */
3577 } else { /* Not LF, deposit CR */
3585 if (s[len] == CR) { /* This probably won't happen */
3592 #endif /* COMMENT */
3594 *s = a; /* Deposit character */
3598 *s = '\0'; /* Terminate the string */
3600 #endif /* COMMENT */
3601 return(x < 0 ? -1 : len);
3608 tytrap(int foo) /* TYPE interrupt trap */
3610 tytrap(foo) int foo;
3611 #endif /* CK_ANSIC */
3614 signal(SIGINT, SIG_ACK);
3616 debug(F100,"type tytrap SIGINT","",0);
3617 typ_int = 1; /* (Need arg for ANSI C) */
3623 dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z)
3624 char * file, * pat, * prefix; int paging, first, head, width, incs, outcs;
3625 char * outfile; int z;
3628 char buf[TYPBUFL+2];
3630 int rc = 1, lines = 0, ucs2 = 0;
3631 char ** tail = NULL;
3633 int tailing = 0, counting = 0;
3634 int x, c, n, i, j, k = 0;
3635 int number = 0, save, len, pfxlen = 0, evalpfx = 1;
3639 #endif /* UNICODE */
3647 SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
3649 SIGTYP (* volatile oldsig)(int);
3652 SIGTYP (* oldsig)();
3657 if (outfile == (char *)1) {
3663 if (!file) file = "";
3664 if (!*file) return(-2);
3666 if (ofp != stdout) { /* In case of previous interruption */
3667 if (ofp) fclose(ofp);
3670 if (!outfile) outfile = "";
3672 ofp = fopen(outfile,"w"); /* Open output file */
3674 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
3680 if (number && prefix) prefix = NULL;
3683 ucsbom_sav = ucsbom; /* We are not creating a file */
3684 ucsbom = 0; /* Do not use BOM bytes */
3685 #endif /* UNICODE */
3689 save = binary; /* Save file type */
3691 debug(F101,"dotype incs","",incs);
3692 debug(F101,"dotype outcs","",outcs);
3695 debug(F111,"dotype fileorder","A",fileorder);
3697 if (!inserver && !k95stdout)
3701 if (outcs == FC_UCS2) /* Output is UCS-2? */
3704 fileorder = ucsorder;
3705 debug(F111,"dotype fileorder","B",fileorder);
3706 #endif /* UNICODE */
3712 /* Check whether window size changed */
3713 if (ttgwsiz() > 0) {
3714 if (tt_rows > 0 && tt_cols > 0) {
3717 debug(F101,"dotype cmd_rows","",cmd_rows);
3718 debug(F101,"dotype cmd_cols","",cmd_cols);
3722 #endif /* CK_TTGWSIZ */
3725 pfxlen = strlen(prefix);
3727 if (paging < 0) { /* Count only, don't print */
3733 if (ucs2) /* Crude... */
3738 ckstrncpy(buf, file, TYPBUFL); /* Change / to \. */
3741 if (*p == '/') *p = '\\';
3751 if (zchki(file) == -2) { /* It's a directory */
3752 debug(F111,"dotype zchki failure",file,-2);
3754 printf("?Not a regular file: \"%s\"\n",file);
3760 if (!zopeni(ZIFILE, file)) { /* Not a directory, open it */
3761 debug(F111,"dotype zopeni failure",file,0);
3763 printf("?Can't open file: \"%s\"\n",file);
3773 oldsig = signal(SIGINT, tytrap); /* Save current interrupt trap. */
3774 debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig);
3778 if (paging > -1) /* More-prompting */
3783 if (head < 0) { /* "tail" was requested */
3784 tailing = 1; /* Set flag */
3785 head = 0 - head; /* Get absolute number of lines */
3787 tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
3789 printf("?Memory allocation failure\n");
3793 tlen = (int *) malloc(head * sizeof(int));
3795 printf("?Memory allocation failure\n");
3799 for (i = 0; i < head; i++) { /* Initialize each pointer in list. */
3809 if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */
3811 initxlate(incs,outcs); /* Set up translation functions */
3813 #endif /* UNICODE */
3814 outcs = -1; /* Means we don't know the charset */
3816 debug(F101,"dotype ffc","",ffc);
3817 debug(F101,"dotype outcs 2","",outcs);
3819 debug(F111,"dotype fileorder","C",fileorder);
3820 #endif /* UNICODE */
3822 /* Allow the buffer to contain NULs */
3825 (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1;
3828 debug(F011,"dotype line",buf,len);
3830 if (typ_int) { /* Interrupted? */
3832 debug(F101,"type interrupted line","",lines);
3833 printf("^C...\n"); /* Print message */
3834 if (ofp != stdout) { /* Close any output file */
3835 if (ofp) fclose(ofp);
3841 typ_lines++; /* For \v(ty_ln) */
3842 if (pat) /* Matching? */
3843 if (!ckmatch(pat,buf,1,1+4)) /* Line matches pattern? */
3844 continue; /* No, skip it */
3847 if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
3850 buf[TYPBUFL+1] = NUL; /* Just in case... */
3851 if (prefix) { /* Add specified prefix to each line */
3856 if (evalpfx) { /* Prefix is a variable? */
3857 int n = 63; /* Maybe - evaluate it and see */
3859 zzstring(prefix,&p,&n); /* If there is no change */
3860 if (!strcmp(prefix,pbuf)) { /* it's not a variable */
3861 evalpfx = 0; /* So don't do this again. */
3862 } else { /* It was a variable */
3863 pp = pbuf; /* So substitute its value */
3864 pfxlen = 63 - n; /* and get its new length */
3868 if (len + pfxlen + 2 < TYPBUFL) {
3869 /* Shift right to make room for prefix */
3870 memcpy((char *)line+pfxlen,(char *)buf,len);
3871 lset((char *)line,pp,pfxlen,SP);
3872 debug(F110,"dotype prefix",line,pfxlen);
3874 memcpy((char *)buf,(char *)line,len);
3876 } else if (number) { /* Line numbers */
3878 sprintf(line,"%4d. ",typ_lines);
3881 if (len < LINBUFSIZ) {
3882 memcpy((char *)&line[x],(char *)buf,len);
3883 memcpy((char *)buf,(char *)line,len);
3886 if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
3887 char * obuf = line; /* But to do that first we must */
3888 int i,k,z; /* expand tabs; assume every 8 cols. */
3890 for (i = 0, k = 0; i < width; k++) { /* Character loop... */
3891 if (!buf[k]) /* No more chars in this line, done. */
3893 if (buf[k] != '\t') { /* If it's not a tab */
3894 if (i >= LINBUFSIZ) /* Check for overflow */
3896 obuf[i++] = buf[k]; /* and then deposit it. */
3897 obuf[i] = NUL; /* Keep it null-terminated */
3900 z = 8 - (i % 8); /* It's a tab, expand it. */
3902 for (j = 0; j < z && i < LINBUFSIZ; j++) {
3904 if (ucs2 && !ucsorder)
3906 #endif /* UNICODE */
3909 if (ucs2 && ucsorder)
3911 #endif /* UNICODE */
3916 obuf[width] = NUL; /* Now truncate at given width. */
3918 /* This doesn't work for UCS-2 because it contains NULs */
3919 ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
3921 memcpy((char *)buf,(char *)obuf,i); /* Copy it back */
3922 #endif /* COMMENT */
3923 len = (i > width) ? width : i; /* Spare us another strlen()... */
3925 if (tailing) { /* If /TAIL:n... */
3926 k = lines % head; /* save this line in circular buffer */
3928 if (tail[k]) free(tail[k]);
3929 tail[k] = malloc(len+2);
3931 printf("?Memory allocation failure\n");
3934 memcpy(tail[k],buf,len);
3939 if (counting) /* If only counting */
3940 continue; /* we're done with this line */
3942 if (paging) { /* Displaying this line... */
3944 u = len; /* Length in BYTES */
3945 if (ucs2) /* If outputting in UCS-2 */
3946 u /= 2; /* convert length to CHARACTERS */
3947 x = (u / cmd_cols) + 1; /* Crudely allow for wrap */
3948 if (cmd_rows > 0 && cmd_cols > 0)
3949 n += x; /* This assumes terminal will wrap */
3954 unsigned short * uch = (unsigned short *)buf;
3955 for ( i=0; i<len/2; i++)
3956 gui_text_popup_append(uch[i]);
3957 gui_text_popup_append(CR);
3958 gui_text_popup_append(LF);
3962 typeline(buf,len,outcs,ofp); /* Print line, length based */
3964 debug(F101,"dotype n","",n);
3965 if (paging > 0 && ofp == stdout) { /* Pause at end of screen */
3966 if (cmd_rows > 0 && cmd_cols > 0) {
3967 if (n > cmd_rows - 3) {
3975 #endif /* CK_TTGWSIZ */
3981 "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
3984 "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
3987 if (tailing && tail) { /* Typing tail of file? */
3988 if (lines < head) { /* Yes, show the lines we saved */
3989 k = 0; /* Show all lines */
3990 } else { /* More lines than tail number */
3991 lines = k; /* Last line to show */
3992 k++; /* First line to show */
3996 n = first; /* Output line counter */
3997 for (i = k ;; i++) { /* Loop thru circular buffer */
3999 if (typ_int) { /* Interrupted? */
4000 printf("^C...\n"); /* Print message */
4004 j = i % head; /* Index of this line */
4005 s = tail[j]; /* Point to line to display */
4006 if (!s) /* (shouldn't happen...) */
4008 if (paging) { /* Crudely allow for line wrap */
4011 x = x / cmd_cols + 1;
4012 if (cmd_rows > 0 && cmd_cols > 0)
4015 typeline(s,tlen[j],outcs,ofp); /* Display this line */
4016 if (paging && ofp == stdout) { /* Pause at end of screen */
4017 if (cmd_rows > 0 && cmd_cols > 0) {
4018 if (n > cmd_rows - 3) {
4027 free(s); /* Free the line */
4028 if (i % head == lines) /* When to stop */
4031 free((char *)tail); /* Free the list */
4033 if (tlen) free((char *)tlen);
4037 /* Come here when finished or on SIGINT */
4042 signal(SIGINT,oldsig); /* Put old signal action back. */
4045 if (tailing && tail) {
4046 for (i = 0; i < head; i++) { /* Free each line. */
4050 free((char *)tail); /* Free list pointer */
4054 x = zclose(ZIFILE); /* Done, close the input file */
4055 if (ofp != stdout) { /* Close any output file */
4056 if (ofp) fclose(ofp);
4059 binary = save; /* Restore text/binary mode */
4061 ucsbom = ucsbom_sav; /* Restore BOM usage */
4062 #endif /* UNICODE */
4066 gui_text_popup_wait(-1); /* Wait for user to close the dialog */
4073 #define GREP_CASE 0 /* /CASE */
4074 #define GREP_COUN 1 /* /COUNT */
4075 #define GREP_DOTF 2 /* /DOTFILES */
4076 #define GREP_NAME 3 /* /NAMEONLY */
4077 #define GREP_NOBK 4 /* /NOBACKUP */
4078 #define GREP_NODO 5 /* /NODOTFILES */
4079 #define GREP_NOLI 6 /* /NOLIST */
4080 #define GREP_NOMA 7 /* /INVERT = /NOMATCH */
4081 #define GREP_NOPA 8 /* /NOPAGE */
4082 #define GREP_NUMS 9 /* /LINENUMBERS */
4083 #define GREP_PAGE 10 /* /PAGE */
4084 #define GREP_RECU 11 /* /RECURSIVE */
4085 #define GREP_TYPE 12 /* /TYPE: */
4086 #define GREP_OUTP 13 /* /OUTPUTFILE: */
4088 static struct keytab greptab[] = {
4089 { "/count", GREP_COUN, CM_ARG },
4090 { "/dotfiles", GREP_DOTF, 0 },
4091 { "/linenumbers", GREP_NUMS, 0 },
4092 { "/nameonly", GREP_NAME, 0 },
4093 { "/nobackupfiles",GREP_NOBK, 0 },
4094 { "/nocase", GREP_CASE, 0 },
4095 { "/nodotfiles", GREP_NODO, 0 },
4096 { "/nolist", GREP_NOLI, 0 },
4097 { "/nomatch", GREP_NOMA, 0 },
4098 { "/nopage", GREP_NOPA, 0 },
4099 { "/output", GREP_OUTP, CM_ARG },
4100 { "/page", GREP_PAGE, 0 },
4101 { "/quiet", GREP_NOLI, CM_INV },
4103 { "/recursive", GREP_RECU, 0 },
4104 #endif /* RECURSIVE */
4105 { "/type", GREP_TYPE, CM_ARG },
4108 static int ngreptab = sizeof(greptab)/sizeof(struct keytab)-1;
4112 int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0;
4113 int fline = 0, sline = 0, wild = 0, len = 0;
4114 int xmode = -1, scan = 0;
4115 char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
4118 int /* Switch values and defaults */
4130 g_matchdot = matchdot; /* Save global matchdot setting */
4133 if (ofp != stdout) { /* In case of previous interruption */
4134 if (ofp) fclose(ofp);
4137 cmfdbi(&sw, /* First FDB - command switches */
4139 "String or pattern to search for, or switch",
4141 "", /* addtl string data */
4142 ngreptab, /* addtl numeric data 1: tbl size */
4143 4, /* addtl numeric data 2: 4 = cmswi */
4144 xxstring, /* Processing function */
4145 greptab, /* Keyword table */
4146 &fl /* Pointer to next FDB */
4148 cmfdbi(&fl, /* Anything that doesn't match */
4152 "", /* addtl string data */
4153 0, /* addtl numeric data 1 */
4154 0, /* addtl numeric data 2 */
4155 xxstring, /* xxstring */
4159 while (1) { /* Parse 0 or more switches */
4160 x = cmfdb(&sw); /* Parse something */
4163 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
4166 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4167 printf("?This switch does not take an argument\n");
4170 if ((cmresult.nresult != GREP_COUN) && !getval &&
4171 (cmgkwflgs() & CM_ARG)) {
4172 printf("?This switch requires an argument\n");
4175 switch (cmresult.nresult) {
4179 if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
4185 case GREP_CASE: gr_case=0; break;
4186 case GREP_NAME: gr_name++; gr_noli=0; break;
4187 case GREP_NOBK: gr_nobk++; break;
4188 case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break;
4189 case GREP_NOMA: gr_noma++; break;
4190 case GREP_NOPA: gr_page=0; break;
4191 case GREP_NUMS: gr_nums++; gr_noli=0; break;
4192 case GREP_PAGE: gr_page++; gr_noli=0; break;
4203 #endif /* RECURSIVE */
4205 extern struct keytab txtbin[];
4206 if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
4208 if (x == 2) { /* ALL */
4210 } else { /* TEXT or BINARY only */
4216 case GREP_OUTP: /* Send output to file */
4217 if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0)
4219 ckstrncpy(outfile,s,CKMAXPATH);
4224 ofp = fopen(outfile,"w"); /* Open output file */
4226 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
4232 s = cmresult.sresult;
4233 s = brstrip(s); /* Strip braces from pattern */
4235 printf("?Pattern required\n");
4238 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save pattern */
4239 if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) {
4241 printf("?File specification required\n");
4246 s = brstrip(s); /* Strip braces from filename */
4248 ckstrncpy(line,s,LINBUFSIZ);
4249 #endif /* ZXREWIND */
4250 if ((y = cmcfm()) < 0)
4254 xaskmore = gr_page; /* Paging... */
4256 p = tmpbuf; /* Point to pattern */
4258 /* Now this is done in ckmatch */
4259 if (*p == '^') { /* '^' anchors pattern to beginning */
4261 } else if (*p != '*') { /* Otherwise prepend implied '*' */
4265 x = strlen(p); /* Get length of result */
4266 if (x > 0 && x < TMPBUFSIZ) { /* '$' at end anchors pattern to end */
4267 if (p[x-1] == '$') {
4269 } else if (p[x-1] != '*') {
4274 #endif /* COMMENT */
4275 debug(F111,"grep pat",p,x);
4278 fc = zxrewind(); /* Rewind the file list */
4281 int flags = ZX_FILONLY; /* Expand file list */
4282 if (matchdot) flags |= ZX_MATCHDOT;
4283 if (recursive) flags |= ZX_RECURSE;
4284 fc = nzxpand(line,flags);
4286 #endif /* ZXREWIND */
4288 sh_sort(mtchs,NULL,fc,0,0,filecase);
4291 debug(F101,"grep cmd_rows","",cmd_rows);
4292 debug(F101,"grep cmd_cols","",cmd_cols);
4294 while (1) { /* Loop for each file */
4295 znext(name); /* Get next file */
4296 if (!name[0]) /* No more, done */
4298 if (gr_nobk) /* Skipping backup files? */
4299 if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */
4300 continue; /* Yes, skip */
4301 if (scan) { /* /TYPE: given? */
4302 switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */
4313 #endif /* UNICODE */
4318 fp = fopen(name,"r"); /* Open */
4319 if (!fp) /* Can't */
4320 continue; /* Skip */
4321 count = 0; /* Match count, this file */
4322 fline = 0; /* Line count, this file */
4323 while (1) { /* Loop for each line */
4324 if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */
4327 debug(F100,"GREP EOF","",0);
4330 fline++; /* Count this line */
4331 line[LINBUFSIZ] = NUL; /* Make sure it's terminated */
4332 debug(F111,"GREP",line,fline);
4333 len = (int)strlen(line); /* Get length */
4334 while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
4335 line[--len] = NUL; /* Chop off terminators */
4336 match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
4337 if (gr_noma) /* Invert match sense if requested */
4339 if (match) { /* Have a matching line */
4340 mc++; /* Total match count */
4341 count++; /* Match count this file */
4342 if (gr_name) { /* Don't care how many lines match */
4343 fclose(fp); /* Close the file */
4344 fp = NULL; /* and quit the line-reading loop. */
4347 if (gr_coun || gr_noli) /* Not listing each line */
4348 continue; /* so don't print anything now. */
4349 if (wild) { /* If searching multiple files */
4350 fprintf(ofp,"%s:",name); /* print filename. */
4351 len += (int)strlen(name) + 1;
4353 if (gr_nums) { /* If line numbers wanted */
4355 len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
4356 fprintf(ofp,"%s",nbuf);
4358 if (cmd_rows > 0 && cmd_cols > 0)
4359 sline += (len / cmd_cols) + 1;
4360 fprintf(ofp,"%s\n",line); /* Print the line. */
4361 if (sline > cmd_rows - 3) {
4362 if (!askmore()) goto xgrep; else sline = 0;
4366 if (!gr_noli) { /* If not not listing... */
4368 if (gr_coun) { /* Show match count only */
4369 fprintf(ofp,"%s:%d\n",name,count);
4371 } else if (gr_name && count > 0) { /* Show name only */
4372 fprintf(ofp,"%s\n",name);
4376 if (++sline > cmd_rows - 3) {
4377 if (!askmore()) goto xgrep; else sline = 0;
4381 bigcount += count; /* Overall count */
4385 if (gr_coun && cv) { /* /COUNT:blah */
4386 addmac(cv,ckitoa(bigcount)); /* set the variable */
4387 makestr(&cv,NULL); /* free this */
4390 if (fp) fclose(fp); /* close input file if still open */
4391 if (ofp != stdout) { /* Close any output file */
4392 if (ofp) fclose(ofp);
4395 return(success = mc ? 1 : 0);
4398 /* System-independent directory */
4400 static char ** dirlist = NULL;
4401 static int ndirlist = 0;
4407 for (i = 0; i < ndirlist; i++) {
4411 free((char *)dirlist);
4417 static struct keytab dirswtab[] = { /* DIRECTORY command switches */
4418 { "/after", DIR_AFT, CM_ARG },
4419 { "/all", DIR_ALL, 0 },
4421 { "/array", DIR_ARR, CM_ARG },
4423 { "/ascending", DIR_ASC, 0 },
4424 { "/backup", DIR_BUP, 0 },
4425 { "/before", DIR_BEF, CM_ARG },
4426 { "/brief", DIR_BRF, 0 },
4427 { "/descending", DIR_DSC, CM_INV },
4428 { "/directories", DIR_DIR, 0 },
4429 { "/dotfiles", DIR_DOT, 0 },
4430 { "/englishdate", DIR_DAT, 0 },
4431 { "/except", DIR_EXC, CM_ARG },
4432 { "/files", DIR_FIL, 0 },
4433 { "/heading", DIR_HDG, 0 },
4434 { "/isodate", DIR_ISO, 0 },
4435 { "/larger-than", DIR_LAR, CM_ARG },
4437 { "/followlinks", DIR_LNK, 0 },
4438 #endif /* CKSYMLINK */
4439 { "/message", DIR_MSG, CM_ARG },
4440 { "/nobackupfiles",DIR_NOB, 0 },
4441 { "/nodotfiles", DIR_NOD, 0 },
4443 { "/nofollowlinks",DIR_NLK, 0 },
4444 #endif /* CKSYMLINK */
4445 { "/noheading", DIR_NOH, 0 },
4446 { "/nomessage", DIR_NOM, 0 },
4448 { "/nopage", DIR_NOP, 0 },
4449 #endif /* CK_TTGWSIZ */
4451 { "/norecursive", DIR_NOR, 0 },
4454 { "/norecursive", DIR_NOR, 0 },
4457 { "/norecursive", DIR_NOR, 0 },
4458 #endif /* datageneral */
4460 #endif /* RECURSIVE */
4461 { "/nosort", DIR_NOS, 0 },
4462 { "/not-after", DIR_NAF, CM_ARG },
4463 { "/not-before", DIR_NBF, CM_ARG },
4464 { "/not-since", DIR_NAF, CM_INV|CM_ARG },
4465 { "/noxfermode", DIR_NOT, 0 },
4466 { "/output", DIR_OUT, CM_ARG },
4468 { "/page", DIR_PAG, 0 },
4469 #endif /* CK_TTGWSIZ */
4471 { "/recursive", DIR_REC, 0 },
4474 { "/recursive", DIR_REC, 0 },
4477 { "/recursive", DIR_REC, 0 },
4478 #endif /* datageneral */
4480 #endif /* RECURSIVE */
4481 { "/reverse", DIR_DSC, 0 },
4482 { "/since", DIR_AFT, CM_ARG|CM_INV },
4483 { "/smaller-than",DIR_SMA, CM_ARG },
4484 { "/sort", DIR_SRT, CM_ARG },
4485 { "/summary", DIR_SUM, 0 },
4486 { "/type", DIR_BIN, CM_ARG },
4487 { "/xfermode", DIR_TYP, 0 },
4488 { "/verbose", DIR_VRB, 0 },
4491 static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
4493 static struct keytab dirsort[] = { /* DIRECTORY /SORT: options */
4494 { "date", DIRS_DT, 0 },
4495 { "name", DIRS_NM, 0 },
4496 { "size", DIRS_SZ, 0 }
4498 static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
4500 static int dir_date = -1; /* Option defaults (-1 means none) */
4501 static int dir_page = -1;
4502 static int dir_verb = 1;
4503 static int dir_msg = -1;
4505 static int dir_sort = -1; /* Names are already sorted in VMS */
4506 static int dir_rvrs = -1;
4508 static int dir_sort = 1; /* Sort by default */
4509 static int dir_rvrs = 0; /* Not in reverse */
4511 static int dir_skey = DIRS_NM; /* By name */
4513 static int dir_recu = -1;
4514 #endif /* RECURSIVE */
4515 static int dir_mode = -1;
4516 static int dir_show = -1; /* Show all files by default */
4517 int dir_dots = -1; /* Except dot files */
4520 static char * dirmsg = NULL;
4521 static int dirmsglen = 0;
4527 extern int optlines;
4528 prtopt(&optlines,"DIRECTORY");
4530 prtopt(&optlines,(dir_show == 1) ? "/FILES" :
4531 ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
4534 prtopt(&optlines,"/ALL");
4537 if (dir_verb > -1) {
4538 prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
4541 if (dir_page > -1) {
4542 prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
4545 if (dir_date > -1) {
4546 prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
4549 if (dir_dots > -1) {
4550 prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
4553 if (dir_back > -1) {
4554 prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
4557 if (dir_head > -1) {
4558 prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
4562 if (dir_recu > -1) {
4563 prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
4566 #endif /* RECURSIVE */
4567 if (dir_mode > -1) {
4568 prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
4571 if (dir_sort == 0) {
4573 prtopt(&optlines,"/NOSORT ");
4574 } else if (dir_sort > 0) {
4576 if (dir_skey == DIRS_NM) s = "/SORT:NAME";
4577 else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
4578 else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
4579 prtopt(&optlines,s);
4581 if (dir_rvrs > -1) {
4582 prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
4587 prtopt(&optlines,"/NOMESSAGE");
4589 ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL);
4590 prtopt(&optlines,tmpbuf);
4594 if (!x) prtopt(&optlines,"(no options set)");
4595 prtopt(&optlines,"");
4600 setdiropts() { /* Set DIRECTORY option defaults */
4601 int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
4602 int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
4606 if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
4613 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4614 printf("?This switch does not take an argument\n");
4617 if (!getval && (cmgkwflgs() & CM_ARG)) {
4618 printf("?This switch requires an argument\n");
4622 case DIR_BRF: xv = 0; break;
4623 case DIR_VRB: xv = 1; break;
4624 case DIR_PAG: xp = 1; break;
4625 case DIR_NOP: xp = 0; break;
4626 case DIR_ISO: xd = 0; break;
4627 case DIR_DAT: xd = 1; break;
4628 case DIR_HDG: xh = 1; break;
4629 case DIR_NOH: xh = 0; break;
4630 case DIR_DOT: xf = 1; break;
4631 case DIR_NOD: xf = 0; break;
4632 case DIR_ALL: xa = 3; break;
4633 case DIR_DIR: xa = 2; break;
4634 case DIR_FIL: xa = 1; break;
4638 if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
4643 case DIR_NOS: xs = 0; break;
4644 case DIR_ASC: xx = 0; break;
4645 case DIR_DSC: xx = 1; break;
4646 case DIR_REC: xr = 1; break;
4647 case DIR_NOR: xr = 0; break;
4648 case DIR_TYP: xm = 1; break;
4649 case DIR_NOT: xm = 0; break;
4650 case DIR_BUP: xb = 1; break;
4651 case DIR_NOB: xb = 0; break;
4652 case DIR_NOM: xg = 0; break;
4655 if ((x = cmfld("Message to append to each line",
4662 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
4665 printf("?This option can not be set\n");
4669 if ((x = cmcfm()) < 0) /* Get confirmation */
4671 if (xv > -1) dir_verb = xv; /* Confirmed, save defaults */
4672 if (xp > -1) dir_page = xp;
4673 if (xd > -1) dir_date = xd;
4674 if (xh > -1) dir_head = xh;
4675 if (xs > -1) dir_sort = xs;
4676 if (xk > -1) dir_skey = xk;
4677 if (xx > -1) dir_rvrs = xx;
4678 if (xf > -1) dir_dots = xf;
4679 if (xa > -1) dir_show = xa;
4680 if (xm > -1) dir_mode = xm;
4681 if (xb > -1) dir_back = xb;
4683 if (xr > -1) dir_recu = xr;
4684 #endif /* RECURSIVE */
4685 if (xg > -1) dir_msg = xg;
4687 makestr(&dirmsg,tmpbuf);
4688 return(success = 1);
4692 domydir() { /* Internal DIRECTORY command */
4693 extern char *months[];
4695 _PROTOTYP( char * zrelname, (char *,char *) );
4699 char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
4700 char linebuf[CKMAXPATH+256];
4701 char * mstr = NULL, * dstr = NULL, * s2 = NULL;
4702 long len = 0, ndirs = 0, nfiles = 0, nbytes = 0, nmatches = 0;
4703 int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0;
4704 int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
4705 int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
4706 int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
4709 int cmifn1 = 1, cmifn2 = 0;
4710 long minsize = -1L, maxsize = -1L;
4711 struct FDB sw, fi, fl;
4712 char dbuf[32], xbuf[32];
4726 g_matchdot = matchdot; /* Save global matchdot setting */
4727 nolinks = 2; /* (it should already be 2) */
4728 outfile[0] = NUL; /* No output file yet */
4730 if (ofp != stdout) { /* In case of previous interruption */
4731 if (ofp) fclose(ofp);
4734 for (i = 0; i < 16; i++) xlist[i] = NULL;
4737 freedirlist(); /* In case not freed last time */
4738 page = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
4739 engdate = dir_date > -1 ? dir_date : 0;
4740 verbose = dir_verb > -1 ? dir_verb : 1;
4741 heading = dir_head > -1 ? dir_head : 0;
4742 xsort = dir_sort > -1 ? dir_sort : 0;
4743 sortby = dir_skey > -1 ? dir_skey : 0;
4744 reverse = dir_rvrs > -1 ? dir_rvrs : 0;
4745 msg = dir_msg > -1 ? dir_msg : 0;
4747 if (dir_dots > -1) matchdot = dir_dots;
4748 #endif /* UNIXOROSK */
4749 xfermod = dir_mode > -1 ? dir_mode : 0;
4750 backup = dir_back > -1 ? dir_back : 1;
4752 recursive = dir_recu > -1 ? dir_recu : 0;
4753 #endif /* RECURSIVE */
4754 show = dir_show > -1 ? dir_show : 3;
4758 ttgcwsz(); /* Screen length for more-prompting */
4760 /* Check whether window size changed */
4761 if (ttgwsiz() > 0) {
4762 if (tt_rows > 0 && tt_cols > 0) {
4768 #endif /* CK_TTGWSIZ */
4771 cmifn1 = nolinks | 1; /* 1 = files or directories */
4772 cmifn2 = 0; /* 0 = not directories only */
4776 cmfdbi(&sw, /* First FDB - command switches */
4778 "Enter or Return to confirm the command, or\n\
4779 file specification, or switch",
4781 "", /* addtl string data */
4782 ndirswtab, /* addtl numeric data 1: tbl size */
4783 4, /* addtl numeric data 2: 4 = cmswi */
4784 xxstring, /* Processing function */
4785 dirswtab, /* Keyword table */
4786 &fi /* Pointer to next FDB */
4788 cmfdbi(&fi, /* 2nd FDB - filespec to match */
4790 "File specification", /* hlpmsg */
4792 "+", /* Default filespec is wildcard */
4793 #else /* that matches all files... */
4799 #endif /* datageneral */
4800 "", /* addtl string data */
4802 cmifn2, /* 1 = only dirs; 0 files or dirs */
4807 cmfdbi(&fl, /* Anything that doesn't match */
4811 "", /* addtl string data */
4812 0, /* addtl numeric data 1 */
4813 0, /* addtl numeric data 2 */
4818 while (1) { /* Parse 0 or more switches */
4819 x = cmfdb(&sw); /* Parse something */
4820 debug(F101,"domydir cmfdb","",x);
4823 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
4826 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4827 printf("?This switch does not take an argument\n");
4830 if (!getval && (cmgkwflgs() & CM_ARG)) {
4831 printf("?This switch requires an argument\n");
4834 switch (k = cmresult.nresult) {
4835 case DIR_BRF: verbose = 0; break;
4836 case DIR_VRB: verbose = 1; break;
4838 case DIR_PAG: page = 1; break;
4839 case DIR_NOP: page = 0; break;
4840 #endif /* CK_TTGWSIZ */
4841 case DIR_ISO: engdate = 0; break;
4842 case DIR_DAT: engdate = 1; break;
4843 case DIR_HDG: heading = 1; break;
4844 case DIR_NOH: heading = 0; break;
4846 case DIR_DOT: matchdot = 1; break;
4847 case DIR_NOD: matchdot = 0; break;
4848 #endif /* UNIXOROSK */
4866 if (c == ':' || c == '=')
4867 if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
4873 case DIR_BUP: backup = 1; fs++; break;
4874 case DIR_NOB: backup = 0; fs++; break;
4876 case DIR_NOS: xsort = 0; break;
4877 case DIR_ASC: reverse = 0; break;
4878 case DIR_DSC: reverse = 1; break;
4880 case DIR_REC: recursive = 1; diractive = 1; break;
4881 case DIR_NOR: recursive = 0; diractive = 0; break;
4882 #endif /* RECURSIVE */
4883 case DIR_TYP: xfermod = 1; break;
4884 case DIR_NOT: xfermod = 0; break;
4887 case DIR_LNK: /* Follow links */
4891 case DIR_NLK: /* Don't follow links */
4895 #endif /* CKSYMLINK */
4897 case DIR_NOM: msg = 0; break;
4899 if (c == ':' || c == '=')
4900 if ((x = cmfld("Message to append to each line",
4907 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
4913 if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
4917 switch (cmresult.nresult) {
4918 case DIR_SMA: minsize = y; break;
4919 case DIR_LAR: maxsize = y; break;
4925 if (c != ':' && c != '=') {
4926 printf("?Array name required\n");
4929 if ((x = cmfld("Array name (a single letter will do)",
4935 printf("?Array name required\n");
4941 printf("?Array name required\n");
4945 if (*s == CMDQ) s++;
4948 printf("?Bad array name - \"%s\"\n",s2);
4952 if (isupper(array)) array = tolower(array);
4953 if (*s && (*s != '[' || *(s+1) != ']')) {
4954 printf("?Bad array name - \"%s\"\n",s2);
4964 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
4966 printf("?Date-time required\n");
4974 case DIR_AFT: makestr(&dir_aft,s); break;
4975 case DIR_BEF: makestr(&dir_bef,s); break;
4976 case DIR_NAF: makestr(&dir_naf,s); break;
4977 case DIR_NBF: makestr(&dir_nbf,s); break;
4982 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
4984 printf("?Pattern required\n");
4991 makestr(&dir_exc,s);
4998 extern struct keytab txtbin[];
4999 extern int xfiletype;
5001 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) {
5014 if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0)
5016 ckstrncpy(outfile,s,CKMAXPATH+1);
5020 printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
5024 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
5026 /* ^^^ START MULTIPLE */
5029 x = cmfld("Another filespec or Enter","",&s,xxstring);
5034 ckstrncat(line,",",LINBUFSIZ);
5035 ckstrncat(line,s,LINBUFSIZ);
5038 ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL);
5039 ckstrncpy(line,tmpbuf,LINBUFSIZ);
5040 cmresult.nresult = 1;
5041 cmresult.fcode = _CMIFI;
5043 /* ^^^ END MULTIPLE */
5047 if ((x = cmcfm()) < 0) /* Get confirmation */
5049 if (cmresult.fcode != _CMIFI) { /* Nothing matched */
5053 m = "does not match switch or name of accessible file";
5056 m = "does not match switch or name of accessible file";
5058 m = "no switches match";
5060 #endif /* UNIXOROSX */
5062 m = "not found or not accessible";
5063 printf("\"%s\" - %s\n",s,m);
5067 wild = cmresult.nresult; /* Wildcard was given? */
5068 debug(F111,"domydir cmifi2",s,wild);
5071 ofp = fopen(outfile,"w"); /* Open output file */
5073 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
5082 if (zchki(s) == -2) { /* Found a directory */
5083 p = s + (int)strlen(s) - 1; /* Yes */
5084 if (*p == '\\' || *p == '/')
5090 wild = 1; /* Now it's wild */
5094 if (!wild) if (isdir(s)) { /* Is it a directory? */
5095 p = s + (int)strlen(s) - 1; /* Yes */
5098 /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
5099 char buf[CKMAXPATH+1];
5100 debug(F000,"domydir directory 0",s,*p);
5101 if (cvtdir(s,buf,CKMAXPATH) > 0)
5102 ckstrncpy(line,buf,LINBUFSIZ);
5105 debug(F000,"domydir directory 1",s,*p);
5107 if (*p == ']' || *p == '>' || *p == ':')
5121 #endif /* STRATUS */
5122 #endif /* datageneral */
5124 wild = 1; /* Now it's wild */
5125 debug(F000,"domydir directory 2",s,*p);
5130 /* cmifi() already called nzxpand so we can just re-use the same list. */
5132 x = zxrewind(); /* Rewind the list */
5133 debug(F111,"domydir zxrewind",s,x);
5135 #endif /* ZXREWIND */
5136 nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
5137 (show == ZX_FILONLY ? ZX_FILONLY : 0);
5138 if (matchdot) nzxopts |= ZX_MATCHDOT;
5139 if (recursive) nzxopts |= ZX_RECURSE;
5140 x = nzxpand(s,nzxopts); /* Expand file list */
5141 debug(F111,"domydir nzxpand",s,x);
5144 #endif /* ZXREWIND */
5149 n = (x < 0) ? 0 : x;
5150 if ((xx = dclarray(array,n)) < 0) {
5151 printf("?Array declaration failure\n");
5165 extern int ckrooterr;
5167 printf("?Off limits: %s\n",s);
5170 if (x == 0 && isdir(s))
5171 printf("?Empty directory - \"%s\"\n", s);
5173 printf("?%s %s match - \"%s\"\n",
5174 (x == 0) ? "No" : "Too many",
5175 (show == 2) ? "directories" : "files",
5181 nx = x; /* Remember how many files */
5184 makestr(&dirmsg,tmpbuf);
5185 dirmsglen = strlen(tmpbuf);
5189 cdp = zgtdir(); /* Get current directory */
5190 debug(F110,"domydir VMS zgtdir",cdp,0);
5193 if (xsort && verbose) { /* If sorting, allocate space */
5194 if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
5196 printf("* Warning: Failure to allocate memory for sorting.\n");
5197 printf("* Will proceed without sorting...\n");
5201 debug(F101,"domydir sort malloc","",xsort);
5204 /* Display the listing */
5207 if (array) /* Storing instead of printing */
5211 if (heading) { /* If /HEADING print heading */
5212 zfnqfp(s,TMPBUFSIZ,tmpbuf);
5213 fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf);
5216 if (page > -1) /* Paging */
5219 if (!verbose) { /* /BRIEF */
5220 if (outfile[0]) { /* To file */
5223 while (name[0]) { /* One line per file */
5225 if (fs) if (fileselect(name,
5226 dir_aft,dir_bef,dir_naf,dir_nbf,
5227 minsize,maxsize,!backup,16,xlist) < 1) {
5231 fprintf(ofp,"%s\n",name);
5235 fprintf(ofp,"Files: %d\n\n",k);
5239 rc = filhelp(x,"","",n,0);
5242 if (heading && rc > 0)
5243 fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */
5248 ndirs = nfiles = nbytes = 0L; /* Initialize counters */
5250 if (dir_exc) /* Have exception list? */
5251 makelist(dir_exc,xlist,16); /* Yes, convert to array */
5254 znext(name); /* Get next file */
5255 while (name[0]) { /* Loop for each file */
5256 if (fs) if (fileselect(name,
5257 dir_aft,dir_bef,dir_naf,dir_nbf,
5258 minsize,maxsize,!backup,16,xlist) < 1) {
5262 len = zgetfs(name); /* Get file length */
5263 debug(F111,"domydir zgetfs",name,len);
5265 itsadir = zgfs_dir; /* See if it's a directory */
5267 itsadir = (len == -2 || isdir(name));
5268 #endif /* VMSOUNIX */
5269 debug(F111,"domydir itsadir",name,itsadir);
5270 if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
5274 /* Get here when we know we have selected this file */
5277 if (itsadir) { /* Accumulate totals for summary */
5283 if (summary) { /* Summary only, no detail */
5289 debug(F111,"domydir array",name,nfiles);
5291 makestr(&(ap[nmatches]),name);
5298 NOTE: The sprintf's in this routine should be safe. They involve
5299 permission strings, date/time strings, and filenames, all of which have
5300 known maximum lengths; none of these items is input from users. The
5301 destination buffers are large enough to hold maximum sizes for any and
5304 dstr = zfcdat(name); /* Get modification date/time */
5305 debug(F111,"domydir zcfdat",dstr,0);
5306 if (!dstr) dstr = "";
5309 Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings
5310 about possible out-of-bounds dstr[] array refs do not apply. This block of
5311 code is to stifle the warnings and also allows for any out-of-spec
5312 zfcdat() implementations.
5315 char * p = "00000000 00:00:00";
5316 x = ckstrncpy(xbuf,dstr,32);
5317 if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x);
5320 if (engdate) { /* English date requested? */
5321 short month, day, year, hour, minute, seconds;
5322 month = (dstr[4]-48)*10 + (dstr[5]-48);
5323 mstr = (month > 0 && month <= 12) ? months[month-1] : "xxx";
5324 day = (dstr[6]-48)*10 + (dstr[7]-48);
5325 year = (((dstr[0]-48)*10 +
5329 hour = (dstr[9]-48)*10 + (dstr[10]-48);
5330 minute = (dstr[12]-48)*10 + (dstr[13]-48);
5331 seconds = (dstr[15]-48)*10 + (dstr[16]-48);
5332 sprintf(dbuf, /* SAFE */
5333 "%2d-%s-%4d %02d:%02d:%02d",
5334 day,mstr,year,hour,minute,seconds
5337 } else { /* ISO date */
5338 dbuf[0] = dstr[0]; /* yyyy */
5343 dbuf[5] = dstr[4]; /* mm (numeric) */
5346 dbuf[8] = dstr[6]; /* dd */
5348 strcpy(dbuf+10,dstr+8); /* hh:mm:ss */
5351 dlen = strlen(dbuf); /* Length of date */
5352 name[CKMAXPATH] = NUL;
5355 p = ziperm(name); /* Get permissions */
5356 debug(F110,"ziperm perms",p,0);
5359 debug(F110,"zgperm perms",p,0);
5360 #endif /* VMSORUNIX */
5363 debug(F110,"NULL perms",p,0);
5364 #endif /* CK_PERMS */
5367 /* Get relative name to save space -- VMS fullnames are long... */
5368 ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
5371 if (itsadir && len < 0) { /* Directory */
5373 sprintf(linebuf,"%-22s%-10s %s %s",p,"<DIR>",dstr,name);
5376 sprintf(linebuf,"%10s%-10s %s %s",p,"<DIR>",dstr,name);
5378 sprintf(linebuf,"%-10s %s %s", "<DIR>", dstr, name);
5380 } else { /* Regular file */
5382 sprintf(linebuf,"%-22s%10ld %s %s", p, len, dstr, name);
5385 sprintf(linebuf,"%10s%10ld %s %s", p, len, dstr, name);
5387 sprintf(linebuf,"%10ld %s %s", len, dstr, name);
5394 extern char linkname[];
5395 n = strlen(linebuf);
5396 m = strlen(linkname) + n;
5397 if (m < CKMAXPATH + 58)
5398 strcpy(linebuf+n, " -> "); /* safe (checked) */
5399 if (m + 4 < CKMAXPATH - 58)
5400 strcpy(linebuf+n+4, linkname); /* safe (checked) */
5402 #endif /* CKSYMLINK */
5404 if (xfermod) { /* Show transfer mode */
5408 x = scanfile(name,&y,nscanfile);
5410 case FT_TEXT: s = " (T)"; break;
5411 case FT_7BIT: s = " (T)(7BIT)"; break;
5412 case FT_8BIT: s = " (T)(8BIT)"; break;
5414 case FT_UTF8: s = " (T)(UTF8)"; break;
5416 s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)";
5418 #endif /* UNICODE */
5419 case FT_BIN: s = " (B)"; break;
5422 s = binary ? " (B)" : " (T)";
5426 n = strlen(linebuf);
5427 if (n + 4 < CKMAXPATH - 58)
5428 strcpy(linebuf+n, s); /* safe (checked) */
5431 if (msg && dirmsg) {
5433 n = strlen(linebuf);
5434 if (n + dirmsglen + 2 < CKMAXPATH)
5435 sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */
5437 if (xsort) { /* Sorting - save line */
5438 i = strlen(linebuf);
5439 if ((ndirlist >= nx) ||
5440 !(dirlist[ndirlist] = (char *)malloc(i+1))) {
5441 printf("?Memory allocation error - try /NOSORT\n");
5445 strcpy(dirlist[ndirlist],linebuf); /* safe */
5448 znext(name); /* Peek ahead to next file */
5451 fprintf(ofp,"%s\n",linebuf);
5452 if (page && (name[0] || heading)) { /* If /PAGE */
5454 int x = strlen(linebuf);
5456 y = (x % cmd_cols) ? 1 : 0;
5457 n += x / cmd_cols + y;
5462 if (n > (cmd_rows - 3)) { /* Do more-prompting */
5469 #endif /* CK_TTGWSIZ */
5476 makestr(&(ap[0]),ckitoa(nmatches));
5485 case DIRS_NM: skey = dlen + 35; break;
5486 case DIRS_DT: skey = 33; break;
5487 case DIRS_SZ: skey = 21;
5492 case DIRS_NM: skey = dlen + 24; break;
5493 case DIRS_DT: skey = 22; break;
5494 case DIRS_SZ: skey = 10;
5498 case DIRS_NM: skey = dlen + 14; break;
5499 case DIRS_DT: skey = 12; break;
5500 case DIRS_SZ: skey = 0;
5504 sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
5505 for (i = 0; i < ndirlist; i++) {
5506 fprintf(ofp,"%s\n",dirlist[i]);
5507 if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */
5509 int x = strlen(dirlist[i]);
5511 y = (x % cmd_cols) ? 1 : 0;
5512 n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
5517 if (n > (cmd_rows - 3)) { /* Do more-prompting */
5524 #endif /* CK_TTGWSIZ */
5529 if (heading || summary) {
5532 #endif /* CKFLOAT */
5533 fprintf(ofp,"\n%ld director%s, %ld file%s, %ld byte%s",
5535 (ndirs == 1) ? "y" : "ies",
5537 (nfiles == 1) ? "" : "s",
5539 (nbytes == 1) ? "" : "s"
5542 gm = ((CKFLOAT) nbytes ) / 1000000.0;
5544 fprintf(ofp," (%0.2fGB)",(gm / 1000.0));
5545 else if (gm >= 0.01)
5546 fprintf(ofp," (%0.2fMB)",gm);
5547 #endif /* CKFLOAD */
5548 fprintf(ofp,"\n\n");
5551 if (g_matchdot > -1) {
5552 matchdot = g_matchdot; /* Restore these... */
5556 if (ofp != stdout) { /* Close any output file */
5557 if (ofp) fclose(ofp);
5566 dodir(cx) int cx; { /* Do the DIRECTORY command */
5573 #ifdef DOMYDIR /* Builds that domydir() by default */
5574 || (cx == XXDIR || cx == XXLDIR)
5575 #endif /* DOMYDIR */
5577 return(domydir()); /* Built-in directory command */
5579 /* Use the system's directory command. */
5581 msg = (cx == XXLS) ?
5582 "Arguments for ls" :
5583 "Directory and/or file specification";
5584 if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
5587 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy the filespec */
5590 if ((y = cmcfm()) < 0) return(y);
5593 if (!(dc = getenv("CK_DIR")))
5595 ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL);
5596 debug(F110,"DIR",line,0);
5602 concb((char)escape);
5604 return(success = (x < 1) ? 0 : 1);
5610 /* Do the ENABLE and DISABLE commands */
5613 doenable(y,x) int y, x; {
5615 if (isguest) /* IKSD: Don't let guests */
5616 return(0); /* enable anything that's disabled */
5617 #endif /* CK_LOGIN */
5620 en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
5621 en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
5623 en_who = en_mai = en_pri = y;
5624 en_mkd = en_rmd = y;
5628 #endif /* datageneral */
5630 if (!nopush && !inserver)
5634 en_asg = en_que = y;
5641 In Data General AOS/VS Kermit can't log out its superior process.
5644 #endif /* datageneral */
5652 if (inserver && y == 0) {
5658 case EN_DEL: /* Deleting of files */
5708 printf("?Sorry, not valid for guests\n");
5711 #endif /* CK_LOGIN */
5717 printf("?Sorry, not valid for guests\n");
5720 #endif /* CK_LOGIN */
5733 if (((y & 1) && !(en_ena & 1)) ||
5734 ((y & 2) && !(en_ena & 2))) {
5735 printf("?Sorry, DISABLE ENABLE can not be undone\n");
5746 #endif /* NOFRILLS */
5747 #endif /* NOSERVER */
5751 static int del_lis = 0;
5752 static int del_dot = 0;
5753 static int del_hdg = 0;
5754 static int del_pag = -1;
5755 static int del_ask = 0;
5761 extern int optlines;
5762 prtopt(&optlines,"");
5763 prtopt(&optlines,"DELETE");
5765 prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
5770 prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
5773 #endif /* UNIXOROSK */
5775 prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
5779 prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
5784 prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
5787 #endif /* CK_TTGWSIZ */
5788 if (!x) prtopt(&optlines,"(no options set)");
5789 prtopt(&optlines,"");
5796 int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
5800 if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
5807 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5808 printf("?This switch does not take an argument\n");
5811 if (!getval && (cmgkwflgs() & CM_ARG)) {
5812 printf("?This switch requires an argument\n");
5838 #endif /* CK_TTGWSIZ */
5852 printf("?Sorry, this option can not be set\n");
5856 if ((x = cmcfm()) < 0) /* Get confirmation */
5858 if (x_pag > -1) del_pag = x_pag;
5859 if (x_dot > -1) del_dot = x_dot;
5860 if (x_hdg > -1) del_hdg = x_hdg;
5861 if (x_lis > -1) del_lis = x_lis;
5862 if (x_ask > -1) del_ask = x_ask;
5863 return(success = 1);
5867 static char ** xmtchs = NULL;
5868 static int xmtchn = 0;
5872 dodel() { /* DELETE */
5874 int fs = 0; /* Need to call fileselect() */
5877 int getval = 0, asking = 0;
5878 int simulate = 0, rc = 0;
5879 long minsize = -1L, maxsize = -1L;
5880 int havename = 0, confirmed = 0;
5887 int xmode = -1, scan = 0, skip = 0;
5890 #endif /* COMMENT */
5893 char safebuf[CKMAXPATH+1];
5894 struct FDB sw, fi, fl;
5908 for (i = 0; i < 8; i++) dxlist[i] = NULL;
5910 g_matchdot = matchdot;
5912 if (del_lis > -1) x_lis = del_lis;
5913 if (del_dot > -1) matchdot = del_dot;
5914 if (del_hdg > -1) x_hdg = del_hdg;
5915 if (del_pag > -1) xaskmore = del_pag;
5916 if (del_ask > -1) asking = del_ask;
5919 nolinks = 2; /* By default don't follow links */
5921 cmfdbi(&sw, /* First FDB - command switches */
5923 "File specification;\n or switch",
5925 "", /* addtl string data */
5926 ndeltab, /* addtl numeric data 1: tbl size */
5927 4, /* addtl numeric data 2: 4 = cmswi */
5928 xxstring, /* Processing function */
5929 deltab, /* Keyword table */
5930 &fi /* Pointer to next FDB */
5932 cmfdbi(&fl, /* Anything that doesn't match */
5936 "", /* addtl string data */
5937 0, /* addtl numeric data 1 */
5938 0, /* addtl numeric data 2 */
5944 cmfdbi(&fi, /* 2nd FDB - file to delete */
5946 "File(s) to delete", /* hlpmsg */
5947 deldef, /* default */
5948 "", /* addtl string data */
5949 nolinks | deldirs, /* 0 = files, 1 = files or dirs */
5950 0, /* 1 = dirs only */
5955 while (!havename && !confirmed) {
5956 x = cmfdb(&sw); /* Parse something */
5957 if (x < 0) { /* Error */
5960 if (x == -2 || x == -9)
5961 printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
5964 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
5966 c = cmgbrk(); /* Get break character */
5967 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5968 printf("?This switch does not take an argument\n");
5972 if (!getval && (cmgkwflgs() & CM_ARG)) {
5973 printf("?This switch requires an argument\n");
5977 switch (k = cmresult.nresult) {
5983 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
5985 printf("?Date-time required\n");
5994 case DEL_AFT: makestr(&del_aft,s); break;
5995 case DEL_BEF: makestr(&del_bef,s); break;
5996 case DEL_NAF: makestr(&del_naf,s); break;
5997 case DEL_NBF: makestr(&del_nbf,s); break;
6009 deldef = "*.*"; /* UNIX, Windows, OS/2 */
6012 deldef = "+"; /* AOS/VS */
6014 deldef = "*"; /* UNIX, Windows, OS/2, VMS... */
6015 #endif /* datageneral */
6020 recursive = 1; /* Fall through purposely... */
6026 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6028 printf("?Pattern required\n");
6036 makestr(&del_exc,s);
6045 #endif /* RECURSIVE */
6064 #endif /* CK_TTGWSIZ */
6076 if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
6080 switch (cmresult.nresult) {
6081 case DEL_SMA: minsize = y; break;
6082 case DEL_LAR: maxsize = y; break;
6097 extern struct keytab txtbin[];
6099 if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
6101 if (x == 2) { /* ALL */
6103 } else { /* TEXT or BINARY only */
6110 printf("?Not implemented yet - \"%s\"\n",atmbuf);
6114 if (qflag && (cmresult.fcode == _CMFLD)) {
6115 if ((x = cmcfm()) < 0)
6118 return(success = 0);
6120 if (cmresult.fcode != _CMIFI) {
6123 if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
6124 printf("?No files match: %s\n",atmbuf);
6125 else if ((x = zchki(atmbuf)) == -1)
6126 printf("?File not found: %s\n",atmbuf);
6128 printf("?Not a regular file: %s\n",atmbuf);
6130 /* printf("?Not a deletable file: %s\n",atmbuf); */
6133 printf("?A file specification is required\n");
6138 ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
6140 ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH);
6142 len = zgetfs(tmpbuf); /* Is it a directory name? */
6143 argisdir = zgfs_dir; /* Then because of how zxpand() */
6144 if (argisdir && zgfs_link) /* works, we have to add it to */
6145 argisdir = 0; /* the list. */
6149 len = zchki(tmpbuf);
6151 argisdir = isdir(tmpbuf);
6152 #endif /* VMSORUNIX */
6154 debug(F110,"DELETE file",tmpbuf,0);
6155 if ((x = cmcfm()) < 0)
6160 if (inserver && isguest) {
6161 printf("?Sorry, DELETE unavailable to guests\n");
6164 #endif /* CK_LOGIN */
6169 printf("?Sorry, /SIMULATE not implemented on this platform\n");
6172 #endif /* OS2ORUNIX */
6176 if (!iswild(tmpbuf)) {
6182 case -2: m = "Not a regular file"; break;
6183 case -1: m = "File not found or not accessible"; break;
6184 default: m = errno ? ck_errstr() : "Can't delete";
6186 printf("?%s: \"%s\"\n",m,tmpbuf);
6190 #endif /* COMMENT */
6192 makelist(del_exc,dxlist,8);
6194 /* tmpbuf[] has the name - now do any needed conversions on it */
6197 { /* Lower level functions change / to \, not good for CMD.EXE. */
6199 while (*p) { /* Change them back to \ */
6200 if (*p == '/') *p = '\\';
6207 if (iswild(tmpbuf)) {
6209 /* Does not handle '.' as version separator */
6219 if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ);
6221 j = 0; x = 0; /* for end_dot and number of dots */
6223 if (tmpbuf[i] == ';') {
6224 ckstrncat(tmpbuf,"0",TMPBUFSIZ);
6226 if (tmpbuf[i--] == '.')
6228 for (; i >= 0; i--) {
6229 if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
6230 tmpbuf[i] == ']' || tmpbuf[i] == '>')
6232 else if (tmpbuf[i] == '.')
6235 if (tmpbuf[i] != ';') { /* dot may have been used */
6236 if (j) { /* last char is dot */
6237 if (x) /* second is version separator */
6238 ckstrncat(tmpbuf,"0",TMPBUFSIZ);
6240 ckstrncat(tmpbuf,";0",TMPBUFSIZ);
6241 } else if (x == 1) /* lacking a version separator */
6242 ckstrncat(tmpbuf,";0",TMPBUFSIZ);
6243 else if (x == 0) /* x == 2 has a version */
6244 ckstrncat(tmpbuf,".*;0",TMPBUFSIZ);
6247 #endif /* COMMENT */
6251 debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
6253 #ifndef OS2ORUNIX /* No built-in DELETE code... */
6254 /* Construct system command. */
6255 ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL);
6258 if (asking) { /* Maybe overwrite in VMS */
6259 if (x_lis) /* if options are needed... */
6260 ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL);
6262 ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL);
6264 ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL);
6268 debug(F110,"dodel line",line,0);
6269 #endif /* OS2ORUNIX */
6272 success = (zdelet(tmpbuf) == 0);
6274 #else /* !MAC ... */
6289 /* Check whether window size changed */
6290 if (ttgwsiz() > 0) {
6291 if (tt_rows > 0 && tt_cols > 0) {
6297 #endif /* CK_TTGWSIZ */
6299 if (x_hdg > 0 && !summary) {
6300 printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
6304 z = zxrewind(); /* Rewind file list */
6307 nzxopts = ZX_FILONLY;
6308 if (recursive) nzxopts |= ZX_RECURSE;
6309 if (matchdot) nzxopts |= ZX_MATCHDOT;
6311 z = nzxpand(s,nzxopts); /* Expand file list */
6312 #endif /* ZXREWIND */
6313 debug(F111,"dodel",s,z);
6315 /* If deleting directories, sort in reverse order */
6316 /* so we delete the files first, then the directory. */
6319 /* In K95, we have no mtchs array, nor any control over */
6320 /* the order in which znext() returns filenames, so we */
6321 /* must copy the array and sort it. */
6324 if (xmtchs) { /* Free previous list in case */
6325 debug(F101,"dodel freeing previous list","",xmtchn);
6326 for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */
6332 xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */
6334 printf("?Memory allocation failure\n");
6337 for (i = 0; i < z; i++) {
6342 makestr(&(xmtchs[i]),tmpbuf);
6344 printf("?Memory allocation failure\n");
6349 /* debug(F111,"dodel add",xmtchs[i],i); */
6352 debug(F101,"dodel xmtchn","",xmtchn);
6353 sh_sort(xmtchs,NULL,z,0,deldirs,0);
6357 sh_sort(mtchs,NULL,z,0,deldirs,filecase);
6376 ) { /* Loop for all files */
6378 ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ);
6380 znext(tmpbuf); /* Get next file */
6382 if (!*tmpbuf) { /* No more */
6383 if (deldirs && recursive && argisdir) {
6384 ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ);
6385 argisdir = 0; /* (only do this once) */
6392 if (fileselect(tmpbuf,
6393 del_aft,del_bef,del_naf,del_nbf,
6394 minsize,maxsize,0,8,dxlist) < 1) {
6398 if (!skip && scan && itsadir) {
6401 if (!skip && scan) {
6402 switch (scanfile(tmpbuf,&y,nscanfile)) {
6413 #endif /* UNICODE */
6418 if (!skip && asking) {
6420 ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL);
6421 x = getyesno(line,3);
6423 case 0: continue; /* no */
6424 case 1: break; /* yes */
6425 case 2: goto xdelete; /* quit */
6426 case 3: asking = 0; break; /* go */
6430 len = zgetfs(tmpbuf); /* Get length and accessibility */
6432 if (itsadir && zgfs_link) { /* Treat links to directories */
6433 itsadir = 0; /* as regular files */
6434 if (scan) /* But not if /TYPE: was given */
6437 if (itsadir) /* (emulate non-Unix code) */
6440 len = zchki(tmpbuf); /* Get accessibility */
6441 if (len < 0) /* See if it's a directory */
6442 itsadir = isdir(tmpbuf);
6443 #endif /* VMSORUNIX */
6446 #ifdef COMMENT /* Too verbose */
6449 printf(" %s (SKIPPED)\n",tmpbuf);
6451 if (++n > cmd_rows - 3)
6452 if (!askmore()) goto xdelete; else n = 0;
6453 #endif /* CK_TTGWSIZ */
6455 #endif /* COMMENT */
6459 debug(F111,"DELETE len",tmpbuf,len);
6465 printf(" %s (SELECTED)\n",tmpbuf);
6466 if (++n > cmd_rows - 3) {
6469 if (!xx) goto xdelete; else n = 0;
6472 } else if (len >= 0 || !itsadir) { /* Regular file */
6473 zdelet(tmpbuf); /* or symlink, etc... */
6474 if (zchki(tmpbuf) < 0) {
6479 printf(" %s (OK)\n",tmpbuf);
6480 if (++n > cmd_rows - 3)
6481 if (!askmore()) goto xdelete; else n = 0;
6488 printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr());
6489 if (++n > cmd_rows - 3)
6490 if (!askmore()) goto xdelete; else n = 0;
6493 } else if (/* pass > 0 && */ deldirs && itsadir) {
6494 /* It's a directory */
6495 if (zrmdir(tmpbuf) > -1) { /* Only works if empty */
6499 printf(" %s (OK)\n",tmpbuf);
6500 if (++n > cmd_rows - 3)
6501 if (!askmore()) goto xdelete; else n = 0;
6507 printf(" %s (FAILED: %s)\n",
6510 if (++n > cmd_rows - 3)
6511 if (!askmore()) goto xdelete; else n = 0;
6514 } else if (x_lis > 0) {
6517 printf(" %s (FAILED: directory)\n",tmpbuf);
6519 printf(" %s (FAILED: not a regular file)\n",tmpbuf);
6520 if (++n > cmd_rows - 3)
6521 if (!askmore()) goto xdelete; else n = 0;
6527 if (++n > cmd_rows - 3)
6528 if (!askmore()) goto xdelete; else n = 0;
6529 printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
6531 count != 1 ? "s" : "",
6532 simulate ? "would be " : "",
6534 filespace != 1 ? "s" : "",
6535 simulate ? "would be " : "",
6536 simulate ? " (maybe)" : ""
6539 if (!x_lis && !success && !quiet) {
6540 printf("?DELETE failed for %d file%s \
6541 (use DELETE /LIST to see details)\n",
6542 bad, bad == 1 ? "" : "s"
6545 } else if (x_lis > 0) {
6547 printf("?%s: %s\n",ck_errstr(), tmpbuf);
6549 printf("?Can't delete: %s\n",tmpbuf);
6552 #else /* OS2ORUNIX */
6553 #ifndef VMS /* Others - let the system do it. */
6555 x = nzxpand(tmpbuf,nzxopts);
6556 success = (x > 0) ? 0 : 1;
6558 printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
6562 x = xsystem(line); /* zshcmd returns 1 for success */
6563 success = (x > 0) ? 1 : 0;
6564 if (x_hdg > 0 && !asking)
6565 printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
6566 concb((char)escape);
6568 #endif /* OS2ORUNIX */
6571 if (g_matchdot > -1) {
6572 matchdot = g_matchdot; /* Restore these... */
6578 debug(F101,"dodel freeing list","",xmtchn);
6579 for (i = 0; i < xmtchn; i++)
6580 if (xmtchs[i]) free(xmtchs[i]);
6586 debug(F101,"dodel result","",rc);
6587 return((rc < 0) ? rc : success);
6589 #endif /* NOFRILLS */
6591 #ifndef NOSPL /* The ELSE command */
6592 _PROTOTYP( VOID pushqcmd, (char *) );
6596 if (!ifcmd[cmdlvl]) {
6597 printf("?ELSE doesn't follow IF\n");
6602 Wrong. This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
6606 #endif /* COMMENT */
6607 if (!iftest[cmdlvl]) { /* If IF was false do ELSE part */
6608 if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
6609 debug(F100,"doelse pushing","",0);
6611 pushcmd(NULL); /* save rest of command. */
6613 /* This fixes certain obscure problems */
6614 /* but breaks many other constructions that must work. */
6616 #endif /* COMMENT */
6617 } else { /* If interactive, */
6618 cmini(ckxech); /* just start a new command */
6619 printf("\n"); /* (like in MS-DOS Kermit) */
6620 if (pflag) prompt(xxstring);
6622 } else { /* Condition is false */
6623 if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
6624 return(y); /* Gobble up rest of line */
6633 char *lp, *ap; /* Macro argument pointer */
6634 int len = 0, x, y, pp = 0;
6637 /* Get variable name */
6644 y = cmfld("Variable name","",&s,xxstring);
6645 debug(F111,"doswitch cmfld",s,y);
6647 if (y == -3) /* Because brstrip() writes */
6648 s = brbuf; /* into its argument. */
6652 debug(F110,"doswitch A",s,0);
6653 if (!strcmp(s,"(")) {
6655 if ((y = cmfld("Variable name","",&s,xxstring)) < 0) {
6660 debug(F110,"doswitch B",s,0);
6663 len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
6664 if (tmpbuf[0] == CMDQ) {
6665 if (chkvar(s) < 1) {
6666 printf("?Variable name required\n");
6670 if (pp > 0) { /* If open paren given parse closing */
6671 if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
6673 if (strcmp(atmbuf,")")) {
6674 printf("?Closing parenthesis required\n");
6679 x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */
6682 debug(F010,"SWITCH a",line,0);
6685 x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */
6687 { /* variable name + SP */
6690 if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') {
6691 tmpbuf[len-1] = NUL;
6695 x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," ");
6697 #endif /* COMMENT */
6698 debug(F010,"SWITCH b",line,0);
6703 if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
6704 if ((y = (int)strlen(s)) < 1) return(-2);
6705 if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
6706 ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
6709 if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
6710 printf("?Unbalanced braces\n");
6713 debug(F010,"SWITCH c",line,0);
6715 x = mlook(mactab,"_switx",nmac); /* Look up SWITCH macro definition */
6716 if (x < 0) { /* Not there? */
6717 addmmac("_switx",sw_def); /* Put it back. */
6718 if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
6719 printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
6720 return(success = 0);
6723 debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */
6724 success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC);
6725 debug(F101,"SWITCH status","",success);
6730 dofor() { /* The FOR command. */
6731 int i, fx, fy, fz; /* loop variables */
6732 char *ap, *di; /* macro argument pointer */
6733 int pp = 0; /* Paren level */
6736 for (i = 0; i < 2; i++) {
6737 if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
6739 printf("?Variable name required\n");
6749 if ((y = parsevar(s,&x,&z)) < 0) /* Check variable. */
6752 if (*s == CMDQ) /* If loop variable starts with */
6753 mustquote++; /* backslash, mustquote is > 0. */
6754 #endif /* COMMENT */
6756 lp = line; /* Build a copy of the command */
6757 ckstrncpy(lp,"_forx ",LINBUFSIZ);
6758 lp += (int)strlen(line); /* "_for" macro. */
6759 ap = lp; /* Save pointer to macro args. */
6761 if (*s == CMDQ) s++; /* Skip past backslash if any. */
6762 while ((*lp++ = *s++)) ; /* copy it */
6763 lp--; *lp++ = SP; /* add a space */
6765 if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
6766 if (y == -3) return(-2);
6769 debug(F101,"dofor fx","",fx);
6770 s = atmbuf; /* Copy the atom buffer */
6772 if ((int)strlen(s) < 1) goto badfor;
6774 In edit 192, we change the loop variables to be evaluated at loop entry,
6775 not each time through the loop. This was required in order to allow
6776 \v(argc) to be used as a loop variable, or in a loop-variable expression.
6777 Thus, we can't have FOR loops that modify their own exit conditions by
6778 changing the final value or the increment. The problem with \v(argc) was
6779 that it is on the macro stack; after entry into the _forx macro, it is at
6782 sprintf(tmpbuf,"%d",fx); /* (SAFE) Substitute actual value */
6784 while ((*lp++ = *s++)) ; /* (what they actually typed) */
6788 debug(F110,"FOR A",line,0);
6791 if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
6792 if (y == -3) return(-2);
6795 debug(F101,"dofor fy","",fy);
6796 s = atmbuf; /* Same deal */
6797 if ((int)strlen(s) < 1)
6800 sprintf(tmpbuf,"%d",fy); /* SAFE */
6802 while ((*lp++ = *s++)) ;
6807 debug(F110,"FOR B",line,0);
6810 x_ifnum = 1; /* Increment or parenthesis */
6811 di = (fx < fy) ? "1" : "-1"; /* Default increment */
6812 if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
6813 debug(F111,"dofor increment",atmbuf,y);
6815 if (y == -3) { /* Premature termination */
6817 } else if (y == -2) { /* Maybe closing paren */
6818 if (!strcmp(atmbuf,")")) {
6819 pp--; /* Count it */
6820 s = di; /* supply default interval */
6822 } else /* Not closing paren, invalid */
6824 } else /* Other error */
6826 } else { /* Number */
6828 debug(F101,"dofor fz","",fz);
6829 s = atmbuf; /* Use it */
6831 if ((int)strlen(s) < 1)
6834 sprintf(tmpbuf,"%d",fz); /* (SAFE) Same deal */
6836 while ((*lp++ = *s++)) ;
6841 debug(F110,"FOR C",line,0);
6844 /* Insert the appropriate comparison operator */
6853 debug(F110,"FOR D",line,0);
6856 if (pp > 0) { /* If open paren given parse closing */
6857 if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
6859 if (strcmp(atmbuf,")")) {
6860 printf("?Closing parenthesis required\n");
6864 if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
6865 if ((y = (int)strlen(s)) < 1) return(-2);
6866 if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
6867 ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
6870 if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
6871 printf("?Unbalanced braces\n");
6876 debug(F110,"FOR E",line,0);
6882 printf("?Zero increment not allowed\n");
6885 #endif /* COMMENT */
6887 In version 8.0 we decided to allow macro names anyplace a numeric-valed
6888 variable could appear. But this caused trouble for the FOR loops because
6889 the quoting in for_def[] assumed a \%i-style loop variable. We account
6890 for this here in the if (mustquote)...else logic by invoking separate
6891 FOR macro definitions in the two cases.
6893 if (mustquote) { /* \%i-style loop variable */
6894 x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */
6895 if (x < 0) { /* Not there? */
6896 addmmac("_forx",for_def); /* Put it back. */
6897 if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
6898 printf("?FOR macro definition gone!\n");
6899 return(success = 0);
6902 } else { /* Loop variable is a macro */
6903 x = mlook(mactab,"_forz",nmac);
6905 addmmac("_forz",foz_def);
6906 if ((x = mlook(mactab,"_forz",nmac)) < 0) {
6907 printf("?FOR macro definition gone!\n");
6908 return(success = 0);
6912 debug(F010,"FOR command",line,0); /* Execute the FOR macro. */
6913 return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
6916 printf("?Incomplete FOR command\n");
6922 /* Do the BUG command */
6928 extern char * k_info_dir;
6934 printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
6935 #endif /* COMMENT */
6937 "\nBefore requesting technical support from Columbia U., please consult:\n\n"
6941 printf(" . Your \"Kermit 95\" user manual (use the MANUAL command).\n");
6942 printf(" . The technical reference manual, \"Using C-Kermit\".\n");
6945 printf(" . The book \"Using C-Kermit\" (type HELP for more info).\n");
6949 printf(" . Your own organization's support staff, if any.\n");
6951 " . The comp.protocols.kermit.misc newsgroup.\n");
6953 " . The Kermit support website, http://www.columbia.edu/kermit/support.html \n"
6957 " . The Kermit FAQ, http://www.columbia.edu/kermit/newfaq.html \n");
6960 " . The Kermit 95 FAQ, http://www.columbia.edu/kermit/k95faq.html \n");
6965 " . The C-Kermit FAQ, http://www.columbia.edu/kermit/ckfaq.html \n");
6967 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6969 If you still need help or have a bug to report after consulting these sources,"
6971 printf("\nsend e-mail to:\n\n");
6973 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6974 printf(" mailto:kermit-support@columbia.edu\n\n");
6976 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6977 printf("Or contact us by post:\n\n");
6979 " Kermit, Columbia University, 612 W 115 Street, New York NY 10025, USA\n\n"
6982 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6983 printf("Or by fax at +1 (212) 662-6442.\n\n");
6985 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6987 printf("Telephone support is available too:\n\n");
6989 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6991 " +1 (212) 854-5126, from anywhere, $25.00 USD per call, MC/Visa\n\n");
6993 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6994 #endif /* COMMENT */
6998 "Before reporting problems, please use the SHOW FEATURES command\n");
6999 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
7001 "to get detailed program version and configuration information.\n\n");
7002 #endif /* NOFRILLS */
7006 #endif /* NOFRILLS */
7010 /* T O D 2 S E C -- Convert time of day as hh:mm:ss to secs since midnite */
7012 Call with a string hh:mm or hh:mm:ss.
7013 Returns a 0 to 86400 on success, or a negative number on failure.
7016 tod2sec(t) char * t; {
7018 long hh = 0L, mm = 0L, ss = 0L;
7023 debug(F110,"tod2sec",t,0);
7025 if (isdigit(*t)) /* Get hours from argument */
7030 hh = hh * 10 + *t++ - '0';
7034 #endif /* COMMENT */
7042 if (isdigit(*t)) /* Minutes */
7047 mm = mm * 10 + *t++ - '0';
7057 if (isdigit(*t)) /* Seconds */
7062 ss = ss * 10 + *t++ - '0';
7066 if (*t > 32) /* No trailing junk allowed */
7071 t2 = hh * 3600L + mm * 60L + ss; /* Seconds since midnight from arg */
7072 debug(F101,"tod2sec t2","",t2);
7077 int waitinterval = 1;
7081 #endif /* OLDWAIT */
7086 dopaus(cx) int cx; {
7088 extern int sleepcan;
7092 x_ifnum = 1; /* Turn off internal complaints */
7094 y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
7095 else if (cx == XXPAU)
7096 y = cmnum("seconds to pause, or time of day hh:mm:ss",
7097 "1",10,&x,xxstring);
7099 y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
7100 "100",10,&x,xxstring);
7103 if (y == -2) { /* Invalid number or expression */
7104 char *p = tmpbuf; /* Retrieve string from atmbuf */
7107 zzstring(atmbuf,&p,&n); /* Evaluate in case it's a variable */
7108 zz = tod2sec(tmpbuf); /* Convert to secs since midnight */
7110 printf("?Number, expression, or time of day required\n");
7113 char now[32]; /* Current time */
7118 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
7119 if (zz < tnow) /* User's time before now */
7120 zz += 86400L; /* So make it tomorrow */
7121 zz -= tnow; /* Seconds from now. */
7128 case XXPAU: /* PAUSE */
7129 case XXMSL: /* MSLEEP */
7130 if ((y = cmcfm()) < 0) return(y);
7132 case XXWAI: /* WAIT */
7133 z = 0; /* Modem signal mask */
7134 while (1) { /* Read zero or more signal names */
7135 y = cmkey(mstab,nms,"modem signal","",xxstring);
7136 if (y == -3) break; /* -3 means they typed CR */
7137 if (y < 0) return(y); /* Other negatives are errors */
7138 z |= y; /* OR the bit into the signal mask */
7140 if ((y = cmcfm()) < 0) return(y);
7143 default: /* Shouldn't happen */
7147 /* Command is entered, now do it. */
7149 if (zz > -1L) { /* Time of day given? */
7151 if (zz != (long) x) {
7153 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
7158 if (cx == XXMSL) { /* Millisecond sleep */
7159 msleep(zz < 0 ? x : x * 1000);
7160 return(success = 1);
7162 if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
7164 return(success = 1);
7167 /* WAIT, or else SLEEP with cancellation allowed... */
7169 do { /* Sleep loop */
7171 if (sleepcan) { /* Keyboard cancellation allowed? */
7172 if (y = conchk()) { /* Did they type something? */
7174 while (y--) coninc(0); /* Yes, gobble it all up */
7176 /* There is a debate over whether PAUSE should absorb */
7177 /* its cancelling character(s). There are several */
7178 /* reasons why it should gobble at least one character: */
7179 /* (1) MS-DOS Kermit does it */
7180 /* (2) if not, subsequent PAUSE commands will terminate */
7182 /* (3) if not, subsequent ASK commands will use it as */
7183 /* valid input. If \13, then it will get no input */
7184 /* (4) if not, then the character appears on the command */
7185 /* line after all enclosing macros are complete. */
7186 kbchar = coninc(0); /* Gobble one up */
7187 #endif /* COMMENT */
7188 break; /* And quit PAUSing or WAITing */
7191 if (cx == XXWAI) { /* WAIT (z == modem signal mask) */
7192 debug(F101,"WAIT x","",x);
7193 if (z > 0) { /* Looking for any modem signals? */
7194 mdmsig = ttgmdm(); /* Yes, get them */
7195 if (mdmsig < 0) /* Failed */
7196 return(success = 0);
7197 if ((mdmsig & z) == z) /* Got what we wanted? */
7198 return(success = 1); /* Succeed */
7200 if (x == 0) /* WAIT 0 and didn't get our signals */
7203 sleep(1); /* No interrupt, sleep one second */
7206 if (cx == XXWAI) /* If WAIT and loop exhausted */
7207 success = (z == 0); /* Fail. */
7209 success = (x == 0); /* Set SUCCESS/FAILURE for PAUSE. */
7212 #else /* New code uses chained FDBs and allows FILE waits... */
7214 char * m = ""; /* Help message */
7215 struct FDB nu, fl; /* Parse function descriptor blocks */
7217 int mdmsig = 0, fs = 0;
7223 case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
7224 case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
7225 case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
7229 _CMNUM, /* Number */
7230 m, /* Help message */
7231 (cx == XXMSL) ? "100" : "1", /* Default */
7235 xxstring, /* Processing function */
7239 cmfdbi(&fl, /* Time of day */
7243 "", /* addtl string data */
7244 0, /* addtl numeric data 1 */
7245 0, /* addtl numeric data 2 */
7246 xxstring, /* processing func */
7250 x = cmfdb(&nu); /* Parse a number or a field */
7256 switch (cmresult.fcode) {
7257 case _CMNUM: /* Number */
7258 x = cmresult.nresult;
7260 case _CMFLD: /* Field */
7261 zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */
7263 printf("?Number, expression, or time of day required\n");
7266 char now[32]; /* Current time */
7271 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
7272 if (zz < tnow) /* User's time before now */
7273 zz += 86400L; /* So make it tomorrow */
7274 zz -= tnow; /* Seconds from now. */
7277 debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
7279 case XXPAU: /* PAUSE */
7280 case XXMSL: /* MSLEEP */
7281 if ((y = cmcfm()) < 0) return(y);
7283 case XXWAI: /* WAIT */
7284 z = 0; /* Modem signal mask */
7285 y = cmkey(waittab,nwaittab,"","",xxstring);
7288 if ((y = cmcfm()) < 0)
7294 if (y == WAIT_FIL) { /* FILE */
7296 if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
7299 if (filewait == WF_MOD || filewait == WF_DEL)
7300 z = cmifi("Filename","",&s,&wild,xxstring);
7302 z = cmfld("Filename","",&s,xxstring);
7305 if (wild || ((filewait == WF_CRE) && iswild(s))) {
7306 printf("?Wildcards not valid here\n");
7309 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
7310 if ((z = cmcfm()) < 0)
7313 } else if (y != WAIT_MDM) { /* A modem signal */
7314 z |= y; /* OR the bit into the signal mask */
7316 if (!filewait) { /* Modem signals... */
7317 while (1) { /* Get zero or more signal names */
7318 y = cmkey(mstab,nms,"modem signal","",xxstring);
7319 if (y == -3) break; /* -3 means they typed CR */
7320 if (y < 0) return(y); /* Other negatives are errors */
7321 z |= y; /* OR the bit into the signal mask */
7323 if ((y = cmcfm()) < 0) return(y);
7327 default: /* Shouldn't happen */
7331 /* Command is entered, now do it. */
7333 if (zz > -1L) { /* Time of day given? */
7335 if (zz != (long) x) {
7337 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
7343 concb((char)escape); /* Ensure single-char wakeup */
7345 if (cx == XXMSL) { /* Millisecond sleep */
7346 msleep(zz < 0 ? x : x * 1000);
7347 return(success = 1);
7349 if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
7351 return(success = 1);
7353 if (filewait) { /* FILE... */
7354 fs = zchki(tmpbuf); /* Check if file exists */
7358 return(success = 1);
7362 printf("?File does not exit: %s\n",tmpbuf);
7365 s = zfcdat(tmpbuf); /* Get current modification date */
7367 if (ckstrncpy(filedate,s,32) != 17) {
7368 printf("?Can't get modification time: %s\n",tmpbuf);
7374 return(success = 1);
7378 do { /* Polling loop */
7379 if (sleepcan) { /* Keyboard cancellation allowed? */
7380 if ((y = conchk()) > 0) { /* Did they type something? */
7381 kbchar = coninc(0); /* Yes, get first char they typed */
7382 debug(F000,"WAIT kbchar","",kbchar);
7384 while (--y > 0) /* Gobble the rest up */
7386 #endif /* COMMENT */
7387 return(success = 0); /* And quit PAUSing or WAITing */
7390 if (filewait == 0) {
7391 if (cx == XXWAI) { /* WAIT for modem signals */
7393 mdmsig = ttgmdm(); /* Get them. */
7394 debug(F101,"WAIT ttgmdm","",mdmsig);
7395 if (mdmsig < 0) /* Failure to get them? */
7396 return(success = 0); /* Fail. */
7397 if ((mdmsig & z) == z) /* Got desired ones? */
7398 return(success = 1); /* Succeed. */
7400 return(success = 0);
7402 } else { /* FILE... */
7403 fs = zchki(tmpbuf); /* Get file status */
7404 if (filewait == WF_MOD) { /* Wait for modification */
7405 if (fs == -1) /* Failure to get status */
7406 return(success = 0); /* so WAIT fails. */
7407 s = zfcdat(tmpbuf); /* Get current modification time */
7408 if (!s) s = ""; /* And compare with the time */
7409 if (strcmp(s,filedate)) /* when the WAIT started */
7410 return(success = 1);
7411 } else if (filewait == WF_DEL) { /* Wait for deletion */
7412 if (fs == -1) /* If file doesn't exist, */
7413 return(success = 1); /* succeed. */
7414 } else if (filewait == WF_CRE) { /* Wait for creation */
7415 if (fs != -1) /* If file exists */
7416 return(success = 1); /* succeed. */
7419 if (x < 1) /* SLEEP/WAIT/PAUSE 0 */
7421 sleep(waitinterval); /* No interrupt, sleep */
7422 x -= waitinterval; /* Deduct sleep time */
7425 if (cx == XXWAI) /* WAIT time expired */
7426 success = (z == 0); /* Succeed if no modem signals */
7427 else /* For SLEEP or PAUSE, success */
7428 success = (x == 0); /* depends on whether it was */
7429 return(success); /* interrupted from the keyboard. */
7430 #endif /* OLDWAIT */
7435 _PROTOTYP(int zcmpfn,(char *, char *));
7436 #endif /* OS2ORUNIX */
7442 /* Parse a file or a directory name */
7443 int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
7446 cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
7448 "Filename or switch", /* hlpmsg */
7450 "", /* addtl string data */
7451 nqvswtab, /* addtl numeric data 1: tbl size */
7452 4, /* addtl numeric data 2: 4 = cmswi */
7453 xxstring, /* Processing function */
7454 qvswtab, /* Keyword table */
7455 &fi /* Pointer to next FDB */
7458 cmfdbi(&fi, /* 1st FDB - file to type */
7462 "", /* addtl string data */
7463 3, /* addtl numeric data 1 */
7464 0, /* addtl numeric data 2 */
7471 x = cmfdb(&sw); /* Parse something */
7472 if (x < 0) /* Error */
7474 switch (cmresult.fcode) {
7476 switch (cmresult.nresult) {
7488 s = cmresult.sresult;
7495 wild = cmresult.nresult; /* Source specification wild? */
7497 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
7501 wild = iswild(line);
7503 p = tmpbuf; /* Place for new name */
7504 if ((x = cmofi(wild ? "Target directory" : "New name",
7505 "",&s,xxstring)) < 0) { /* Get new name */
7507 printf("?%s required\n", wild ? "Target directory" : "New name");
7511 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
7512 if ((y = cmcfm()) < 0) return(y);
7514 if (!wild) { /* Just one */
7515 if (listing) printf("%s => %s ",line,p);
7516 if (zlink(line,p) < 0) {
7517 if (listing) printf("(FAILED: %s\n",ck_errstr());
7520 if (listing) printf("(OK)\n");
7522 return(success = rc);
7524 if (!isdir(p)) { /* Multiple */
7525 printf( /* if target is not a directory */
7526 "?Multiple source files not allowed if target is not a directory.\n");
7530 else { /* Show full path of target */
7531 char buf[CKMAXPATH]; /* (too much) */
7532 if (zfnqfp(p,CKMAXPATH,buf))
7533 ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
7535 #endif /* COMMENT */
7538 conres(); /* Let Ctrl-C work. */
7540 debug(F110,"dolink line",line,0);
7543 z = zxrewind(); /* Rewind file list */
7545 z = nzxpand(s,0); /* Expand file list */
7546 #endif /* ZXREWIND */
7547 debug(F111,"dolink p",p,z);
7551 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
7555 if (!(z == 0 && !wild))
7559 if (listing) printf("%s => %s ",line,p);
7560 if (zlink(line,p) < 0) {
7561 if (listing) printf("(FAILED: %s\n",ck_errstr());
7564 if (listing) printf("(OK)\n");
7568 concb((char)escape);
7570 return(success = rc);
7577 int i, x, listing = 0, nolist = 0, havename = 0;
7579 int targetisdir = 0;
7588 cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
7590 "Filename or switch", /* hlpmsg */
7592 "", /* addtl string data */
7593 ncopytab, /* addtl numeric data 1: tbl size */
7594 4, /* addtl numeric data 2: 4 = cmswi */
7595 xxstring, /* Processing function */
7596 copytab, /* Keyword table */
7597 &fi /* Pointer to next FDB */
7599 cmfdbi(&fi, /* 1st FDB - file to type */
7603 "", /* addtl string data */
7604 0, /* addtl numeric data 1 */
7605 0, /* addtl numeric data 2 */
7612 x = cmfdb(&sw); /* Parse something */
7613 if (x < 0) /* Error */
7615 switch (cmresult.fcode) {
7617 switch (cmresult.nresult) {
7645 s = cmresult.sresult;
7652 wild = cmresult.nresult;
7653 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
7655 p = tmpbuf; /* Place for new name */
7657 /* Get destination name */
7658 if ((x = cmofi("destination name and/or directory",
7664 ,&s,xxstring)) < 0) {
7666 printf("?Name for destination file required\n");
7670 ckstrncpy(p,s,TMPBUFSIZ); /* Safe copy of destination name */
7671 if ((y = cmcfm()) < 0) return(y);
7672 if (appending && swapping) {
7673 printf("?Sorry, /APPEND and /SWAP conflict\n");
7678 This unreasonably prevented "COPY /APPEND *.* bifile" from concatenating
7679 a bunch of files into one big file.
7681 if (appending && wild) {
7682 printf("?Sorry, /APPEND can be used only with single files\n");
7685 #endif /* COMMENT */
7686 targetisdir = isdir(p);
7690 if (p[x-1] != '/') {
7691 ckstrncat(p,"/",TMPBUFSIZ);
7696 if (p[x-1] != '/') {
7697 ckstrncat(p,"/",TMPBUFSIZ);
7702 if (p[x-1] != '>') {
7703 ckstrncat(p,">",TMPBUFSIZ);
7708 if (p[x-1] != ':') {
7709 ckstrncat(p,":",TMPBUFSIZ);
7713 if (p[x-1] != '/') {
7714 ckstrncat(p,"/",TMPBUFSIZ);
7717 #endif /* datageneral */
7718 #endif /* STRATUS */
7720 #endif /* UNIXOROSK */
7724 if (!appending) { /* If /APPEND not given */
7725 if (wild && !targetisdir) { /* No wildcards allowed */
7726 printf( /* if target is not a directory */
7727 "?Multiple source files not allowed if target is not a directory.\n");
7733 conres(); /* Let Ctrl-C work. */
7735 debug(F110,"docopy line",line,0);
7736 debug(F110,"docopy p",p,0);
7739 z = zxrewind(); /* Rewind file list */
7741 z = nzxpand(s,0); /* Expand file list */
7742 #endif /* ZXREWIND */
7746 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
7750 if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */
7751 if (inserver && (!ENABLED(en_del)
7754 #endif /* CK_LOGIN */
7756 printf("?Sorry, overwriting existing files is disabled\n");
7762 if (tob64 && fromb64) { /* To and from B64 = no conversion */
7766 debug(F110,"COPY dest",p,0);
7774 errno = 0; /* Reset errno */
7776 if (listing) printf("%s => %s ",line,p);
7779 if (!swapping && !appending && !fromb64 && !tob64) {
7780 debug(F110,"COPY zcopy",line,0);
7782 if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
7786 printf("(FAILED: Not a regular file)\n");
7788 printf("?Not a regular file - %s\n",line);
7793 printf("(FAILED: Not found or not accessible)\n");
7795 printf("?Not found or not accessible - %s\n",line);
7800 printf("(FAILED: Permission denied)\n");
7802 printf("?Permission denied - %s\n",line);
7807 printf("(Source and destination are the same file)\n");
7810 "?Source and destination are the same file - %s\n",
7816 printf("(FAILED: Input/Output error)\n");
7818 printf("?Input/Output error - %s\n",line);
7823 printf("(FAILED: %s - %s)\n",p,ck_errstr());
7825 printf("?%s - %s\n",ck_errstr(),p);
7830 printf("(FAILED: %s)\n",ck_errstr());
7832 printf("?%s\n",ck_errstr());
7836 if (listing) printf("(OK)\n");
7839 } else { /* Special options */
7841 int prev, y, x = 0; /* Variables needed for them */
7848 if ((in = fopen(line,"r")) == NULL) { /* Open input file */
7850 printf("(FAILED: %s)\n",ck_errstr());
7852 printf("?%s - %s)\n",ck_errstr(),line);
7856 if (targetisdir) { /* Target is directory */
7857 char * buf = NULL; /* so append this filename to it */
7861 ckstrncat(p,buf,TMPBUFSIZ);
7864 if (zcmpfn(line,p)) { /* Input and output are same file? */
7866 printf("(FAILED: Source and destination identical)\n");
7868 printf("?Source and destination identical - %s\n", line);
7872 #endif /* OS2ORUNIX */
7873 if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
7876 printf("(FAILED: %s - %s)\n",p,ck_errstr());
7878 printf("?%s - %s\n",p,ck_errstr());
7883 if (tob64) { /* Converting to Base-64 */
7885 debug(F110,"COPY tob64",line,0);
7887 while (1) { /* Loop... */
7889 if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */
7896 printf("(FAILED: Phase error at %d)\n",prev);
7898 printf("?Phase error at %d\n",prev);
7905 printf("(FAILED: Swap error)\n");
7907 printf("?Swap error\n");
7911 for (i = 0; i < x; i+=2) {
7913 ibuf[i] = ibuf[i+1];
7917 if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
7919 printf("(FAILED: Encoding error)\n");
7921 printf("?Encoding error\n");
7925 fprintf(out,"%s\n",obuf);
7928 } else if (fromb64) { /* Converting from Base 64 */
7930 debug(F110,"COPY fromb64",line,0);
7932 if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
7935 printf("(FAILED: %s - %s)\n",p,ck_errstr());
7937 printf("?%s - %s\n",p,ck_errstr());
7943 x = fread(ibuf,1,80,in);
7944 if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
7946 printf("(FAILED: Decoding error)\n");
7948 printf("?Decoding error\n");
7955 printf("(FAILED: Swap error)\n");
7957 printf("?Swap error\n");
7961 for (i = 0; i < y; i+=2) {
7963 obuf[i] = obuf[i+1];
7968 if (fwrite(obuf,1,y,out) < 1) {
7970 printf("(FAILED: %s - %s)\n",p,ck_errstr());
7972 printf("?%s - %s\n",p,ck_errstr());
7982 if (swapping) { /* Swapping bytes */
7987 debug(F110,"COPY swapping",line,0);
7990 x = fread((char *)c,1,2,in);
7995 } else if (x == 1) {
7999 "(WARNING: Odd byte count)");
8000 if (!listing) printf("\n");
8002 if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
8004 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8006 printf("?%s - %s\n",p,ck_errstr());
8012 } else if (appending) { /* Appending to target file */
8016 debug(F110,"COPY appending",line,0);
8019 x = fread(&c,1,1,in);
8025 if (fwrite(&c,1,1,out) < 1) {
8027 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8029 printf("?%s - %s\n",p,ck_errstr());
8035 if (out) fclose(out);
8039 concb((char)escape);
8040 #endif /* VMSORUNIX */
8042 if (rc > -1) success = rc;
8046 #endif /* NOFRILLS */
8053 /* Parse a file or a directory name */
8054 int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
8058 cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
8060 "Filename or switch", /* hlpmsg */
8062 "", /* addtl string data */
8063 nqvswtab, /* addtl numeric data 1: tbl size */
8064 4, /* addtl numeric data 2: 4 = cmswi */
8065 xxstring, /* Processing function */
8066 qvswtab, /* Keyword table */
8067 &fi /* Pointer to next FDB */
8070 cmfdbi(&fi, /* 1st FDB - file to type */
8074 "", /* addtl string data */
8075 3, /* addtl numeric data 1 */
8076 0, /* addtl numeric data 2 */
8083 x = cmfdb(&sw); /* Parse something */
8084 if (x < 0) /* Error */
8086 switch (cmresult.fcode) {
8088 switch (cmresult.nresult) {
8101 s = cmresult.sresult;
8108 wild = cmresult.nresult; /* Source specification wild? */
8110 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
8114 wild = iswild(line);
8116 p = tmpbuf; /* Place for new name */
8117 if ((x = cmofi(wild ? "Target directory" : "New name",
8118 "",&s,xxstring)) < 0) { /* Get new name */
8120 printf("?%s required\n", wild ? "Target directory" : "New name");
8124 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
8125 if ((y = cmcfm()) < 0) return(y);
8127 if (!wild) { /* Just one */
8128 if (listing) printf("%s => %s ",line,p);
8129 if (zrename(line,p) < 0) {
8131 printf("(FAILED: %s)\n",ck_errstr());
8133 printf("?%s\n",ck_errstr());
8136 if (listing) printf("(OK)\n");
8138 return(success = rc);
8140 if (!isdir(p)) { /* Multiple */
8141 printf( /* if target is not a directory */
8142 "?Multiple source files not allowed if target is not a directory.\n");
8146 else { /* Show full path of target */
8147 char buf[CKMAXPATH]; /* (too much) */
8148 if (zfnqfp(p,CKMAXPATH,buf))
8149 ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
8151 #endif /* COMMENT */
8154 conres(); /* Let Ctrl-C work. */
8156 debug(F110,"dorename line",line,0);
8159 z = zxrewind(); /* Rewind file list */
8161 z = nzxpand(s,0); /* Expand file list */
8162 #endif /* ZXREWIND */
8163 debug(F111,"dorename p",p,z);
8167 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
8171 Note: COPY, RENAME, DELETE and similar commands should have options to
8172 stop or proceed when they are operating on multiple files and the operation
8176 if (!(z == 0 && !wild))
8180 if (listing) printf("%s => %s ",line,p);
8181 if (zrename(line,p) < 0) {
8183 printf("(FAILED: %s)\n",ck_errstr());
8185 printf("?%s - %s\n",ck_errstr(),line);
8188 if (listing) printf("(OK)\n");
8192 concb((char)escape);
8194 return(success = rc);
8196 #endif /* ZRENAME */
8197 #endif /* NOFRILLS */
8198 #endif /* NORENAME */
8202 /* Do the RETURN command */
8205 doreturn(s) char *s; {
8211 printf("\n?Can't return from level %d\n",maclvl);
8212 return(success = 0);
8214 line = malloc(LINBUFSIZ);
8216 return(success = 0);
8217 lp = line; /* Expand return value now */
8220 debug(F110,"RETURN s",s,0);
8221 if (zzstring(s,&lp,&x) > -1) {
8223 debug(F110,"RETURN zzstring",s,0);
8226 /* Pop from all FOR/WHILE/SWITCH/XIFs */
8227 while ((maclvl > 0) &&
8228 (m_arg[maclvl-1][0]) &&
8229 (cmdstk[cmdlvl].src == CMD_MD) &&
8230 (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
8231 !strncmp(m_arg[maclvl-1][0],"_for",4) ||
8232 !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
8233 !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
8234 debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl);
8235 dogta(XXPTA); /* Put args back */
8236 popclvl(); /* Pop up two levels */
8239 if (tra_asg) { /* If tracing show return value */
8241 printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
8243 printf("<<< %s: (null)\n", m_arg[maclvl][0]);
8245 popclvl(); /* Pop from enclosing TAKE or macro */
8246 debug(F111,"RETURN tolevel",s,maclvl);
8249 makestr(&(mrval[maclvl+1]),s); /* Set the RETURN value */
8251 return(success = 1); /* Macro succeeds if we RETURN */
8256 /* Do the OPEN command */
8259 doopen() { /* OPEN { append, read, write } */
8260 int x, y, z = 0; char *s;
8261 static struct filinfo fcb; /* (must be static) */
8262 if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
8264 printf("?Mode required\n");
8269 case OPN_FI_R: /* Old file (READ) */
8270 if (chkfn(ZRFILE) > 0) {
8271 printf("?Read file already open\n");
8274 if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
8276 printf("?Input filename required\n");
8280 if (y) { /* No wildcards allowed */
8281 printf("\n?Please specify a single file\n");
8284 ckstrncpy(line,s,LINBUFSIZ);
8285 if ((int)strlen(line) < 1) return(-2);
8286 if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
8289 printf("?Positive number required\n");
8292 if ((z = cmcfm()) < 0) return(z);
8295 free((char *)readbuf);
8296 if (!(readbuf = (CHAR *) malloc(readblock+1))) {
8297 printf("?Can't allocate read buffer\n");
8300 return(success = zopeni(ZRFILE,line));
8304 case OPN_PI_R: /* Pipe/Process (!READ) */
8306 printf("?Read from pipe disabled\n");
8309 if (chkfn(ZRFILE) > 0) {
8310 printf("?Read file already open\n");
8313 if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
8315 printf("?Command name required\n");
8319 ckstrncpy(line,brstrip(s),LINBUFSIZ);
8320 if (!line[0]) return(-2);
8321 if ((y = cmcfm()) < 0) return(y);
8323 if (!(readbuf = (CHAR *) malloc(readblock+1))) {
8324 printf("?Can't allocate read buffer\n");
8328 return(success = zxcmd(ZRFILE,line));
8330 case OPN_PI_W: /* Write to pipe */
8332 printf("?Write to pipe disabled\n");
8335 if (chkfn(ZWFILE) > 0) {
8336 printf("?Write file already open\n");
8339 if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
8341 printf("?Command name required\n");
8345 ckstrncpy(line,brstrip(s),LINBUFSIZ);
8346 if (!line[0]) return(-2);
8347 if ((y = cmcfm()) < 0) return(y);
8348 success = zxcmd(ZWFILE,line);
8349 if (!success && msgflg)
8350 printf("Can't open process for writing: %s\n",line);
8355 case OPN_FI_W: /* New file (WRITE) */
8356 case OPN_FI_A: /* (APPEND) */
8357 if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
8359 printf("?Filename required\n");
8364 printf("?Sorry, %s is a directory name\n",s);
8367 if (chkfn(ZWFILE) > 0) {
8368 printf("?Write/Append file already open\n");
8371 fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
8373 fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
8374 ckstrncpy(line,s,LINBUFSIZ);
8375 if ((int)strlen(line) < 1) return(-2);
8376 if ((y = cmcfm()) < 0) return(y);
8377 return(success = zopeno(ZWFILE,line,NULL,&fcb));
8380 case OPN_SER: /* OPEN PORT or LINE */
8381 case OPN_NET: { /* OPEN HOST */
8382 extern int didsetlin, ttnproto;
8387 if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
8395 #endif /* NOLOCAL */
8398 printf("?Not implemented");
8405 /* D O X G E T -- GET command parser with switches */
8410 #endif /* CK_LABELED */
8413 doxget(cx) int cx; {
8414 extern int /* External variables we need */
8417 #endif /* RECURSIVE */
8418 xfermode, fdispla, protocol, usepipes,
8419 g_binary, g_xfermode, g_displa, g_rpath, g_usepipes;
8420 extern char * rcv_move; /* Directory to move new files to */
8421 extern char * rcv_rename; /* What to rename new files to */
8422 extern char * rcvexcept[]; /* RECEIVE / GET exception list */
8423 int opkt = 0; /* Flag for O-Packet needed */
8426 extern int pipesend;
8427 extern char * rcvfilter;
8428 #endif /* PIPESEND */
8429 extern struct keytab rpathtab[];
8430 extern int nrpathtab;
8431 extern long calibrate;
8432 int asname = 0; /* Flag for have as-name */
8433 int konly = 0; /* Kermit-only function */
8434 int c, i, n, confirmed = 0; /* Workers */
8435 int getval = 0; /* Whether to get switch value */
8436 int rcvcmd = 0; /* Whether it is the RECEIVE command */
8437 int mget = 0; /* Whether it is the MGET command */
8438 struct stringint { /* Temporary array for switch values */
8442 struct FDB sw, fl, cm; /* FDBs for each parse function */
8443 char * cmdstr = "this command";
8446 if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) {
8448 extern int ftpisopen();
8449 if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
8450 return(doftpget(cx,0));
8454 debug(F101,"xget cx","",cx);
8459 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
8463 /* Preset switch values based on top-level command that called us */
8466 case XXREC: /* RECEIVE */
8469 case XXGET: /* GET */
8474 case XXREGET: /* REGET */
8477 pv[SND_BIN].ival = 1; /* Implies /BINARY */
8478 pv[SND_RES].ival = 1; break;
8479 #endif /* CK_RESEND */
8480 case XXRETR: /* RETRIEVE */
8481 cmdstr = "RETRIEVE";
8483 pv[SND_DEL].ival = 1; break;
8485 case XXCREC: /* CRECEIVE */
8486 cmdstr = "CRECEIVE";
8489 pv[SND_CMD].ival = 1; break;
8490 case XXCGET: /* CGET */
8493 pv[SND_CMD].ival = 1; break;
8494 #endif /* PIPESEND */
8496 case XXMGET: /* MGET */
8502 debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
8503 debug(F101,"xget konly","",konly);
8506 if (!rcvcmd && protocol != PROTO_K) {
8507 printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
8512 /* Set up chained parse functions... */
8514 cmfdbi(&sw, /* First FDB - command switches */
8517 "Optional name/template to store incoming files under, or switch" :
8518 "Remote filename, or switch", /* hlpmsg */
8520 "", /* addtl string data */
8521 rcvcmd ? nrcvtab : ngettab, /* addtl numeric data 1: tbl size */
8522 4, /* addtl numeric data 2: 4 = cmswi */
8523 xxstring, /* Processing function */
8524 rcvcmd ? rcvtab : gettab, /* Keyword table */
8525 &fl /* Pointer to next FDB */
8527 if (rcvcmd || mget) /* RECEIVE or MGET */
8530 rcvcmd ? /* hlpmsg */
8531 "Output filename or Command" : /* Output filename */
8532 "File(s) to GET", /* Files we are asking for */
8534 "", /* addtl string data */
8535 0, /* addtl numeric data 1 */
8536 0, /* addtl numeric data 2 */
8538 (protocol == PROTO_X || protocol == PROTO_XC) ?
8540 (rcvcmd ? (xx_strp)0 : xxstring)
8542 rcvcmd ? (xx_strp)0 : xxstring /* Processing function */
8549 cmfdbi(&fl, /* Remote filename or command */
8551 "Remote filename", /* hlpmsg */
8553 "", /* addtl string data */
8554 0, /* addtl numeric data 1 */
8555 0, /* addtl numeric data 2 */
8560 cmfdbi(&cm, /* Confirmation */
8564 "", /* addtl string data */
8565 0, /* addtl numeric data 1 */
8566 0, /* addtl numeric data 2 */
8572 /* (See doxsend() for fuller commentary) */
8574 while (1) { /* Parse 0 or more switches */
8575 x = cmfdb(&sw); /* Parse something */
8576 debug(F101,"xget cmfdb","",x);
8577 if (x < 0) /* Error */
8578 goto xgetx; /* or reparse needed */
8579 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
8581 c = cmgbrk(); /* Get break character */
8582 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
8583 printf("?This switch does not take an argument\n");
8587 if (!getval && (cmgkwflgs() & CM_ARG)) {
8588 printf("?This switch requires an argument\n");
8592 n = cmresult.nresult; /* Numeric result = switch value */
8593 debug(F101,"xget switch","",n);
8595 switch (n) { /* Process the switch */
8597 case SND_CMD: /* These take no args */
8599 printf("?Sorry, system command access is disabled\n");
8602 } else if (rcvfilter) {
8604 "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
8609 sw.hlpmsg = "Command, or switch"; /* Change help message */
8611 #endif /* PIPESEND */
8613 case SND_REC: /* /RECURSIVE */
8614 pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
8615 pv[n].ival = 1; /* Set the recursive flag */
8618 case SND_RES: /* /RECOVER */
8619 pv[SND_BIN].ival = 1; /* Implies /BINARY */
8620 pv[n].ival = 1; /* Set the resend flag */
8623 case SND_DEL: /* /DELETE */
8624 case SND_SHH: /* /QUIET */
8625 case SND_CAL: /* /CALIBRATE */
8626 case SND_XPA: /* /TRANSPARENT */
8627 pv[n].ival = 1; /* Just set the appropriate flag */
8630 case SND_PIP: /* /PIPES:{ON,OFF} */
8635 if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
8641 /* File transfer modes - each undoes the others */
8643 case SND_BIN: /* Binary */
8644 case SND_TXT: /* Text */
8645 case SND_IMG: /* Image */
8646 case SND_LBL: /* Labeled */
8647 pv[SND_BIN].ival = 0; /* Unset all */
8648 pv[SND_TXT].ival = 0;
8649 pv[SND_IMG].ival = 0;
8650 pv[SND_LBL].ival = 0;
8651 pv[n].ival = 1; /* Set the requested one */
8654 case SND_EXC: /* Excludes */
8656 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
8658 printf("?Pattern required\n");
8663 if (pv[n].sval) free(pv[n].sval);
8666 printf("?Pattern too long - 256 max\n");
8670 pv[n].sval = malloc(y+1);
8672 strcpy(pv[n].sval,s); /* safe */
8678 /* Not implemented */
8679 case SND_PRI: /* GET to printer */
8682 if ((x = cmfld("Print options","",&s,xxstring)) < 0)
8684 pv[n].sval = malloc((int)strlen(s)+1);
8686 strcpy(pv[n].sval,s); /* safe */
8688 #endif /* COMMENT */
8690 case SND_MOV: /* MOVE after */
8691 case SND_REN: /* RENAME after */
8693 if ((x = cmfld(n == SND_MOV ?
8694 "device and/or directory for source file after sending" :
8695 "new name for source file after sending",
8698 n == SND_MOV ? xxstring : NULL
8701 printf("%s\n", n == SND_MOV ?
8702 "?Destination required" :
8703 "?New name required"
8716 pv[n].sval = malloc(y+1);
8718 strcpy(pv[n].sval,s); /* safe */
8724 case SND_ASN: /* As-name */
8727 printf("?Sorry, as-name not allowed with MGET\n");
8731 if ((x = cmfld("Name to store it under","",&s,NULL)) < 0)
8734 if ((y = strlen(s)) > 0) {
8735 if (pv[n].sval) free(pv[n].sval);
8736 pv[n].sval = malloc(y+1);
8738 strcpy(pv[n].sval,s); /* safe */
8745 case SND_FLT: /* Filter */
8746 debug(F101,"xget /filter getval","",getval);
8748 if ((x = cmfld("Filter program to receive through",
8755 if (*s) s = brstrip(s);
8757 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
8758 if (s[x] != '\\') continue;
8759 if (s[x+1] == 'v') break;
8763 "?Filter must contain a replacement variable for filename.\n"
8773 if ((y = strlen(s)) > 0) {
8774 if ((pv[n].sval = malloc(y+1)))
8775 strcpy(pv[n].sval,s); /* safe */
8778 #endif /* PIPESEND */
8780 case SND_PTH: /* Pathnames */
8782 pv[n].ival = PATH_REL;
8785 if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
8787 pv[n].ival = x; /* Ditto */
8790 case SND_NAM: /* Filenames */
8792 if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
8797 case SND_PRO: /* Protocol to use */
8799 if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
8806 debug(F111,"xget /proto",atmbuf,x);
8808 if (konly && x != PROTO_K) {
8810 "?Sorry, this command works only with Kermit protocol\n"
8818 printf("?Unexpected switch value - %d\n",cmresult.nresult);
8823 debug(F101,"xget cmresult fcode","",cmresult.fcode);
8825 cmarg = line; /* Initialize string pointers */
8828 line[0] = NUL; /* and buffers. */
8831 switch (cmresult.fcode) { /* How did we get out of switch loop */
8832 case _CMFLD: /* (3) Remote filespec */
8833 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
8835 case _CMTXT: /* (4) As-name */
8837 ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
8838 if ((int)strlen(tmpbuf) > 0)
8841 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
8843 case _CMCFM: /* (6) Confirmation */
8847 printf("?Unexpected function code: %d\n",cmresult.fcode);
8851 debug(F110,"xget string",cmarg,0);
8852 debug(F101,"xget confirmed","",confirmed);
8854 cmarg = brstrip(cmarg); /* Strip any braces */
8856 if (!confirmed) { /* CR not typed yet, get more fields */
8857 if (pv[SND_CMD].ival > 0) {
8858 debug(F100,"xget calling cmtxt","",0);
8859 x = cmtxt("Local command to pipe into","",&s,NULL);
8860 if (x < 0 && x != -3) goto xgetx;
8862 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8865 } else if (!rcvcmd) {
8867 /* cmofi() fails if you give it a directory name */
8868 x = cmfld("Name or directory for incoming file","",&s,NULL);
8869 debug(F111,"xget cmfld",s,x);
8871 x = cmofi("Name or directory for incoming file","",&s,NULL);
8872 debug(F111,"xget cmofi",s,x);
8874 if (x < 0 && x != -3) goto xgetx;
8876 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8877 if ((x = cmcfm()) < 0) goto xgetx;
8882 /* Arrive here with cmarg and cmarg2 all set */
8884 debug(F111,"xget asname",cmarg2,asname);
8886 if (pv[SND_ASN].sval)
8887 ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
8891 cmarg2 = brstrip(cmarg2); /* Strip outer braces if any. */
8892 debug(F110,"xget cmarg",cmarg,0);
8893 debug(F110,"xget cmarg2",cmarg2,0);
8896 (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
8897 printf("?A remote file specification is required\n");
8902 if (pv[SND_CMD].ival > 0) { /* /COMMAND sets pipesend flag */
8905 printf("?Command required\n");
8907 } else if (nopush) {
8908 printf("?Sorry, system command access is disabled\n");
8910 } else if (rcvfilter) {
8911 printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
8916 debug(F101,"xget /COMMAND pipesend","",pipesend);
8917 #endif /* PIPESEND */
8920 if (pv[SND_RES].ival > 0) { /* REGET or GET /RECOVER */
8922 if (pv[SND_REC].ival > 0) { /* RECURSIVE */
8924 printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
8929 #endif /* COMMENT */
8931 #endif /* RECURSIVE */
8932 if (pv[SND_DEL].ival > 0) { /* /DELETE */
8934 printf("?Unsupported option combination: /RECOVER /DELETE\n");
8939 #endif /* COMMENT */
8942 #endif /* CK_RESEND */
8944 if (pv[SND_EXC].ival > 0) /* /EXCEPT */
8945 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
8950 && protocol == PROTO_K
8953 if (!iks_wait(KERMIT_REQ_START,1)) {
8955 "?A Kermit Server is not available to process this command\n");
8956 x = -9; /* correct the return code */
8960 #endif /* IKS_OPTION */
8964 int po, pg; /* (for clarity) */
8965 po = pv[SND_PRO].ival; /* /PROTOCOL option */
8966 pg = protocol; /* Protocol global */
8967 if ((rcvcmd && !*cmarg2) && /* If no as-name was given */
8968 /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */
8969 ((po < 0 && (pg == PROTO_X || pg == PROTO_XC)) ||
8970 (po > -1 && (po == PROTO_X || po == PROTO_XC)))
8973 "Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
8982 if (pv[SND_REC].ival > 0) { /* RECURSIVE */
8984 pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames too */
8986 #endif /* RECURSIVE */
8988 if (pv[SND_PIP].ival > -1) {
8989 g_usepipes = usepipes;
8990 usepipes = pv[SND_PIP].ival;
8993 /* Save global protocol parameters */
8997 g_lf_opts = lf_opts; /* Save labeled transfer options */
8998 #endif /* CK_LABELED */
8999 g_urpsiz = urpsiz; /* Receive packet length */
9000 g_spsizf = spsizf; /* Send packet length flag */
9001 g_spsiz = spsiz; /* Send packet length */
9002 g_spsizr = spsizr; /* etc etc */
9005 g_prefixing = prefixing;
9008 g_fnspath = fnspath;
9009 g_fnrpath = fnrpath;
9012 if (pv[SND_PRO].ival > -1) { /* Change according to switch */
9013 protocol = pv[SND_PRO].ival;
9014 if (ptab[protocol].rpktlen > -1) /* copied from initproto() */
9015 urpsiz = ptab[protocol].rpktlen;
9016 if (ptab[protocol].spktflg > -1)
9017 spsizf = ptab[protocol].spktflg;
9018 if (ptab[protocol].spktlen > -1) {
9019 spsiz = ptab[protocol].spktlen;
9021 spsizr = spmax = spsiz;
9023 if (ptab[protocol].winsize > -1)
9024 wslotr = ptab[protocol].winsize;
9025 if (ptab[protocol].prefix > -1)
9026 prefixing = ptab[protocol].prefix;
9027 if (ptab[protocol].fnca > -1)
9028 fncact = ptab[protocol].fnca;
9029 if (ptab[protocol].fncn > -1)
9030 fncnv = ptab[protocol].fncn;
9031 if (ptab[protocol].fnsp > -1)
9032 fnspath = ptab[protocol].fnsp;
9033 if (ptab[protocol].fnrp > -1)
9034 fnrpath = ptab[protocol].fnrp;
9036 debug(F101,"xget protocol","",protocol);
9037 debug(F111,"xget cmarg2",cmarg2,xfermode);
9039 g_xfermode = xfermode;
9041 if (pv[SND_BIN].ival > 0) { /* Change according to switch */
9043 binary = XYFT_B; /* FILE TYPE BINARY */
9044 omode = GMOD_BIN; /* O-Packet mode */
9045 debug(F101,"doxget /BINARY xfermode","",xfermode);
9046 } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */
9050 debug(F101,"doxget /TEXT xfermode","",xfermode);
9051 } else if (pv[SND_IMG].ival > 0) {
9059 debug(F101,"doxget /IMAGE xfermode","",xfermode);
9062 else if (pv[SND_LBL].ival > 0) {
9066 debug(F101,"doxget /LABELED xfermode","",xfermode);
9068 #endif /* CK_LABELED */
9069 debug(F101,"xget binary","",binary);
9070 debug(F101,"xget omode","",omode);
9072 if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */
9073 xfrxla = 0; /* Don't translate character sets */
9076 if (pv[SND_FLT].ival > 0)
9077 makestr(&rcvfilter,pv[SND_FLT].sval);
9078 #endif /* PIPESEND */
9081 if (pv[SND_MOV].ival > 0) {
9083 char * p = pv[SND_MOV].sval;
9086 printf("?Sorry, /MOVE-TO not available to guests\n");
9090 #endif /* CK_LOGIN */
9092 if (!isdir(p)) { /* Check directory */
9095 s = (char *)malloc(len + 4);
9097 strcpy(s,p); /* safe */
9099 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
9101 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
9102 #endif /* datageneral */
9108 printf("?Can't create \"%s\"\n",p);
9114 printf("?Directory \"%s\" not found\n",p);
9117 #endif /* CK_MKDIR */
9119 zfnqfp(p,LINBUFSIZ,line);
9120 makestr(&rcv_move,line);
9122 #endif /* CK_TMPDIR */
9124 if (pv[SND_REN].ival > 0) { /* /RENAME-TO:name */
9125 char * p = pv[SND_REN].sval;
9128 printf("?Sorry, /RENAME-TO not available to guests\n");
9132 #endif /* CK_LOGIN */
9135 printf("?New name required for /RENAME\n");
9140 makestr(&rcv_rename,p);
9141 debug(F110,"xget rcv_rename","",0);
9145 if (pv[SND_CAL].ival > 0)
9147 #endif /* CALIBRATE */
9149 if (pv[SND_SHH].ival > 0)
9151 debug(F101,"xget display","",fdispla);
9153 if (pv[SND_NAM].ival > -1) { /* /FILENAMES */
9154 g_fncnv = fncnv; /* Save global value */
9155 fncnv = pv[SND_NAM].ival;
9156 debug(F101,"xsend fncnv","",fncnv);
9157 /* We should also handle O packet filename option here */
9158 /* but we don't really need to since WHATAMI already handles it */
9160 if (pv[SND_PTH].ival > -1) { /* PATHNAMES */
9161 g_rpath = fnrpath; /* Save global values */
9162 fnrpath = pv[SND_PTH].ival;
9163 debug(F101,"xsend fnrpath","",fnrpath);
9165 if (fnrpath != PATH_OFF) {
9168 debug(F101,"xsend fncnv","",fncnv);
9170 /* We should also handle O packet pathname option here */
9171 /* but we don't really need to since WHATAMI already handles it */
9175 /* Set protocol start state */
9177 if (opkt) { /* Extended GET Options*/
9178 sstate = (CHAR) 'o';
9180 if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
9181 if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
9182 if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
9184 sstate = (CHAR) 'v'; /* RECEIVE or CRECEIVE */
9185 else if (pv[SND_DEL].ival > 0)
9186 sstate = (CHAR) 'h'; /* GET /DELETE (= RETRIEVE) */
9187 else if (pv[SND_RES].ival > 0)
9188 sstate = (CHAR) 'j'; /* GET /RECOVER (= REGET) */
9190 sstate = (CHAR) 'r'; /* Regular GET */
9192 debug(F000,"xget sstate","",sstate);
9198 if (pv[SND_SHH].ival != 0)
9206 #endif /* PIPESEND */
9210 cmarg2 is also allowed to be a device or directory name;
9211 even the name of a directory that doesn't exist.
9214 debug(F111,"xget strlen(cmarg2)",cmarg2,y);
9217 ((isalpha(cmarg2[0]) &&
9219 cmarg2[2] == NUL) ||
9220 (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
9224 (cmarg2[y-1] == '/' || isdir(cmarg2))
9227 (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
9230 (cmarg2[y-1] == '>' || isdir(cmarg2))
9233 (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
9236 #endif /* datageneral */
9237 #endif /* STRATUS */
9239 #endif /* UNIXOROSK */
9242 debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
9247 ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
9248 f_tmpdir = 1; /* and that we did this */
9250 printf("?Can't get current directory\n");
9257 x = zchki(cmarg2); /* Does as-name exist? */
9258 if (x == -1) { /* Doesn't exist */
9259 char * p = NULL; /* Try to create it */
9261 if ((p = (char *)malloc(x+4))) {
9262 sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */
9266 printf("?Can't create %s\n",cmarg2);
9272 #endif /* CK_MKDIR */
9273 if (!zchdir(cmarg2)) { /* change to given disk/directory, */
9274 printf("?Can't access %s\n",cmarg2);
9281 #endif /* CK_TMPDIR */
9283 ckstrncpy(fspec,cmarg,CKMAXPATH); /* Note - this is a REMOTE filespec */
9284 debug(F111,"xget fspec",fspec,fspeclen);
9285 debug(F110,"xget cmarg2",cmarg2,0);
9288 for (i = 0; i < SND_MAX; i++)
9298 D O G T A -- Do _GETARGS or _PUTARGS Command.
9300 Used by XIF, FOR, WHILE, and SWITCH, each of which are implemented as
9301 2-level macros; the first level defines the macro, the second runs it.
9302 This routine hides the fact that they are macros by importing the
9303 macro arguments (if any) from two levels up, to make them available
9304 in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
9305 loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
9306 _PUTARGS is in case we changed any of these variables or used SHIFT
9307 on them, so the new values won't be lost as we pop up the stack.
9312 char c, *p, mbuf[4];
9313 extern int topargc, cmdint;
9314 extern char ** topxarg;
9316 if ((y = cmcfm()) < 0)
9318 debug(F101,"dogta cx","",cx);
9319 debug(F101,"dogta maclvl","",maclvl);
9321 debug(F101,"dogta _GETARGS maclvl","",maclvl);
9322 } else if (cx == XXPTA) {
9323 debug(F101,"dogta _PUTARGS maclvl","",maclvl);
9328 return(success = 0);
9330 /* Make new copies of macro arguments /%0..9 */
9332 mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
9334 if (cx == XXPTA) { /* Go NOINT because _PUTARGS */
9335 if (cmdint) /* temporarily changes maclvl. */
9336 connoi(); /* Interrupts OFF. */
9338 for (i = 0; i < 10; i++) { /* For all args */
9339 c = (char) (i + '0'); /* Make name */
9340 mbuf[1] = (char) c; /* Insert digit */
9341 if (cx == XXGTA) { /* Get arg from level-minus-2 */
9342 if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
9343 else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
9347 makestr(&(m_line[maclvl]),m_line[maclvl-2]);
9348 #endif /* COMMENT */
9349 } else if (cx == XXPTA) { /* Put args level+2 */
9350 maclvl -= 2; /* This is gross, it's because we're */
9351 addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */
9352 maclvl += 2; /* and addmac() uses maclvl. */
9353 count[cmdlvl - 2] = count[cmdlvl];
9354 intime[cmdlvl - 2] = intime[cmdlvl];
9355 inpcas[cmdlvl - 2] = inpcas[cmdlvl];
9356 takerr[cmdlvl - 2] = takerr[cmdlvl];
9357 merror[cmdlvl - 2] = merror[cmdlvl];
9358 xquiet[cmdlvl - 2] = xquiet[cmdlvl];
9359 } else return(success = 0); /* Bad call to this routine */
9361 if (cx == XXPTA) { /* Restore interrupts if we */
9362 if (cmdint) /* turned them off above. */
9363 conint(trap,stptrap);
9365 /* Now take care of the argument vector array \&_[], \v(return), */
9366 /* and \v(argc) by just copying the pointers. */
9368 if (cx == XXGTA) { /* GETARGS from 2 levels up */
9370 a_ptr[0] = topxarg; /* \&_[] array */
9371 a_dim[0] = topargc - 1; /* Dimension doesn't include [0] */
9372 m_xarg[maclvl] = topxarg;
9373 n_xarg[maclvl] = topargc; /* But \v(argc) does include \%0 */
9374 macargc[maclvl] = topargc;
9375 makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
9377 a_ptr[0] = m_xarg[maclvl-2];
9378 a_dim[0] = n_xarg[maclvl-2];
9379 m_xarg[maclvl] = m_xarg[maclvl-2];
9380 n_xarg[maclvl] = n_xarg[maclvl-2];
9381 macargc[maclvl] = n_xarg[maclvl-2];
9382 makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
9385 } else { /* PUTARGS 2 levels up */
9387 a_ptr[0] = m_xarg[maclvl];
9388 m_xarg[maclvl-2] = m_xarg[maclvl];
9389 a_dim[0] = n_xarg[maclvl];
9390 n_xarg[maclvl-2] = n_xarg[maclvl];
9391 macargc[maclvl-2] = n_xarg[maclvl];
9394 return(1); /* Internal command - don't change success */
9400 Do the GOTO and [_]FORWARD commands.
9401 s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
9404 #define LBLMAXLEN 255 /* Max label length */
9406 #define LBLMAXLEN 63
9407 #endif /* BIGBUFOK */
9410 dogoto(s, cx) char *s; int cx; {
9411 int i, j, x, y, z, bc;
9412 int empty = 0, stopflg = 0;
9413 char * cmd; /* Name of this command */
9414 char tmplbl[LBLMAXLEN+1], *lp; /* Current label from command stream */
9415 char tmp2[LBLMAXLEN+1]; /* SWITCH label conversion buffer */
9416 char tmp3[LBLMAXLEN+1]; /* Target label */
9418 stopflg = (cx == XXXFWD); /* _FORWARD (used in SWITCH) */
9419 bc = 0; /* Brace counter */
9421 cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
9427 debug(F111,"GOTO command",cmd,cx);
9428 debug(F101,"GOTO cmdlvl","",cmdlvl);
9429 debug(F101,"GOTO maclvl","",maclvl);
9430 debug(F101,"GOTO tlevel","",tlevel);
9431 debug(F111,"GOTO target",s,empty);
9434 debug(F110,cmd,s,0);
9435 ckstrncpy(tmp3+1,s,LBLMAXLEN-1);
9437 if (*s != ':') { /* Make copy of label */
9438 tmp3[0] = ':'; /* guaranteed to start with ":" */
9441 if (!stopflg && !empty) {
9442 if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
9443 printf("?Bad label syntax - '%s'\n",s);
9444 return(success = 0);
9448 printf("?Sorry, %s only works in a command file or macro\n",cmd);
9449 return(success = 0);
9451 y = strlen(s); /* y = length of target label */
9452 debug(F111,cmd,s,y);
9454 while (cmdlvl > 0) { /* As long as not at top level... */
9455 if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
9459 /* GOTO: rewind the macro; FORWARD: start at current position */
9461 lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
9462 m = (int)strlen(lp) - y + 1;
9463 debug(F010,"GOTO in macro",lp,0);
9465 flag = 1; /* flag for valid label position */
9466 for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
9467 if (*lp == '{') /* But only at this level */
9468 bc++; /* Anything inside braces is off */
9469 else if (*lp == '}') /* limits. */
9471 if (stopflg && bc > 0) /* This is good for SWITCH */
9472 continue; /* but interferes with WHILE, etc. */
9477 if (flag) { /* If in valid label position */
9478 if (*lp == SP) /* eat leading spaces */
9480 if (*lp != ':') { /* Look for label introducer */
9481 flag = 0; /* this isn't it */
9482 continue; /* keep looking */
9485 if (!flag) /* We don't have a label */
9486 continue; /* so keep looking... */
9487 xp = lp; tp = tmplbl; /* Copy the label from the macro */
9488 j = 0; /* to make it null-terminated */
9489 while ((*tp = *xp)) {
9490 if (j++ > LBLMAXLEN) /* j = length of word from macro */
9493 if (*tp < 33 || *tp == ',') /* Look for end of word */
9495 if (!*tp || *tp == ',') /* Look for end of word */
9496 #endif /* COMMENT */
9498 else tp++, xp++; /* Next character */
9500 *tp = NUL; /* In case we stopped early */
9501 /* Now do caseless string comparison, using longest length */
9502 debug(F111,"macro GOTO label",s,y);
9503 debug(F111,"macro target label",tmplbl,j);
9504 if (stopflg) { /* Allow variables as SWITCH labels */
9505 int n = LBLMAXLEN - 1;
9507 zzstring(tmplbl,&p,&n);
9508 ckstrncpy(tmplbl,tmp2,LBLMAXLEN);
9511 debug(F111,"GOTO s",s,y);
9512 debug(F111,"GOTO tmplbl",tmplbl,j);
9513 debug(F101,"GOTO empty",ckitoa(stopflg),empty);
9515 if (empty) { /* Empty target */
9516 z = (!strcmp(s,":") && /* String is empty */
9517 /* and Label is ":" or ":*"... */
9518 (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*")))
9520 debug(F111,"GOTO","A",z);
9521 } else if (stopflg) {
9522 z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
9523 debug(F111,"GOTO","B",z);
9525 z = (stopflg && inpcas[cmdlvl]) ?
9527 ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
9528 debug(F111,"GOTO","C",z);
9532 } else if (stopflg &&
9533 !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) {
9534 debug(F100,"GOTO DEFAULT","",0);
9540 debug(F111,"GOTO macro i",cmd,i);
9541 debug(F111,"GOTO macro m",cmd,m);
9542 if (i >= m) { /* Didn't find the label */
9543 debug(F101,"GOTO failed cmdlvl","",cmdlvl);
9545 /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */
9548 #endif /* COMMENT */
9550 (m_arg[maclvl-1][0]) &&
9551 (cmdstk[cmdlvl].src == CMD_MD) &&
9552 (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
9553 !strncmp(m_arg[maclvl-1][0],"_for",4) ||
9554 !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
9555 !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
9556 dogta(XXPTA); /* Restore args */
9557 debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
9558 popclvl(); /* Pop an extra level */
9560 debug(F101,"GOTO popping","",cmdlvl);
9561 if (!popclvl()) { /* pop up to next higher level */
9562 printf("?Label '%s' not found\n",s); /* if none */
9563 return(0); /* Quit */
9564 } else if (stopflg) { /* SWITCH no case label match */
9565 return(0); /* and no DEFAULT lable. */
9567 continue; /* otherwise look again */
9570 debug(F110,"GOTO found macro label",tmplbl,0);
9571 macp[maclvl] = lp; /* set macro buffer pointer */
9573 } else if (cmdstk[cmdlvl].src == CMD_TF) {
9574 x = 0; /* GOTO issued in take file */
9575 debug(F111,"GOTO in TAKE file",cmd,cx);
9576 if (cx == XXGOTO) { /* If GOTO, but not FORWARD, */
9577 rewind(tfile[tlevel]); /* search file from beginning */
9580 while (! feof(tfile[tlevel])) {
9582 /* This is wrong - it lets us jump to labels inside inferior blocks */
9584 if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
9586 if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0)
9587 #endif /* COMMENT */
9588 break; /* If no more, done, label not found */
9589 lp = line; /* Got line */
9590 while (*lp == SP || *lp == HT)
9591 lp++; /* Strip leading whitespace */
9592 if (*lp != ':') continue; /* Check for label introducer */
9593 while (*(lp+1) == SP) { /* Remove space between : and name */
9595 lp++; /* Strip leading whitespace */
9597 tp = lp; /* Get end of word */
9599 while (*tp) { /* And null-terminate it */
9605 if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
9608 } else if (stopflg &&
9609 !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
9614 if (x == 0) { /* If not found, print message */
9615 debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
9618 if (!popclvl()) { /* pop up to next higher level */
9619 printf("?Label '%s' not found\n",s); /* if none */
9620 return(0); /* quit */
9621 } else continue; /* otherwise look again */
9623 return(x); /* Send back return code */
9626 printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
9631 /* Finish parsing and do the IF, XIF, and WHILE commands */
9635 /* C H K V A R -- Check (if it's a) Variable */
9640 Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
9641 have backslashes in them. How do we know if a backslash in a filename is a
9642 directory separator, or if it's a Kermit backslash? This routine does a
9643 rough syntax check of the next few characters and if it looks like it MIGHT
9644 be a variable, then it tries to evaluate it, and if the result is not empty,
9645 we say it's a variable, although sometimes it might not be -- some cases are
9646 truly ambiguous. For example there might a DOS directory called \%a, and
9647 we also have a variable with the same name. This is all for the sake of not
9648 having to tell PC users that they have to double all backslashes in file
9649 and directory names.
9653 Somewhat less crude & disgusting. The previous method was nondeterministic
9654 and (worse) it interfered with macro argument passing. So now we only
9655 check the syntax of backslash-items to see if they are variables, but we
9656 do NOT check their values.
9658 #endif /* OLDCHKVAR */
9660 Call with a string pointer pointing at the backslash of the purported
9661 variable. Returns 1 if it has the syntax of a variable, 0 if not.
9664 chkvar(s) char *s; {
9665 int z = 0; /* Return code - assume failure. */
9666 if (!s) s = ""; /* Watch our for null pointers. */
9667 if (!*s) return(0); /* Empty arg so not a variable. */
9668 if (*s == CMDQ) { /* Object begins with backslash. */
9670 c = s[1]; /* Character following backslash. */
9673 if (c == CMDQ) /* Quoted backslash */
9675 c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
9676 if (c == '%') { /* Simple variable */
9681 #endif /* OLDCHKVAR */
9682 } else if (c == '&') { /* Array */
9683 if (!s[2]) return(0);
9685 t = ckindex("]",s,4,0,1);
9687 return((t > 0) ? 1 : 0);
9688 #endif /* OLDCHKVAR */
9689 } else if (c == '$' || /* Environment variable */
9690 c == 'V' || /* Built-in variable */
9691 c == 'M') { /* Macro name */
9694 return((t > 0) ? 1 : 0);
9695 #endif /* OLDCHKVAR */
9696 } else if (c == 'F') { /* Function reference */
9697 /* Don't actually call it - it might have side effects */
9699 if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */
9700 if ((x = ckindex(")",s,x,0,1)))
9702 /* Insert a better syntax check here if necessary */
9706 t = 255; /* This lets us test \v(xxx) */
9707 lp = line; /* and even \f...(xxx) */
9708 zzstring(s,&lp,&t); /* Evaluate it, whatever it is. */
9709 t = strlen(line); /* Get its length. */
9710 debug(F111,"chkvar",line,t);
9711 z = t > 0; /* If length > 0, it's defined */
9713 #endif /* OLDCHKVAR */
9719 /* B O O L E X P -- Evaluate a Boolean expression */
9721 #define BOOLLEN 1024
9722 static char boolval[BOOLLEN];
9725 boolexp(cx) int cx; {
9726 int x, y, z; char *s, *p;
9727 int parens = 0, pcount = 0, ecount = 0;
9732 CKFLOAT f1 = 0.0, f2 = 0.0;
9733 int f1flag = 0, f2flag = 0;
9734 #endif /* FNFLOAT */
9739 not = 0; /* Flag for whether "NOT" was seen */
9740 z = 0; /* Initial IF condition */
9741 ifargs = 0; /* Count of IF condition words */
9742 bx = boolval; /* Initialize boolean value */
9746 cmfdbi(&kw, /* First FDB - command switches */
9748 "Number, numeric-valued variable, Boolean expression, or keyword",
9750 "", /* addtl string data */
9751 nif, /* addtl numeric data 1: tbl size */
9752 0, /* addtl numeric data 2: 4 = silent */
9753 xxstring, /* Processing function */
9754 iftab, /* Keyword table */
9755 &nu /* Pointer to next FDB */
9757 cmfdbi(&nu, /* 2nd FDB - An integer */
9761 "", /* addtl string data */
9770 #endif /* FNFLOAT */
9773 cmfdbi(&fl, /* A floating-point number */
9777 "", /* addtl string data */
9778 0, /* addtl numeric data 1 */
9779 0, /* addtl numeric data 2 */
9784 #endif /* FNFLOAT */
9785 x = cmfdb(&kw); /* Parse a keyword or a number */
9786 debug(F111,"boolval cmfdb","",x);
9792 debug(F111,"boolval switch","",cmresult.fcode);
9793 switch (cmresult.fcode) { /* What did we get? */
9795 case _CMFLD: /* A "field" */
9796 if (isfloat(cmresult.sresult,0)) { /* A floating-point number? */
9797 f1 = floatval; /* Yes, get its value */
9798 f1flag = 1; /* remember we did this */
9799 ifc = 9999; /* Set special "if-code" */
9802 #endif /* FNFLOAT */
9803 case _CMNUM: /* A number... */
9804 ifc = 9999; /* Set special "if-code" */
9806 case _CMKEY: /* A keyword */
9807 ifc = cmresult.nresult; /* Get if-code */
9812 switch (ifc) { /* set z = 1 for true, 0 for false */
9813 case 9999: /* Number */
9816 z = (f1 == 0.0) ? 0 : 1;
9818 #endif /* FNFLOAT */
9819 z = (cmresult.nresult == 0) ? 0 : 1;
9821 case XXIFLP: /* Left paren */
9822 if (pcount == 0 && ifargs > 0)
9829 case XXIFRP: /* Right paren */
9840 case XXIFAN: /* AND (&&) */
9846 case XXIFOR: /* OR (||) */
9852 case XXIFNO: /* IF NOT [ NOT [ NOT ... ] ] */
9853 if (bx > boolval) { /* evala() doesn't like cascaded */
9854 if (*(bx-1) == '!') { /* unary operators... */
9855 *(bx-1) = NUL; /* So here, two wrongs make a right. */
9865 case XXIFTR: /* IF TRUE */
9867 debug(F101,"if true","",z);
9870 case XXIFNT: /* IF FALSE */
9872 debug(F101,"if true","",z);
9875 case XXIFSU: /* IF SUCCESS */
9876 z = ( success != 0 ) ? 1 : 0;
9877 debug(F101,"if success","",z);
9880 case XXIFFA: /* IF FAILURE */
9881 z = ( success == 0 ) ? 1 : 0;
9882 debug(F101,"if failure","",z);
9886 case XXIFDE: /* IF DEFINED */
9887 if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
9888 return((x == -3) ? -2 : x);
9894 if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */
9895 extern struct keytab fnctab[];
9897 ckstrncpy(line,s+2,256);
9899 lp = ckstrchr(line,'(');
9901 x = lookup(fnctab,line,nfuncs,&t);
9904 debug(F111,"if defined function",line,z);
9905 } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */
9906 extern struct keytab vartab[];
9909 if (*(s+2) == '(') {
9910 ckstrncpy(line,s+3,256);
9912 lp = ckstrchr(line,')');
9914 x = lookup(vartab,line,nvars,&t);
9916 if (z) { /* 8.0.203 */
9917 int t; /* It must have a value to succeed */
9918 t = 255; /* as in C-Kermit 6.0 and 7.0 */
9919 lp = line; /* (this was broken in 8.0.200-201) */
9922 z = line[0] ? 1 : 0;
9926 debug(F111,"if defined variable",line,z);
9928 z = chkvar(s); /* Starts with backslash */
9929 if (z > 0) { /* Yes... */
9930 t = 255; /* than buffer so if zzstring fails */
9931 lp = line; /* check for that -- overflow means */
9932 line[0] = NUL; /* the quantity is defined. */
9933 x = zzstring(s,&lp,&t);
9934 if ((x < 0 && t != 255) || !line[0])
9936 debug(F111,"if defined zzstring",line,z);
9937 debug(F101,"if defined zzstring t","",t);
9941 z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
9943 debug(F111,"if defined final",s,z);
9947 case XXIFDC: { /* IF DECLARED */
9951 if ((x = cmfld("Array name","",&s,NULL)) < 0)
9952 return((x == -3) ? -2 : x);
9954 if (*(s+1) != '&') {
9958 x = zzstring(s,&lp,&t);
9963 if ((x = arraybounds(s,&j,&k)) > -1) {
9967 else if (j <= a_dim[x])
9969 if (z == 1 && k > a_dim[x])
9975 case XXIFBG: /* IF BACKGROUND */
9976 case XXIFFG: /* IF FOREGROUND */
9977 bgchk(); /* Check background status */
9978 if (ifc == XXIFFG) /* Foreground */
9980 else z = pflag ? 0 : 1; /* Background */
9984 case XXIFCO: /* IF COUNT */
9985 z = ( --count[cmdlvl] > 0 );
9986 if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
9987 debug(F101,"if count","",z);
9991 case XXIFEX: /* IF EXIST */
9993 case XXIFDI: /* IF DIRECTORY */
9994 #endif /* CK_TMPDIR */
9995 case XXIFAB: /* IF ABSOLUTE */
9997 ((ifc == XXIFDI) ? "Directory name" : "File"),
10000 NULL /* This allows \'s in filenames */
10008 printf("?File or directory name required\n");
10014 if (ifc == XXIFAB) {
10016 } else if (ifc == XXIFEX) {
10017 z = (zgetfs(s) > -1L);
10018 debug(F101,"if exist 1","",z);
10020 if (!z) { /* File not found. */
10021 int t; /* Try expanding variables */
10022 t = LINBUFSIZ-1; /* and looking again. */
10024 zzstring(s,&lp,&t);
10026 z = ( zchki(s) > -1L );
10027 debug(F101,"if exist 2","",z);
10033 z = (zchki(s) == -2)
10035 /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
10038 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
10042 debug(F101,"if directory 1","",z);
10044 if (!z) { /* File not found. */
10045 int t; /* Try expanding variables */
10046 t = LINBUFSIZ-1; /* and looking again. */
10048 zzstring(s,&lp,&t);
10052 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
10055 debug(F101,"if directory 2","",z);
10057 #endif /* CK_TMPDIR */
10062 case XXIFEQ: /* IF EQUAL (string comparison) */
10063 case XXIFLL: /* IF Lexically Less Than */
10064 case XXIFLG: /* If Lexically Greater Than */
10065 if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
10067 printf("?Text required\n");
10071 s = brstrip(s); /* Strip braces */
10072 x = (int)strlen(s);
10073 if (x > LINBUFSIZ-1) {
10074 printf("?IF: strings too long\n");
10077 lp = line; /* lp points to first string */
10078 ckstrncpy(line,s,LINBUFSIZ);
10079 if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
10081 printf("?Text required\n");
10086 y = (int)strlen(s);
10087 if (x + y + 2 > LINBUFSIZ) {
10088 printf("?IF: strings too long\n");
10091 tp = lp + x + 2; /* tp points to second string */
10092 strcpy(tp,s); /* safe (checked) */
10093 x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
10095 case XXIFEQ: /* IF EQUAL (string comparison) */
10098 case XXIFLL: /* IF Lexically Less Than */
10101 case XXIFLG: /* If Lexically Greater Than */
10105 debug(F101,"IF EQ result","",z);
10109 case XXIFVE: /* IF VERSION */
10110 case XXIFAE: /* IF (arithmetically) = */
10111 case XXIFNQ: /* IF != (not arithmetically equal) */
10112 case XXIFLT: /* IF < */
10113 case XXIFLE: /* IF <= */
10114 case XXIFGE: /* IF >= */
10115 case XXIFGT: { /* IF > */
10117 /* Really should use longs here... */
10118 /* But cmnum parses ints. */
10119 int xx, n1 = 0, n2 = 0;
10120 if (ifc == XXIFVE) {
10123 x = cmfld("first number or variable name","",&s,xxstring);
10125 printf("?Quantity required\n");
10128 if (x < 0) return(x);
10129 debug(F101,"xxifgt cmfld","",x);
10130 ckstrncpy(line,s,LINBUFSIZ);
10131 lp = brstrip(line);
10132 debug(F110,"xxifgt exp1",lp,0);
10134 /* The following bit is for compatibility with old versions of MS-DOS Kermit */
10136 if (!ckstrcmp(lp,"count",5,0)) {
10137 n1 = count[cmdlvl];
10138 } else if (!ckstrcmp(lp,"version",7,0)) {
10140 } else if (!ckstrcmp(lp,"argc",4,0)) {
10141 n1 = (int) macargc[maclvl];
10144 /* End of compatibility bit */
10147 if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */
10151 #endif /* FNFLOAT */
10154 } else { /* Check for arithmetic expression */
10155 q = evala(lp); /* cmnum() does this but ... */
10156 if (chknum(q)) /* we're not using cmnum(). */
10163 y = cmfld("number or variable name","",&s,xxstring);
10165 printf("?Quantity required\n");
10168 if (y < 0) return(y);
10170 if (!*s) return(-2);
10171 if (ifc == XXIFVE) {
10174 x = (int)strlen(lp);
10177 ckstrncpy(tp,s,LINBUFSIZ-x-2);
10178 debug(F110,"xxifgt exp2",tp,0);
10179 if (!ckstrcmp(tp,"count",5,0)) {
10180 n2 = count[cmdlvl];
10181 } else if (!ckstrcmp(tp,"version",7,0)) {
10183 } else if (!ckstrcmp(tp,"argc",4,0)) {
10184 n2 = (int) macargc[maclvl];
10187 if (isfloat(tp,0) > 1) {
10191 #endif /* FNFLOAT */
10202 xx = (ifc == XXIFVE) ? XXIFGE : ifc;
10205 if (f1flag && !f2flag) {
10209 if (f2flag && !f1flag)
10212 z = ((f1 < f2 && xx == XXIFLT)
10213 || (f1 != f2 && xx == XXIFNQ)
10214 || (f1 <= f2 && xx == XXIFLE)
10215 || (f1 == f2 && xx == XXIFAE)
10216 || (f1 >= f2 && xx == XXIFGE)
10217 || (f1 > f2 && xx == XXIFGT));
10219 #endif /* FNFLOAT */
10220 z = ((n1 < n2 && xx == XXIFLT)
10221 || (n1 != n2 && xx == XXIFNQ)
10222 || (n1 <= n2 && xx == XXIFLE)
10223 || (n1 == n2 && xx == XXIFAE)
10224 || (n1 >= n2 && xx == XXIFGE)
10225 || (n1 > n2 && xx == XXIFGT));
10226 debug(F101,"xxifge z","",z);
10234 case XXIFNU: /* IF NUMERIC */
10235 x = cmfld("variable name or constant","",&s,NULL);
10239 printf("?Quantity required\n");
10246 zzstring(s,&lp,&x);
10248 debug(F110,"xxifnu quantity",lp,0);
10252 This works, but it's not wise -- IF NUMERIC is mostly used to see if a
10253 string really does contain only numeric characters. If they want to force
10254 evaluation, they can use \feval() on the argument string.
10256 if (!z) { /* Not a number */
10257 x_ifnum = 1; /* Avoid "eval" error messages */
10258 q = evala(lp); /* Maybe it's an expression */
10259 z = chknum(q); /* that evaluates to a number */
10260 x_ifnum = 0; /* Put eval messages back to normal */
10261 if (z) debug(F110,"xxifnu exp",lp,0);
10263 #endif /* COMMENT */
10264 debug(F101,"xxifnu chknum","",z);
10269 case XXIFNE: { /* IF NEWER */
10270 char d1[20], * d2; /* Buffers for 2 dates */
10271 if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
10273 ckstrncpy(d1,zfcdat(s),20);
10274 if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
10277 if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
10278 printf("?Failure to get file date\n");
10281 debug(F110,"xxifnewer d1",d1,0);
10282 debug(F110,"xxifnewer d2",d2,0);
10283 z = (strcmp(d1,d2) > 0) ? 1 : 0;
10284 debug(F101,"xxifnewer","",z);
10288 #endif /* ZFCDAT */
10291 case XXIFRO: /* REMOTE-ONLY advisory */
10297 #endif /* NOLOCAL */
10299 #endif /* CK_IFRO */
10301 case XXIFAL: /* ALARM */
10303 debug(F101,"IF ALARM ck_alarm","",ck_alarm);
10304 debug(F110,"IF ALARM alrm_date",alrm_date,0);
10305 debug(F110,"IF ALARM alrm_time",alrm_time,0);
10307 if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
10308 z = 0; /* ALARM not SET */
10309 break; /* so IF ALARM fails */
10311 /* Get current date and time */
10312 ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ);
10315 z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
10316 debug(F101,"IF ALARM date z","",z);
10317 if (z == 0) { /* Dates are the same */
10318 /* Compare times */
10319 z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
10320 debug(F101,"IF ALARM time z","",z);
10322 tmpbuf[0] = NUL; /* z >= 0 if alarm is passed */
10323 z = ((z >= 0) ? 1 : 0); /* z < 0 otherwise */
10324 debug(F101,"IF ALARM final z","",z);
10327 case XXIFOP: /* IF OPEN */
10328 if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
10330 if (x == 9999 || x == ZSTDIO) {
10331 bgchk(); /* Check background status */
10333 } else if (x == 8888) {
10334 z = local ? ttchk() > -1 : 0;
10336 } else if (x == 7777) {
10338 z = dialog ? 1 : 0;
10339 #endif /* CKLOGDIAL */
10341 z = (chkfn(x) > 0) ? 1 : 0;
10345 case XXIFSD: /* Started-From-Dialer */
10347 z = StartedFromDialer;
10353 case XXIFTM: /* Terminal-Macro */
10355 z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
10361 case XXIFEM: /* Emulation is active */
10369 case XXIFIK: /* Running as IKSD? */
10373 case XXIFTA: /* Connection is TAPI */
10377 if (local && !network && tttapi)
10379 #endif /* CK_TAPI */
10380 #endif /* NODIAL */
10383 case XXIFMA: /* IF MATCH */
10384 x = cmfld("String or variable","",&s,xxstring);
10388 printf("?String required\n");
10393 ckstrncpy(line,s,LINBUFSIZ);
10395 debug(F110,"xxifma string",line,0);
10396 x = cmfld("Pattern","",&p,xxstring);
10400 printf("?Pattern required\n");
10405 ckstrncpy(tmpbuf,p,TMPBUFSIZ);
10406 p = brstrip(tmpbuf);
10407 debug(F110,"xxifma pattern",tmpbuf,0);
10408 z = ckmatch(p,s,inpcas[cmdlvl],1);
10411 case XXIFFL: { /* IF FLAG */
10416 case XXIFAV: { /* IF AVAILABLE */
10417 if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
10421 z = ck_krb4_is_installed();
10424 z = ck_krb5_is_installed();
10427 z = ck_srp_is_installed();
10430 z = ck_ssleay_is_installed();
10433 z = ck_ntlm_is_installed();
10436 z = ck_crypt_is_installed();
10439 z = ck_ssh_is_installed();
10446 case XXIFAT: /* IF ASKTIMEOUT */
10450 case XXIFRD: /* IF READABLE */
10451 case XXIFWR: /* IF WRITEABLE */
10452 if ((x = cmfld("File or directory name",
10456 NULL /* This allows \'s in filenames */
10464 printf("?File or directory name required\n");
10471 zchk[io]() do not do what we want here for directories, so we set
10472 a global flag telling it to behave specially in this case. Othewise
10473 we'd have to change the API and change all ck?fio.c modules accordingly.
10475 y = 0; /* Try-again control */
10479 if (ifc == XXIFRD) { /* IF READABLE */
10483 } else if (ifc == XXIFWR) { /* IF WRITEABLE */
10489 if (!z && !y) { /* File not found. */
10490 int t; /* Try expanding variables */
10491 t = LINBUFSIZ-1; /* and looking again. */
10493 zzstring(s,&lp,&t);
10502 case XXIFQU: /* IF QUIET */
10504 debug(F101,"if quiet","",z);
10508 case XXIFWI: /* WILD */
10509 if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
10513 case XXIFCK: /* C-KERMIT */
10521 case XXIFK9: /* K-95 */
10529 case XXIFGU: /* GUI */
10537 case XXIFMS: /* MS-KERMIT */
10541 case XXIFLO: /* IF LOCAL */
10545 case XXIFCM: { /* IF COMMAND */
10546 extern struct keytab cmdtab[];
10548 if ((x = cmfld("Word","",&s,xxstring)) < 0)
10550 z = lookup(cmdtab,s,ncmd,&y);
10551 z = (z == -2 || z > -1) ? 1 : 0;
10555 case XXIFFP: /* IF FLOAT */
10556 if ((x = cmfld("Number","",&s,xxstring)) < 0)
10557 if (x != -3) /* e.g. empty variable */
10561 #endif /* CKFLOAT */
10563 case XXIFKB: /* KBHIT */
10569 case XXIFKG: { /* KERBANG */
10571 z = (xcmdsrc == 0) ? 0 : cfilef;
10575 default: /* Shouldn't happen */
10577 } /* end of switch */
10584 if (bx > boolval + BOOLLEN - 2) {
10585 printf("?Boolean expression too long");
10588 ecount++; /* Expression counter */
10589 debug(F101,"boolexp parens","",parens);
10590 debug(F101,"boolexp pcount","",pcount);
10591 if (parens && pcount > 0)
10594 ifend: /* No more - done */
10596 z = atoi(evalx(boolval));
10597 debug(F111,"boolexp boolval",boolval,z);
10601 /* D O I F -- Do the IF command */
10605 int x, y, z; char *s, *p;
10611 debug(F101,"doif cx","",cx);
10613 z = boolexp(cx); /* Evaluate the condition(s) */
10614 debug(F010,"doif cmdbuf",cmdbuf,0);
10615 debug(F101,"doif boolexp","",z);
10619 if (cx == XXIF) { /* Allow IF to have XIF semantics. */
10624 if (*p == SP || *p == HT)
10632 switch (cx) { /* Separate handling for IF and XIF */
10634 case XXASSER: /* And ASSERT */
10635 if ((x = cmcfm()) < 0)
10637 return(success = z);
10639 case XXIF: /* This is IF... */
10640 ifcmd[cmdlvl] = 1; /* We just completed an IF command */
10641 debug(F101,"doif condition","",z);
10642 if (z) { /* Condition is true */
10643 iftest[cmdlvl] = 1; /* Remember that IF succeeded */
10644 if (maclvl > -1) { /* In macro, */
10645 pushcmd(NULL); /* save rest of command. */
10646 } else if (tlevel > -1) { /* In take file, */
10647 debug(F100, "doif: pushing command", "", 0);
10648 pushcmd(NULL); /* save rest of command. */
10649 } else { /* If interactive, */
10650 cmini(ckxech); /* just start a new command */
10651 printf("\n"); /* (like in MS-DOS Kermit) */
10652 if (pflag) prompt(xxstring);
10654 } else { /* Condition is false */
10655 iftest[cmdlvl] = 0; /* Remember command failed. */
10656 if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
10657 return(y); /* Gobble up rest of line */
10661 case XXIFX: { /* This is XIF (Extended IF) */
10665 if ((y = cmtxt("Object command","",&s,NULL)) < 0)
10666 return(y); /* Get object command. */
10669 debug(F110,"doif THEN part",s,-54);
10670 if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
10673 debug(F111,"doif THEN part 2",line,z);
10675 while (*p == SP) p++; /* Strip trailing spaces */
10676 ifcmd[cmdlvl] = 0; /* Assume ELSE part in same line */
10677 iftest[cmdlvl] = z ? 1 : 0;
10678 if (*p) { /* At end? */
10679 if (!z) { /* No, use ELSE-part, if any */
10680 for (i = 0; i < 4; i++) e[i] = *p++;
10681 if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
10682 return(-2); /* Something else - error. */
10683 debug(F010,"doif ELSE line 1",p,0);
10684 while (*p == SP) p++; /* Skip spaces */
10685 if (*p != '{') { /* Brace ELSE part if necessary */
10686 ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL);
10688 debug(F010,"doif ELSE line 2",p,0);
10690 lp = line; /* Write over THEN part... */
10691 *lp = NUL; /* with ELSE part. */
10692 if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
10695 while (*p == SP) p++; /* Strip trailing spaces */
10696 if (*p) return(-2); /* Should be nothing here. */
10697 debug(F010,"doif ELSE line 3",line,0);
10699 } else { /* At end, treat like an IF command */
10700 if (!z) line[0] = NUL; /* Condition not true and no ELSE */
10701 ifcmd[cmdlvl] = 1; /* Allow ELSE on next line */
10702 debug(F101,"IF condition","",z);
10705 x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
10706 if (x < 0) { /* Not there? */
10707 addmmac("_xif",xif_def); /* Put it back. */
10708 if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
10709 printf("?XIF macro gone!\n");
10710 return(success = 0);
10713 dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
10717 case XXWHI: { /* WHILE Command */
10718 p = cmdbuf; /* Capture IF condition */
10719 ifcond[0] = NUL; /* from command buffer */
10720 while (*p == SP) p++;
10721 while (*p != SP) p++;
10723 ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN);
10726 This doesn't work because it breaks on the first left brace, which does
10727 not necessarily start the command list, e.g. "while equal \%a {\35}".
10729 while (*p != '{' && *p != NUL) *ifcp++ = *p++;
10730 p = " ) goto _..bot) } ";
10731 while (*ifcp++ = *p++) ;
10734 The command parser sets cmbptr to the spot where it left off parsing in
10735 the command buffer.
10738 extern char * cmbptr;
10740 while (p < cmbptr && *p != NUL)
10742 p = " ) goto _..bot) } ";
10743 while ((*ifcp++ = *p++)) ;
10745 printf("?Internal error parsing WHILE condition\n");
10749 #endif /* COMMENT */
10751 debug(F110,"WHILE cmd",ifcond,0);
10753 if ((y = cmtxt("Object command","",&s,NULL)) < 0)
10754 return(y); /* Get object command. */
10757 if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
10760 debug(F101,"WHILE body",line,-54);
10763 x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
10764 if (x < 0) { /* Not there? */
10765 addmmac("_while",whil_def); /* Put it back. */
10766 if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
10767 printf("?WHILE macro definition gone!\n");
10768 return(success = 0);
10771 p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
10773 strcpy(p,ifcond); /* safe (prechecked) */
10774 strcat(p,line); /* safe (prechecked) */
10775 debug(F010,"WHILE dodo",p,0);
10776 dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
10780 printf("?Can't allocate storage for WHILE command");
10781 return(success = 0);
10792 /* Set up a TAKE command file */
10795 dotake(s) char *s; {
10797 extern int tra_cmd;
10801 extern int term_io;
10802 int term_io_sav = term_io;
10804 #endif /* NOLOCAL */
10807 debug(F110,"dotake",s,0);
10809 if (!*s) return(success = 0);
10811 debug(F101,"dotake len","",slen);
10813 if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
10815 debug(F110,"dotake fail",s,0);
10817 return(success = 0);
10819 tfline[tlevel] = 0; /* Line counter */
10821 conres(); /* So Ctrl-C will work */
10825 term_io = 0; /* Disable Terminal Emulator I/O */
10827 #endif /* NOLOCAL */
10829 cmdlvl++; /* Entering a new command level */
10830 debug(F111,"CMD +F",s,cmdlvl);
10831 debug(F101,"dotake cmdlvl","",cmdlvl);
10832 debug(F101,"dotake tlevel","",tlevel);
10833 if (cmdlvl > CMDSTKL) {
10834 debug(F100,"dotake stack overflow","",0);
10836 debug(F111,"CMD*-F",s,cmdlvl);
10837 fclose(tfile[tlevel--]);
10838 printf("?TAKE files and/or DO commands nested too deeply\n");
10839 return(success = 0);
10841 if (tfnam[tlevel]) { /* Copy the filename */
10842 free(tfnam[tlevel]);
10843 tfnam[tlevel] = NULL;
10845 if ((tfnam[tlevel] = malloc(strlen(s) + 1))) {
10846 strcpy(tfnam[tlevel],s); /* safe */
10848 printf("?Memory allocation failure\n");
10849 return(success = 0);
10851 ifcmd[cmdlvl] = 0; /* Set variables for this cmd file */
10852 iftest[cmdlvl] = 0;
10853 count[cmdlvl] = count[cmdlvl-1]; /* Inherit this */
10854 intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
10855 inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
10856 takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
10857 merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
10858 xquiet[cmdlvl] = quiet;
10860 cmdstk[cmdlvl].src = CMD_TF; /* Say we're in a TAKE file */
10861 cmdstk[cmdlvl].lvl = tlevel; /* nested at this level */
10862 cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
10864 takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
10869 printf("[%d] +F: \"%s\"\n",cmdlvl,s);
10873 term_io = term_io_sav;
10875 #endif /* NOLOCAL */