6 Frank da Cruz <fdc@columbia.edu>,
7 The Kermit Project, Columbia University, New York City
8 Jeffrey E Altman <jaltman@secure-endpoints.com>
9 Secure Endpoints Inc., New York City
11 Copyright (C) 1985, 2011,
12 Trustees of Columbia University in the City of New York.
13 All rights reserved. See the C-Kermit COPYING.TXT file or the
14 copyright text in the ckcmai.c module for disclaimer and permissions.
24 #include "ckcnet.h" /* Network symbols */
29 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
33 #endif /* def VMS [else] */
39 #endif /* TCPSOCKET */
43 #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
44 #endif /* datageneral */
47 #define readblock kreadblock
50 /* External Kermit Variables, see ckmain.c for description. */
52 extern xx_strp xxstring;
54 extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
55 turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
56 zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive;
58 extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive,
59 xcmdsrc, nscanfile, reliable, nolinks, cmflgs;
62 extern int zgfs_dir, zgfs_link;
63 #endif /* VMSORUNIX */
70 extern int StartedFromDialer ;
75 #define INCL_VIO /* Needed for ckocon.h */
87 extern long vernum, speed;
88 extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
89 extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
90 extern char *foz_def[];
91 extern char *ckxsys, *ckzsys;
98 extern char ttname[], filnam[];
99 extern CHAR sstate, feol;
103 extern char ** mtchs; /* zxpand() file list */
107 extern int oopts, omode, oname, opath; /* O-Packet options */
109 extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
110 stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
111 atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
112 fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
113 g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
114 g_fnspath, g_fnrpath, xfrxla, g_xfrxla;
116 extern char *cmarg, *cmarg2;
118 #ifndef NOMSEND /* Multiple SEND */
119 extern char *msfiles[];
121 extern char fspec[]; /* Most recent filespec */
125 extern int f_tmpdir; /* Directory changed temporarily */
126 extern char savdir[]; /* For saving current directory */
127 #endif /* CK_TMPDIR */
129 extern struct keytab protos[]; /* File transfer protocols */
130 extern struct ck_p ptab[NPROTOS];
133 #ifdef DCMDBUF /* Declarations from cmd package */
134 extern char *cmdbuf, *atmbuf; /* Command buffers */
136 extern char cmdbuf[], atmbuf[]; /* Command buffers */
142 int askflag = 0; /* ASK-class command active */
143 int echostars = 0; /* ASKQ should echo asterisks */
144 extern char **a_ptr[];
146 extern char **m_xarg[];
148 extern struct mtab *mactab;
150 extern long ck_alarm;
151 extern char alrm_date[], alrm_time[];
155 extern int inserver; /* I am IKSD */
156 extern int backgrd; /* Kermit executing in background */
157 extern char psave[]; /* For saving & restoring prompt */
158 extern char *tp; /* Temporary buffer */
160 int readblock = 4096; /* READ buffer size */
161 CHAR * readbuf = NULL; /* Pointer to read buffer */
162 int readsize = 0; /* Number of chars actually read */
163 int getcmd = 0; /* GET-class command was given */
165 extern int zchkod, zchkid;
167 /* C K U U S 6 -- "User Interface" for Unix Kermit (Part 6) */
169 struct keytab deltab[] = { /* DELETE Command Options */
170 { "/all", DEL_ALL, CM_INV },
171 { "/after", DEL_AFT, CM_ARG },
172 { "/ask", DEL_ASK, 0 },
173 { "/before", DEL_BEF, CM_ARG },
174 { "/directories", DEL_DIR, 0 },
175 { "/dotfiles", DEL_DOT, 0 },
176 { "/except", DEL_EXC, CM_ARG },
177 { "/heading", DEL_HDG, 0 },
178 { "/l", DEL_LIS, CM_INV|CM_ABR },
179 { "/larger-than", DEL_LAR, CM_ARG },
180 { "/list", DEL_LIS, 0 },
181 { "/log", DEL_LIS, CM_INV },
182 { "/noask", DEL_NAS, 0 },
183 { "/nodotfiles", DEL_NOD, 0 },
184 { "/noheading", DEL_NOH, 0 },
185 { "/nol", DEL_NOL, CM_INV|CM_ABR },
186 { "/nolist", DEL_NOL, 0 },
187 { "/nolog", DEL_NOL, CM_INV },
188 { "/nopage", DEL_NOP, 0 },
189 { "/not-after", DEL_NAF, CM_ARG },
190 { "/not-before", DEL_NBF, CM_ARG },
191 { "/not-since", DEL_NAF, CM_INV|CM_ARG },
192 { "/page", DEL_PAG, 0 },
193 { "/quiet", DEL_QUI, CM_INV },
194 { "/recursive", DEL_REC, 0 },
195 { "/simulate", DEL_SIM, 0 },
196 { "/since", DEL_AFT, CM_ARG|CM_INV },
197 { "/smaller-than", DEL_SMA, CM_ARG },
198 { "/summary", DEL_SUM, 0 },
199 { "/tree", DEL_ALL, 0 },
200 { "/type", DEL_TYP, CM_ARG },
201 { "/verbose", DEL_VRB, CM_INV }
203 int ndeltab = sizeof(deltab)/sizeof(struct keytab);
205 /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
207 struct keytab qvswtab[] = {
208 { "/l", DEL_LIS, CM_INV|CM_ABR },
209 { "/list", DEL_LIS, 0 },
210 { "/log", DEL_LIS, CM_INV },
211 { "/nol", DEL_NOL, CM_INV|CM_ABR },
212 { "/nolist", DEL_NOL, 0 },
213 { "/nolog", DEL_NOL, CM_INV },
214 { "/quiet", DEL_QUI, CM_INV },
215 { "/verbose", DEL_VRB, CM_INV }
217 int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
219 static struct keytab renamsw[] = {
220 { "/collision", REN_OVW, CM_ARG },
222 { "/convert", REN_XLA, CM_ARG },
223 #endif /* NOUNICODE */
224 { "/fixspaces", REN_SPA, CM_ARG },
225 { "/l", DEL_LIS, CM_INV|CM_ABR },
226 { "/list", DEL_LIS, 0 },
227 { "/log", DEL_LIS, CM_INV },
228 { "/lower", REN_LOW, CM_ARG },
229 { "/nol", DEL_NOL, CM_INV|CM_ABR },
230 { "/nolist", DEL_NOL, 0 },
231 { "/nolog", DEL_NOL, CM_INV },
232 { "/quiet", DEL_QUI, CM_INV },
233 { "/replace", REN_RPL, CM_ARG },
234 { "/simulate", DEL_SIM, 0 },
235 { "/upper", REN_UPP, CM_ARG },
236 { "/verbose", DEL_VRB, CM_INV }
238 static int nrenamsw = sizeof(renamsw)/sizeof(struct keytab);
240 static struct keytab renamset[] = {
241 { "collision", REN_OVW, 0 },
242 { "list", DEL_LIS, 0 }
244 static int nrenamset = sizeof(renamset)/sizeof(struct keytab);
246 /* Args for RENAME /LOWER: and /UPPER: */
248 static struct keytab r_upper[] = {
253 static struct keytab r_lower[] = {
258 /* Args for RENAME /COLLISION... */
264 static struct keytab r_collision[] = {
265 { "fail", RENX_FAIL, 0 },
266 { "overwrite", RENX_OVWR, 0 },
267 { "proceed", RENX_SKIP, CM_INV },
268 { "skip", RENX_SKIP, 0 }
270 static int nr_collision = sizeof(r_collision)/sizeof(struct keytab);
272 struct keytab copytab[] = {
273 { "/append", 998, 0 },
275 { "/fromb64", 997, 0 },
277 { "/l", DEL_LIS, CM_INV|CM_ABR },
278 { "/list", DEL_LIS, 0 },
279 { "/log", DEL_LIS, CM_INV },
280 { "/nol", DEL_NOL, CM_INV|CM_ABR },
281 { "/nolist", DEL_NOL, 0 },
282 { "/nolog", DEL_NOL, CM_INV },
283 { "/overwrite", 994, CM_ARG },
285 { "/preserve", 995, 0 },
287 { "/quiet", DEL_QUI, CM_INV },
288 { "/swap-bytes", 999, 0 },
290 { "/tob64", 996, 0 },
292 { "/verbose", DEL_VRB, CM_INV }
294 int ncopytab = sizeof(copytab)/sizeof(struct keytab);
301 static struct keytab ovwtab[] = {
302 { "always", OVW_ALWAYS, 0 },
303 { "never", OVW_NEVER, 0 },
304 { "newer", OVW_NEWER, 0 },
305 { "older", OVW_OLDER, 0 }
307 static int novwtab = 4;
310 static struct keytab gettab[] = { /* GET options */
311 { "/as-name", SND_ASN, CM_ARG },
312 { "/binary", SND_BIN, 0 },
314 { "/calibrate", SND_CAL, CM_INV },
315 #endif /* CALIBRATE */
317 { "/command", SND_CMD, CM_PSH },
318 #endif /* PIPESEND */
319 { "/delete", SND_DEL, 0 },
320 { "/except", SND_EXC, CM_ARG },
321 { "/filenames", SND_NAM, CM_ARG },
323 { "/filter", SND_FLT, CM_ARG|CM_PSH },
324 #endif /* PIPESEND */
326 { "/image", SND_IMG, 0 },
327 { "/labeled", SND_LBL, 0 },
329 { "/image", SND_BIN, CM_INV },
332 { "/move-to", SND_MOV, CM_ARG },
333 #endif /* CK_TMPDIR */
334 { "/pathnames", SND_PTH, CM_ARG },
335 { "/pipes", SND_PIP, CM_ARG|CM_PSH },
336 { "/quiet", SND_SHH, 0 },
338 { "/recover", SND_RES, 0 },
339 #endif /* CK_RESEND */
340 { "/recursive", SND_REC, 0 },
341 { "/rename-to", SND_REN, CM_ARG },
343 { "/smaller-than", SND_SMA, CM_ARG },
345 { "/subdirectories", SND_REC, CM_INV },
346 { "/text", SND_TXT, 0 },
347 { "/transparent", SND_XPA, 0 }
349 #define NGETTAB sizeof(gettab)/sizeof(struct keytab)
350 static int ngettab = NGETTAB;
352 static struct keytab rcvtab[] = { /* RECEIVE options */
353 { "/as-name", SND_ASN, CM_ARG },
354 { "/binary", SND_BIN, 0 },
356 { "/calibrate", SND_CAL, CM_INV },
357 #endif /* CALIBRATE */
359 { "/command", SND_CMD, CM_PSH },
360 #endif /* PIPESEND */
361 { "/except", SND_EXC, CM_ARG },
362 { "/filenames", SND_NAM, CM_ARG },
364 { "/filter", SND_FLT, CM_ARG|CM_PSH },
365 #endif /* PIPESEND */
367 { "/image", SND_IMG, 0 },
368 { "/labeled", SND_LBL, 0 },
370 { "/image", SND_BIN, CM_INV },
373 { "/move-to", SND_MOV, CM_ARG },
374 #endif /* CK_TMPDIR */
375 { "/pathnames", SND_PTH, CM_ARG },
376 { "/pipes", SND_PIP, CM_ARG|CM_PSH },
378 { "/protocol", SND_PRO, CM_ARG },
380 { "/protocol", SND_PRO, CM_ARG|CM_INV },
382 { "/quiet", SND_SHH, 0 },
383 { "/recursive", SND_REC, 0 },
384 { "/rename-to", SND_REN, CM_ARG },
385 { "/text", SND_TXT, 0 },
386 { "/transparent", SND_XPA, 0 }
388 #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
389 static int nrcvtab = NRCVTAB;
397 struct keytab waittab[] = {
398 { "cd", BM_DCD, CM_INV }, /* (Carrier Detect) */
399 { "cts", BM_CTS, CM_INV }, /* (Clear To Send) */
400 { "dsr", BM_DSR, CM_INV }, /* (Data Set Ready) */
401 { "file", WAIT_FIL, 0 }, /* New category selector keywords */
402 { "modem-signals", WAIT_MDM, 0 }, /* ... */
403 { "ri", BM_RNG, CM_INV } /* (Ring Indicator) */
405 int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
407 /* Modem signal table */
409 struct keytab mstab[] = {
410 { "cd", BM_DCD, 0 }, /* Carrier Detect */
411 { "cts", BM_CTS, 0 }, /* Clear To Send */
412 { "dsr", BM_DSR, 0 }, /* Data Set Ready */
413 { "ri", BM_RNG, 0 } /* Ring Indicator */
415 int nms = (sizeof(mstab) / sizeof(struct keytab));
421 struct keytab wfswi[] = { /* WAIT FILE switches */
422 { "creation", WF_CRE, 0 }, /* Wait for file to be created */
423 { "deletion", WF_DEL, 0 }, /* Wait for file to be deleted */
424 { "modification", WF_MOD, 0 } /* Wait for file to be modified */
426 int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
429 struct keytab asgtab[] = { /* Assignment operators for "." */
430 { "::=", 2, 0 }, /* ASSIGN and EVALUATE */
431 { ":=", 1, 0 }, /* ASSIGN */
432 { "=", 0, 0 } /* DEFINE */
434 int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
436 struct keytab opntab[] = {
438 { "!read", OPN_PI_R, CM_INV },
439 { "!write", OPN_PI_W, CM_INV },
441 { "append", OPN_FI_A, 0 },
442 { "host", OPN_NET, 0 },
444 { "line", OPN_SER, CM_INV },
445 { "port", OPN_SER, 0 },
447 { "line", OPN_SER, 0 },
448 { "port", OPN_SER, CM_INV },
450 { "read", OPN_FI_R, 0 },
451 { "write", OPN_FI_W, 0 }
453 int nopn = (sizeof(opntab) / sizeof(struct keytab));
457 #define XXIFCO 0 /* IF COUNT */
458 #define XXIFER 1 /* IF ERRORLEVEL */
459 #define XXIFEX 2 /* IF EXIST */
460 #define XXIFFA 3 /* IF FAILURE */
461 #define XXIFSU 4 /* IF SUCCESS */
462 #define XXIFNO 5 /* IF NOT */
463 #define XXIFDE 6 /* IF DEFINED */
464 #define XXIFEQ 7 /* IF EQUAL (strings) */
465 #define XXIFAE 8 /* IF = (numbers) */
466 #define XXIFLT 9 /* IF < (numbers) */
467 #define XXIFGT 10 /* IF > (numbers) */
468 #define XXIFLL 11 /* IF Lexically Less Than (strings) */
469 #define XXIFLG 12 /* IF Lexically Greater Than (strings) */
470 #define XXIFEO 13 /* IF EOF (READ file) */
471 #define XXIFBG 14 /* IF BACKGROUND */
472 #define XXIFNU 15 /* IF NUMERIC */
473 #define XXIFFG 16 /* IF FOREGROUND */
474 #define XXIFDI 17 /* IF DIRECTORY */
475 #define XXIFNE 18 /* IF NEWER */
476 #define XXIFRO 19 /* IF REMOTE-ONLY */
477 #define XXIFAL 20 /* IF ALARM */
478 #define XXIFSD 21 /* IF STARTED-FROM-DIALER */
479 #define XXIFTR 22 /* IF TRUE */
480 #define XXIFNT 23 /* IF FALSE */
481 #define XXIFTM 24 /* IF TERMINAL-MACRO */
482 #define XXIFEM 25 /* IF EMULATION */
483 #define XXIFOP 26 /* IF OPEN */
484 #define XXIFLE 27 /* IF <= */
485 #define XXIFGE 28 /* IF >= */
486 #define XXIFIP 29 /* IF INPATH */
487 #define XXIFTA 30 /* IF TAPI */
488 #define XXIFMA 31 /* IF MATCH */
489 #define XXIFFL 32 /* IF FLAG */
490 #define XXIFAB 33 /* IF ABSOLUTE */
491 #define XXIFAV 34 /* IF AVAILABLE */
492 #define XXIFAT 35 /* IF ASKTIMEOUT */
493 #define XXIFRD 36 /* IF READABLE */
494 #define XXIFWR 37 /* IF WRITEABLE */
495 #define XXIFAN 38 /* IF ... AND ... */
496 #define XXIFOR 39 /* IF ... OR ... */
497 #define XXIFLP 40 /* IF left parenthesis */
498 #define XXIFRP 41 /* IF right parenthesis */
499 #define XXIFNQ 42 /* IF != (== "NOT =") */
500 #define XXIFQU 43 /* IF QUIET */
501 #define XXIFCK 44 /* IF C-KERMIT */
502 #define XXIFK9 45 /* IF K-95 */
503 #define XXIFMS 46 /* IF MS-KERMIT */
504 #define XXIFWI 47 /* IF WILD */
505 #define XXIFLO 48 /* IF LOCAL */
506 #define XXIFCM 49 /* IF COMMAND */
507 #define XXIFFP 50 /* IF FLOAT */
508 #define XXIFIK 51 /* IF IKS */
509 #define XXIFKB 52 /* IF KBHIT */
510 #define XXIFKG 53 /* IF KERBANG */
511 #define XXIFVE 54 /* IF VERSION */
512 #define XXIFDC 55 /* IF DECLARED */
513 #define XXIFGU 56 /* IF GUI */
514 #define XXIFLN 57 /* IF LINK */
515 #define XXIFDB 58 /* IF DEBUG */
517 struct keytab iftab[] = { /* IF commands */
526 { "==", XXIFAE, CM_INV },
529 { "absolute", XXIFAB, 0 },
530 { "alarm", XXIFAL, 0 },
531 { "and", XXIFAN, 0 },
532 { "asktimeout", XXIFAT, 0 },
533 { "available", XXIFAV, 0 },
534 { "background", XXIFBG, 0 },
535 { "c-kermit", XXIFCK, 0 },
536 { "command", XXIFCM, 0 },
537 { "count", XXIFCO, 0 },
538 { "dcl", XXIFDC, CM_INV },
539 { "debug", XXIFDB, 0 },
540 { "declared", XXIFDC, 0 },
541 { "defined", XXIFDE, 0 },
543 { "directory", XXIFDI, 0 },
544 #endif /* CK_TMPDIR */
545 { "emulation", XXIFEM, 0 },
547 { "eof", XXIFEO, 0 },
549 { "equal", XXIFEQ, 0 },
550 { "error", XXIFFA, CM_INV },
551 { "exist", XXIFEX, 0 },
552 { "failure", XXIFFA, 0 },
553 { "false", XXIFNT, 0 },
554 { "flag", XXIFFL, 0 },
556 { "float", XXIFFP, 0 },
558 { "foreground", XXIFFG, 0 },
560 { "gui", XXIFGU, 0 },
562 { "gui", XXIFGU, CM_INV },
565 { "iksd", XXIFIK, 0 },
567 { "iksd", XXIFIK, CM_INV },
569 { "integer", XXIFNU, CM_INV },
570 { "k-95", XXIFK9, 0 },
571 { "kbhit", XXIFKB, 0 },
573 { "kerbang", XXIFKG, 0 },
575 { "kerbang", XXIFKG, CM_INV },
577 { "lgt", XXIFLG, 0 },
579 { "link", XXIFLN, 0 },
581 { "llt", XXIFLL, 0 },
582 { "local", XXIFLO, 0 },
583 { "match", XXIFMA, 0 },
584 { "ms-kermit", XXIFMS, CM_INV },
586 { "newer", XXIFNE, 0 },
588 { "not", XXIFNO, 0 },
589 { "numeric", XXIFNU, 0 },
590 { "ok", XXIFSU, CM_INV },
591 { "open", XXIFOP, 0 },
593 { "quiet", XXIFQU, 0 },
594 { "readable", XXIFRD, 0 },
595 { "remote-only",XXIFRO, 0 },
596 { "started-from-dialer",XXIFSD, CM_INV },
597 { "success", XXIFSU, 0 },
598 { "tapi", XXIFTA, 0 },
600 { "terminal-macro", XXIFTM, 0 },
602 { "terminal-macro", XXIFTM, CM_INV },
604 { "true", XXIFTR, 0 },
605 { "version", XXIFVE, 0 },
606 { "wild", XXIFWI, 0 },
607 { "writeable", XXIFWR, 0 },
611 int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
613 struct keytab iotab[] = { /* Keywords for IF OPEN */
614 { "!read-file", ZRFILE, CM_INV },
615 { "!write-file", ZWFILE, CM_INV },
616 { "append-file", ZWFILE, CM_INV },
617 { "connection", 8888, 0 },
619 { "cx-log", 7777, 0 },
620 #endif /* CKLOGDIAL */
621 { "debug-log", ZDFILE, 0 },
622 { "error", 9999, 0 },
623 { "packet-log", ZPFILE, 0 },
624 { "read-file", ZRFILE, 0 },
625 { "screen", ZSTDIO, 0 },
626 { "session-log", ZSFILE, 0 },
627 { "transaction-log", ZTFILE, 0 },
628 { "write-file", ZWFILE, 0 }
630 int niot = (sizeof(iotab) / sizeof(struct keytab));
633 /* Variables and prototypes */
635 _PROTOTYP(static int doymdir,(int));
636 _PROTOTYP(static int renameone,(char *,char *,
637 int,int,int,int,int,int,int,int,int,int,int));
640 extern int nnetdir; /* How many network directories */
643 _PROTOTYP(int ck_krb4_is_installed,(void));
644 _PROTOTYP(int ck_krb5_is_installed,(void));
645 _PROTOTYP(int ck_ntlm_is_installed,(void));
646 _PROTOTYP(int ck_srp_is_installed,(void));
647 _PROTOTYP(int ck_ssleay_is_installed,(void));
648 _PROTOTYP(int ck_ssh_is_installed,(void));
649 _PROTOTYP(int ck_crypt_is_installed,(void));
651 #define ck_krb4_is_installed() (0)
652 #define ck_krb5_is_installed() (0)
653 #define ck_ntlm_is_installed() (0)
654 #define ck_srp_is_installed() (0)
655 #define ck_ssleay_is_installed() (0)
656 #define ck_ssh_is_installed() (0)
657 #define ck_crypt_is_installed() (0)
658 #endif /* CK_SECURITY */
668 struct keytab availtab[] = { /* Available authentication types */
669 { "crypto", AV_CRYPTO, CM_INV }, /* and encryption */
670 { "encryption", AV_CRYPTO, 0 },
671 { "k4", AV_KRB4, CM_INV },
672 { "k5", AV_KRB5, CM_INV },
673 { "kerberos4", AV_KRB4, 0 },
674 { "kerberos5", AV_KRB5, 0 },
675 { "krb4", AV_KRB4, CM_INV },
676 { "krb5", AV_KRB5, CM_INV },
677 { "ntlm", AV_NTLM, 0 },
678 { "srp", AV_SRP, 0 },
679 { "ssh", AV_SSH, 0 },
680 { "ssl", AV_SSL, 0 },
681 { "tls", AV_SSL, 0 },
684 int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
687 _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
688 _PROTOTYP(static int dncvt, (int, int, int, int) );
689 _PROTOTYP(char * getdname, (void) );
691 static int partial = 0; /* For partial dial */
692 static char *dscopy = NULL;
695 char *dialnum = (char *)0; /* Remember DIAL number for REDIAL */
696 int dirline = 0; /* Dial directory line number */
697 extern char * dialdir[]; /* Dial directory file names */
698 extern int dialdpy; /* DIAL DISPLAY on/off */
699 extern int ndialdir; /* How many dial directories */
700 extern int ntollfree; /* Toll-free call info */
701 extern int ndialpxx; /* List of PBX exchanges */
702 extern char *dialtfc[];
703 char * matchpxx = NULL; /* PBX exchange that matched */
704 extern int nlocalac; /* Local area-code list */
705 extern char * diallcac[];
708 extern int tapiconv; /* TAPI Conversions */
709 extern int tapipass; /* TAPI Passthrough */
712 extern char * dialnpr, * dialsfx;
713 extern char * dialixp, * dialixs, * dialmac;
714 extern char * dialldp, * diallds, * dialtfp;
715 extern char * dialpxi, * dialpxo, * diallac;
716 extern char * diallcp, * diallcs, * diallcc;
717 extern char * dialpxx[];
719 extern int dialcnf; /* DIAL CONFIRMATION */
720 int dialfld = 0; /* DIAL FORCE-LONG-DISTANCE */
721 int dialsrt = 1; /* DIAL SORT ON */
722 int dialrstr = 6; /* DIAL RESTRICTION */
723 int dialtest = 0; /* DIAL TEST */
724 int dialcount = 0; /* \v(dialcount) */
726 extern int dialsta; /* Dial status */
727 int dialrtr = -1, /* Dial retries */
728 dialint = 10; /* Dial retry interval */
729 extern long dialcapas; /* Modem capabilities */
730 extern int dialcvt; /* DIAL CONVERT-DIRECTORY */
734 #define IFCONDLEN 256
735 int ifc, /* IF case */
736 not = 0, /* Flag for IF NOT */
737 ifargs = 0; /* Count of IF condition words */
738 char ifcond[IFCONDLEN]; /* IF condition text */
739 char *ifcp; /* Pointer to IF condition text */
743 *ifcmd, *count, *iftest, *intime,
744 *inpcas, *takerr, *merror, *xquiet, *xvarev;
746 extern int ifcmd[]; /* Last command was IF */
747 extern int iftest[]; /* Last IF was true */
748 extern int count[]; /* For IF COUNT, one for each cmdlvl */
749 extern int intime[]; /* Ditto for other stackables... */
761 extern char *line; /* Character buffer for anything */
764 extern char line[], tmpbuf[];
766 extern char *lp; /* Pointer to line buffer */
768 int cwdf = 0; /* CWD has been done */
770 /* Flags for ENABLE/DISABLE */
771 extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
772 en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
773 en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
775 extern FILE *tfile[]; /* File pointers for TAKE command */
776 extern char *tfnam[]; /* Names of TAKE files */
777 extern int tfline[]; /* TAKE-file line number */
779 extern int success; /* Command success/failure flag */
780 extern int cmdlvl; /* Current position in command stack */
783 extern int maclvl; /* Macro to execute */
784 extern char *macx[]; /* Index of current macro */
785 extern char *mrval[]; /* Macro return value */
786 extern char *macp[]; /* Pointer to macro */
787 extern int macargc[]; /* ARGC from macro invocation */
790 extern char *m_line[];
793 extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */
794 extern char *g_var[]; /* Global variables %a, %b, etc */
797 extern struct cmdptr *cmdstk; /* The command stack itself */
799 extern struct cmdptr cmdstk[]; /* The command stack itself */
803 #define xsystem(s) zsyscmd(s)
805 static int x, y, z = 0;
809 _PROTOTYP( int os2settitle, (char *, int) );
812 extern struct keytab yesno[], onoff[], fntab[];
813 extern int nyesno, nfntab;
817 /* Do the ASK, ASKQ, GETOK, and READ commands */
828 static struct keytab asktab[] = {
829 { "/default", ASK_DEF, CM_ARG },
844 { "/quiet", ASK_QUI, 0 },
845 { "/timeout", ASK_TMO, CM_ARG },
848 static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1;
850 static struct keytab askqtab[] = {
851 { "/default", ASK_DEF, CM_ARG },
852 { "/echo", ASK_ECH, CM_ARG },
860 { "/noecho", ASK_QUI, CM_INV },
868 { "/quiet", ASK_QUI, 0 },
869 { "/timeout", ASK_TMO, CM_ARG },
872 static int naskqtab = sizeof(askqtab)/sizeof(struct keytab)-1;
876 extern int asktimer, timelimit;
878 extern int on_recall;
879 #endif /* CK_RECALL */
886 extern int apcactive, apcstatus;
889 char dfbuf[1024]; /* Buffer for default answer */
890 char * dfanswer = NULL; /* Pointer to it */
892 char vnambuf[VNAML+1]; /* Buffer for variable names */
893 char *vnp = NULL; /* Pointer to same */
899 if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
904 mytimer = asktimer; /* Inherit global ASK timer */
905 echostars = 0; /* For ASKQ */
907 if (cx == XXASK || cx == XXASKQ) {
911 if (cx == XXASKQ) /* Don't log ASKQ response */
913 cmfdbi(&sw, /* First FDB - command switches */
915 "Variable name or switch",
917 "", /* addtl string data */
918 ((cx == XXASK) ? nasktab : naskqtab), /* Table size */
919 4, /* addtl numeric data 2: 4 = cmswi */
920 xxstring, /* Processing function */
921 ((cx == XXASK) ? asktab : askqtab), /* Keyword table */
922 &fl /* Pointer to next FDB */
924 cmfdbi(&fl, /* Anything that doesn't match */
928 "", /* addtl string data */
929 0, /* addtl numeric data 1 */
930 0, /* addtl numeric data 2 */
935 while (1) { /* Parse 0 or more switches */
936 x = cmfdb(&sw); /* Parse something */
939 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
942 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
943 printf("?This switch does not take an argument\n");
946 if (!getval && (cmgkwflgs() & CM_ARG)) {
947 printf("?This switch requires an argument\n");
950 switch (cmresult.nresult) {
963 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
971 if ((y = cmfld("Character to echo","*",&s,xxstring)) < 0)
977 if ((y = cmfld("Text to supply if reply is empty",
978 "",&s,xxstring)) < 0)
980 ckstrncpy(dfbuf,s,1024);
987 /* Have variable name, make copy. */
988 ckstrncpy(vnambuf,cmresult.sresult,VNAML);
990 if (vnambuf[0] == CMDQ &&
991 (vnambuf[1] == '%' || vnambuf[1] == '&'))
994 if (*vnp == '%' || *vnp == '&') {
995 if ((y = parsevar(vnp,&x,&z)) < 0)
998 } else if (cx != XXGOK && cx != XXRDBL) { /* Get variable name */
999 if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
1001 printf("?Variable name required\n");
1005 ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */
1007 if (vnambuf[0] == CMDQ &&
1008 (vnambuf[1] == '%' || vnambuf[1] == '&'))
1011 if (*vnp == '%' || *vnp == '&') {
1012 if ((y = parsevar(vnp,&x,&z)) < 0)
1016 if (cx == XXREA || cx == XXRDBL) { /* READ or READBLOCK command */
1017 if ((y = cmcfm()) < 0) /* Get confirmation */
1019 if (chkfn(ZRFILE) < 1) { /* File open? */
1020 printf("?Read file not open\n");
1021 return(success = 0);
1023 if (!(s = (char *)readbuf)) { /* Where to read into. */
1024 printf("?Oops, no READ buffer!\n");
1025 return(success = 0);
1027 y = zsinl(ZRFILE, s, readblock); /* Read a line. */
1028 debug(F111,"read zsinl",s,y);
1029 if (y < 0) { /* On EOF or other error, */
1030 zclose(ZRFILE); /* close the file, */
1031 delmac(vnp,0); /* delete the variable, */
1032 return(success = 0); /* and return failure. */
1033 } else { /* Read was OK. */
1034 readsize = (int) strlen(s);
1035 success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
1036 debug(F111,"read addmac",vnp,success);
1037 return(success); /* Return success. */
1041 /* ASK, ASKQ, GETOK, or GETC */
1043 if (cx == XXGOK) { /* GETOK can take switches */
1047 cmfdbi(&sw, /* First FDB - command switches */
1049 "Variable name or question prompt",
1051 "", /* addtl string data */
1052 nasktab, /* addtl numeric data 1: tbl size */
1053 4, /* addtl numeric data 2: 4 = cmswi */
1054 xxstring, /* Processing function */
1055 asktab, /* Keyword table */
1056 &fl /* Pointer to next FDB */
1058 cmfdbi(&fl, /* Anything that doesn't match */
1062 "", /* addtl string data */
1063 0, /* addtl numeric data 1 */
1064 0, /* addtl numeric data 2 */
1069 while (1) { /* Parse 0 or more switches */
1070 x = cmfdb(&sw); /* Parse something */
1073 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
1076 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1077 printf("?This switch does not take an argument\n");
1080 if (!getval && (cmgkwflgs() & CM_ARG)) {
1081 printf("?This switch requires an argument\n");
1084 switch (cmresult.nresult) {
1092 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
1100 if ((y = cmfld("Text to supply if reply is empty",
1101 "",&s,xxstring)) < 0)
1103 ckstrncpy(dfbuf,s,1024);
1110 default: return(-2);
1113 p = cmresult.sresult;
1117 enclose in { braces } or \" quotes \" to preserve leading and trailing\n\
1118 spaces, precede question mark with backslash (\\).",
1119 "",&p,xxstring)) < 0)
1125 if (popupflg) { /* Popup requested */
1127 ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
1129 if (cx == XXASK || cx == XXASKQ) {
1131 len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1133 len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1134 asktimedout = ( len < 0 && mytimer );
1135 } else if (cx == XXGOK) {
1136 printf("?Sorry, GETOK /POPUP not implemented yet\n");
1141 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1142 } else if ( asktimedout && dfanswer ) {
1143 y = addmac(vnp,dfanswer); /* Add it to the macro table. */
1148 return(success = ((len >= 0) && (y >= 0)) && !asktimedout);
1151 if (guiflg) { /* GUI requested */
1156 zzstring(brstrip(p),&s1,&n);
1158 if (cx == XXASK || cx == XXASKQ) {
1159 rc = gui_txt_dialog(NULL,p,(cx == XXASK),
1160 line,LINBUFSIZ,dfanswer,mytimer);
1161 asktimedout = (rc == -1 && mytimer);
1163 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1164 } else if ( asktimedout && dfanswer ) {
1165 y = addmac(vnp,dfanswer); /* Add default to macro table. */
1170 return(success = (rc == 1 && (y >= 0)) && !asktimedout);
1171 } else if (cx == XXGOK) {
1173 x = lookup(yesno,dfanswer,nyesno,NULL);
1175 rc = uq_ok(NULL, p, 3, NULL, x);
1176 return(success = (rc == 1));
1181 #endif /* NOLOCAL */
1183 concb((char)escape); /* Enter CBREAK mode */
1184 cmsavp(psave,PROMPTL); /* Save old prompt */
1185 cmsetp(brstrip(p)); /* Make new prompt */
1188 if (cx == XXASKQ) { /* For ASKQ, */
1189 cmini(0); /* no-echo mode. */
1191 echostars = echochar;
1192 } else { /* For others, regular echoing. */
1197 x = -1; /* This means to reparse. */
1200 prompt(xxstring); /* Issue prompt. */
1202 asktimedout = 0; /* Handle timed responses. */
1203 timelimit = mytimer;
1206 if (cx == XXGOK) { /* GETOK */
1209 #endif /* CK_RECALL */
1211 /* GETOK uses keyword table */
1212 x = cmkey(yesno,nyesno,"",dfanswer,xxstring);
1213 if (x < 0) { /* Parse error */
1216 ds = dfanswer ? dfanswer : "No";
1218 printf("?Timed out, assuming \"%s\"",ds);
1221 x = lookup(yesno,ds,nyesno,NULL);
1224 } else if (x == -3) { /* No answer? */
1225 printf("Please respond Yes or No\n"); /* Make them answer */
1228 } else if (x == -1) {
1233 if (cmcfm() < 0) /* Get confirmation */
1237 cmsetp(psave); /* Restore prompt */
1239 if (cmdlvl > 0) /* In VMS and not at top level, */
1240 conres(); /* restore console again. */
1243 return(x); /* Return success or failure */
1244 } else if (cx == XXGETC /* GETC */
1246 || cx == XXGETK /* or GETKEYCODE */
1250 conbin((char)escape); /* Put keyboard in raw mode */
1253 if (cx == XXGETK) { /* GETKEYCODE */
1256 t = os2gks; /* Turn off kverb recognition */
1258 x = congks(timelimit); /* Read a key event, blocking */
1259 os2gks = t; /* Put back kverb recognition */
1262 #endif /* NOSETKEY */
1264 debug(F101,"GETC conchk","",conchk());
1265 x = coninc(timelimit); /* Just read one character */
1266 debug(F101,"GETC coninc","",x);
1268 concb((char)escape); /* Put keyboard back in cbreak mode */
1273 if (cx == XXGETK) { /* GETKEYCODE */
1274 sprintf(tmp,"%d",x); /* SAFE */
1277 tmp[0] = (char) (x & 0xff);
1282 y = addmac(vnp,tmp); /* Add it to the macro table. */
1283 debug(F111,"getc/getk addmac",vnp,y);
1285 cmsetp(psave); /* Restore old prompt. */
1288 if (!quiet && !nomsg)
1289 printf("?Timed out");
1293 return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0)));
1294 } else { /* ASK or ASKQ */
1296 on_recall = 0; /* Don't put response in recall buf */
1297 #endif /* CK_RECALL */
1298 askflag = 1; /* ASK[Q] always goes to terminal */
1299 y = cmdgquo(); /* Get current quoting */
1300 cmdsquo(0); /* Turn off quoting */
1301 while (x == -1) { /* Prompt till they answer */
1302 x = cmtxt("Please respond.",dfanswer,&s,NULL);
1303 debug(F111,"ASK cmtxt",s,x);
1306 cmdsquo(y); /* Restore previous quoting */
1307 if (cx == XXASKQ) /* ASKQ must echo CRLF here */
1309 if (x == -10 && dfanswer) { /* Don't fail on timeout if */
1310 s = dfanswer; /* a default was specified */
1311 asktimedout = 0; /* and don't fail */
1314 if (x < 0) { /* If cmtxt parse error, */
1315 cmsetp(psave); /* restore original prompt */
1317 if (cmdlvl > 0) /* In VMS and not at top level, */
1318 conres(); /* restore console again. */
1320 if (x == -10) { /* Timed out with no response */
1322 printf("?Timed out");
1325 if (dfanswer) /* Supply default answer if any */
1327 success = x = 0; /* (was "x = -9;") */
1330 return(x); /* and return cmtxt's error code. */
1332 if (!s || *s == NUL) { /* If user typed a bare CR, */
1333 cmsetp(psave); /* Restore old prompt, */
1334 delmac(vnp,0); /* delete variable if it exists, */
1336 if (cmdlvl > 0) /* In VMS and not at top level, */
1337 conres(); /* restore console again. */
1340 return(success = 1); /* and return. */
1342 y = addmac(vnp,s); /* Add it to the macro table. */
1343 debug(F111,"ask addmac",vnp,y);
1344 cmsetp(psave); /* Restore old prompt. */
1346 if (cmdlvl > 0) /* In VMS and not at top level, */
1347 conres(); /* restore console again. */
1350 return(success = (y < 0 ? 0 : 1) && (asktimedout == 0));
1357 doincr(cx) int cx; { /* INCREMENT, DECREMENT */
1358 char vnambuf[VNAML+1]; /* Buffer for variable names */
1361 eval = (cx == XX_DECR || cx == XX_INCR);
1363 if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
1365 printf("?Variable name required\n");
1369 ckstrncpy(vnambuf,s,VNAML);
1370 if ((y = cmnumw("by amount","1",10,&x,xxstring)) < 0)
1372 if ((y = cmcfm()) < 0)
1375 z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */
1377 if (incvar(vnambuf,x,z) < 0) {
1378 printf("?Variable %s not defined or not numeric\n",vnambuf);
1379 return(success = 0);
1381 return(success = 1);
1384 /* Used by doundef() */
1386 xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
1389 if (*s == CMDQ && *(s+1) == '%') {
1390 char c = *(s+2), * p = NULL;
1391 if (c >= '0' && c <= '9') {
1395 p = m_arg[maclvl][c - '0'];
1397 if (isupper(c)) c += ('a'-'A');
1398 if (c >= 'a' && c <= 'z')
1406 printf("(SELECTED)\n");
1407 } else if ((x = delmac(s,1)) > -1) { /* Full name required */
1409 if (verbose) printf("(OK)\n");
1411 printf("(FAILED)\n");
1415 /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
1422 static struct keytab undefswi[] = {
1423 { "/list", UND_VRB, 0 },
1425 { "/except", UND_EXC, CM_ARG },
1426 #endif /* COMMENT */
1427 { "/matching", UND_MAT, 0 },
1428 { "/simulate", UND_SIM, 0 },
1429 { "/verbose", UND_VRB, CM_INV }
1431 static int nundefswi = sizeof(undefswi) / sizeof(struct keytab);
1434 static char ** undeflist = NULL;
1436 doundef(cx) int cx; { /* UNDEF, _UNDEF */
1437 int i, j, n, rc = 0, arraymsg = 0;
1438 int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0;
1439 char *vnp, vnbuf[4];
1441 char *except = NULL;
1442 #endif /* COMMENT */
1447 if (!undeflist) { /* Allocate list if necessary */
1448 undeflist = (char **)malloc(UNDEFMAX * sizeof(char *));
1450 printf("?Memory allocation failure\n");
1453 for (i = 0; i < UNDEFMAX; i++)
1454 undeflist[i] = NULL;
1456 cmfdbi(&sw, /* First FDB - command switches */
1458 "Variable name or switch",
1460 "", /* addtl string data */
1461 nundefswi, /* addtl numeric data 1: tbl size */
1462 4, /* addtl numeric data 2: 4 = cmswi */
1463 xxstring, /* Processing function */
1464 undefswi, /* Keyword table */
1465 &fl /* Pointer to next FDB */
1467 cmfdbi(&fl, /* Anything that doesn't match */
1471 "", /* addtl string data */
1472 0, /* addtl numeric data 1 */
1473 0, /* addtl numeric data 2 */
1474 (cx == XXUNDEF) ? NULL : xxstring,
1478 while (1) { /* Parse 0 or more switches */
1479 x = cmfdb(&sw); /* Parse something */
1482 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
1485 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1486 printf("?This switch does not take an argument\n");
1489 switch (cmresult.nresult) {
1490 case UND_MAT: domatch = 1; break;
1491 case UND_SIM: simulate = 1; /* fall thru on purpose */
1492 case UND_VRB: verbose = 1; break;
1497 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
1499 printf("?Pattern required\n");
1504 makestr(&except,cmresult.sresult);
1506 #endif /* COMMENT */
1513 makestr(&(undeflist[n++]),cmresult.sresult);
1514 for (i = 1; i < UNDEFMAX; i++) {
1515 x = cmfld("Macro or variable name","",&s,
1516 ((cx == XXUNDEF) ? NULL : xxstring)
1519 if ((y = cmcfm()) < 0)
1525 makestr(&(undeflist[n++]),s);
1527 /* Now we have a list of n variables or patterns to undefine */
1529 for (i = 0; i < n; i++) {
1531 if (!(vnp = undeflist[i]))
1533 if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) {
1537 if (!domatch) { /* Pattern match not requested */
1539 if ((y = parsevar(vnp,&x,&z)) < 0) {
1541 if (verbose) printf(" %s...error\n",vnp);
1546 x = xxundef(vnp,verbose,simulate);
1548 if (!x && !simulate) errors++;
1553 /* Pattern match requested */
1555 if (!flag) { /* It's a macro */
1556 for (j = 0; j < nmac; j++) {
1557 if (ckmatch(vnp,mactab[j].kwd,0,1)) {
1558 x = xxundef(mactab[j].kwd,verbose,simulate);
1564 j--; /* Because mactab shifted up */
1567 } else if (vnp[0] == '%') { /* It's a \%x variable */
1571 for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */
1573 if (ckmatch(vnp,&vnbuf[1],0,1)) {
1574 x = xxundef(vnbuf,verbose,simulate);
1580 if (j == '9') j = (int)'a' - 1; /* 9 -> a */
1582 } else if (vnp[0] == '&') {
1583 if (!arraymsg && !quiet) {
1584 printf("?UNDEFINE /MATCH can't be used with arrays.\n");
1585 printf("(Type HELP ARRAY to see other methods.)\n");
1592 printf("undefined: %d, errors: %d\n",rc,errors);
1594 for (i = 0; i < UNDEFMAX; i++) { /* Check them all */
1595 if (undeflist[i]) { /* in case we were interrupted */
1596 free(undeflist[i]); /* previously... */
1597 undeflist[i] = NULL;
1600 return(success = (errors == 0) ? 1 : 0);
1606 extern char ppvnambuf[];
1608 char vnambuf[VNAML+1]; /* Buffer for variable names */
1609 char *vnp; /* Pointer to same */
1611 mydot = xxdot; /* Copy */
1612 xxdot = 0; /* and reset */
1614 In case we got here from a command that begins like ".\%a", cmkey() has
1615 already evaluated \%a, but we don't want that, so we retrieve the variable
1616 name from a special pre-evaluation buffer in the command module, and we
1617 undo the "unget word" that would be done because of the token, because if
1618 the variable was defined, it will unget its value rather than its name.
1622 if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
1627 if (cx == XXDFX || cx == XXASX)
1628 /* Evaluate variable name */
1629 y = cmfld("Macro or variable name","",&s,xxstring);
1631 /* Don't evaluate the variable name */
1632 y = cmfld("Macro or variable name","",&s,NULL);
1635 printf("?Variable name required\n");
1642 printf("?Name too long: \"%s\"\n",s);
1645 ckstrncpy(vnambuf,s,VNAML);
1646 vnambuf[VNAML] = NUL;
1648 if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
1649 if (*vnp == '%' || *vnp == '&') {
1650 if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
1652 if (cx == XXUNDEF) { /* Undefine */
1653 if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1655 return(success = 1);
1657 #endif /* COMMENT */
1658 debug(F101,"dodef parsevar x","",x);
1660 if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1662 if (doeval > 0) /* Type of assignment */
1665 if (y == 1) { /* Simple variable */
1666 if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
1669 debug(F110,"xxdef var name",vnp,0);
1670 debug(F110,"xxdef var def",s,0);
1671 } else if (y == 2) { /* Array element */
1672 if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
1674 printf("?Argument vector array is read-only\n");
1677 if (chkarray(x,z) < 0) return(-2);
1678 if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
1680 debug(F110,"xxdef array ref",vnp,0);
1681 debug(F110,"xxdef array def",s,0);
1683 } else { /* Macro */
1685 if (cx == XXUNDEF) { /* Undefine */
1686 if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1688 return(success = 1);
1690 #endif /* COMMENT */
1692 if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1697 if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
1700 debug(F110,"xxdef macro name",vnp,0);
1701 debug(F010,"xxdef macro def",s,0);
1706 if (*s == NUL) { /* No arg given, undefine */
1707 delmac(vnp,1); /* silently... */
1708 return(success = 1); /* even if it doesn't exist... */
1710 /* Defining a new macro or variable */
1712 if (cx == XXASS || cx == XXASX) { /* ASSIGN rather than DEFINE? */
1715 lp = line; /* If so, expand its value now */
1719 if (doeval == 2) { /* Arithmetic evaluation wanted too? */
1720 ckstrncpy(line,evala(s),LINBUFSIZ);
1721 line[LINBUFSIZ] = NUL;
1723 /* debug(F111,"calling addmac",s,(int)strlen(s)); */
1725 y = addmac(vnp,s); /* Add it to the appropriate table. */
1727 printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
1728 "ASSIGN" : "DEFINE");
1729 return(success = 0);
1730 } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
1731 return(1); /* don't change success variable */
1733 return(success = 1);
1740 L U D I A L -- Lookup up dialing directory entry.
1742 Call with string to look up and file descriptor of open dialing directory
1743 file. On success, returns number of matches found, with numbers stored
1744 in an array accessible via getdnum().
1746 static char *dn_p[MAXDNUMS + 1]; /* Dial Number pointers */
1747 static char *dn_p2[MAXDNUMS + 1]; /* Converted dial number pointers */
1748 static int dn_x[MAXDNUMS + 1]; /* Type of call */
1749 static int dncount = 0;
1750 char * d_name = NULL; /* Dial name pointer */
1752 char * /* Get dial directory entry name */
1754 return(d_name ? d_name : "");
1758 getdnum(n) int n; { /* Get dial number n from directory */
1759 if (n < 0 || n > dncount || n > MAXDNUMS)
1765 char * /* Check area code for spurious leading digit */
1766 chk_ac(i,buf) int i; char buf[]; {
1770 p = (char *) buf; /* Country we are calling: */
1771 if (i == 44 || /* UK */
1772 i == 49 || /* Germany */
1773 i == 39 || /* Italy */
1774 i == 31 || /* Netherlands */
1775 i == 351 || /* Portugal */
1776 i == 55 || /* Brazil */
1777 i == 972 || /* Israel */
1778 i == 41 || /* Switzerland */
1779 i == 43 || /* Austria */
1780 i == 42 || /* Czech Republic */
1781 i == 36 || /* Hungary */
1782 i == 30 || /* Greece */
1783 i == 352 || /* Luxembourg */
1784 i == 48 || /* Poland */
1785 i == 27 || /* South Africa */
1786 i == 33 || /* France (as of 1997) */
1787 i == 358 /* Finland (ditto) */
1795 /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
1797 src = area code of caller
1798 dest = area code of callee
1801 1 if call is long distance
1802 2 if call is local but area code must be dialed anyway
1805 callisld(src, dest) char * src, * dest; {
1807 if (dialfld) /* Force long distance? */
1809 if (!strcmp(src,dest)) { /* Area codes are the same */
1810 for (i = 0; i < nlocalac; i++) /* Is AC in the lc-area-codes list? */
1811 if (!strcmp(src,diallcac[i]))
1812 return(2); /* Yes so must be dialed */
1813 return(0); /* No so don't dial it. */
1815 for (i = 0; i < nlocalac; i++) /* ACs not the same so look in list */
1816 if (!strcmp(dest,diallcac[i])) /* Match */
1817 return(2); /* So local call with area code */
1818 return(1); /* Not local so long-distance */
1821 char pdsfx[64] = { NUL, NUL };
1825 xdial(s) char *s; { /* Run dial string thru macro */
1829 makestr(&s2,s); /* Copy the argument */
1830 if (!dialmac) /* Dial macro name given? */
1832 if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
1835 x = dodo(x,s2,0); /* Set up the macro */
1838 while (maclvl > m) /* Execute the parser */
1840 return(mrval[maclvl+1]); /* Return the result */
1847 dncvt(k,cx, prefix, suffix)
1848 int k, cx, prefix, suffix; { /* Dial Number Convert */
1849 int i, j, n, what; /* cx is top-level command index */
1850 char *ss; /* prefix - add prefixes? */
1851 char *p, *p2, *pxo; /* suffix - add suffixes? */
1862 First pass for strict (punctuation-based) interpretation.
1863 If it fails, we try the looser (length-based) one.
1866 what = 0; /* Type of call */
1867 s = dn_p[k]; /* Number to be converted. */
1868 debug(F111,"dncvt",s,k);
1874 printf("Error - No phone number to convert\n");
1877 if ((int)strlen(s) > 200) {
1878 ckstrncpy(outbuf,s,40);
1879 printf("?Too long: \"%s...\"\n",outbuf);
1882 npr = (prefix && dialnpr) ? dialnpr : "";
1883 sfx = (suffix && dialsfx) ? dialsfx : "";
1884 /* if (partial) psfx = dialsfx ? dialsfx : ""; */
1885 pxo = (prefix && dialpxo) ? dialpxo : "";
1886 lac = diallac ? diallac : ""; /* Local area code */
1888 outbuf[0] = NUL; /* Initialize conversion buffer */
1889 ss = s; /* Remember original string */
1891 if (*s != '+') { /* Literal number */
1892 dn_x[k] = DN_UNK; /* Sort key is "unknown". */
1893 ckmakmsg(outbuf,256, /* Sandwich it between */
1894 pxo,npr,s,sfx /* DIAL PREFIX and SUFFIX */
1897 if (tttapi && /* TAPI does its own conversions */
1898 !tapipass && /* if not in passthru mode */
1899 tapiconv == CK_AUTO || /* and TAPI conversions are AUTO */
1900 tapiconv == CK_ON /* OR if TAPI conversions are ON */
1904 if (!cktapiConvertPhoneNumber(dn_p[k], &p))
1906 makestr(&dn_p2[k], p);
1910 #endif /* CK_TAPI */
1911 makestr(&dn_p2[k], outbuf); /* Not TAPI */
1913 return(0); /* Done. */
1915 i = 0; /* Portable number */
1916 s++; /* Tiptoe past the plus sign */
1917 ccbuf[0] = NUL; /* Do country code first */
1919 if (!diallcc) { /* Do we know our own? */
1921 printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
1925 /* Parse the number */
1927 while (1) { /* Get the country code */
1928 while (*s == HT || *s == SP)
1930 if (!s) /* Not in standard format */
1932 if (*s == '(') { /* Beginning of area code */
1933 s++; /* Skip past parenthesis */
1934 ccbuf[i] = NUL; /* End of country code */
1935 if (!s) { /* Check for end of string */
1936 printf("Error - phone number ends prematurely: \"%s\"\n",ss);
1940 } else { /* Collect country code */
1942 ccbuf[i++] = *s; /* copy this character */
1944 if (!*s || i > 127) /* watch out for memory leak */
1948 cc = atoi(ccbuf); /* Numeric version of country code */
1950 i = 0; /* Now get area code */
1951 acbuf[0] = NUL; /* Initialize area-code buffer */
1952 acptr = acbuf; /* and pointer. */
1954 while (*s == HT || *s == SP) /* Ignore whitespace */
1956 if (!s) /* String finished */
1958 if (*s == ')') { /* End of area code */
1959 s++; /* Skip past parenthesis */
1960 acbuf[i] = NUL; /* Terminate area-code buffer */
1962 } else { /* Part of area code */
1963 if (isdigit(*s)) /* If it's a digit, */
1964 acbuf[i++] = *s; /* copy this character */
1965 s++; /* Point to next */
1966 if (!*s || i > 23) /* Watch out for overflow */
1972 Here we strip any leading 0 for countries that we know have
1973 0 as a long-distance prefix and do not have any area codes that
1974 start with 0 (formerly also ditto for "9" in Finland...)
1977 acptr = chk_ac(i,acbuf);
1979 while (*s == HT || *s == SP) /* Skip whitespace */
1982 /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
1984 if (*s && *acptr) { /* Area code was delimited */
1986 while (*s == '-' || *s == '.') /* Skip past gratuitious punctuation */
1988 if (!*s) s--; /* But not to end of string */
1990 if (strcmp(diallcc,ccbuf)) { /* Out of country? */
1991 if (!dialixp) { /* Need intl-prefix */
1993 printf("Error - No international dialing prefix defined\n");
1996 what = dn_x[k] = DN_INTL;
1997 p = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
1998 p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
2000 /* Form the final phone number */
2002 sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */
2005 pxo,npr,p,ccbuf,acptr,s,p2,sfx
2008 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2009 ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx,
2010 NULL,NULL,NULL,NULL);
2011 #endif /* COMMENT */
2013 } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
2014 if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
2016 printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
2018 if (x == 2) { /* Local call with area code */
2019 what = dn_x[k] = DN_LOCAL; /* Local-call */
2020 p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
2021 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
2023 what = dn_x[k] = DN_LONG; /* Long-distance */
2024 for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
2025 if (!strcmp(acptr,dialtfc[i])) {
2026 what = dn_x[k] = DN_FREE;
2030 if (what == DN_FREE) { /* Toll-free call */
2031 p = (prefix && dialtfp) ? dialtfp :
2032 ((prefix && dialldp) ? dialldp : "");
2033 p2 = ""; /* no suffix */
2034 } else { /* normal long distance */
2035 p = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
2036 p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
2039 /* Form the number to be dialed */
2041 sprintf(outbuf,"%s%s%s%s%s%s%s",
2042 pxo,npr,p,acptr,s,p2,sfx
2044 sprintf(pdsfx,"%s%s",p2,sfx);
2046 ckmakxmsg(outbuf,256,
2047 pxo,npr,p,acptr,s,p2,sfx,
2048 NULL,NULL,NULL,NULL,NULL);
2049 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2050 #endif /* COMMENT */
2051 } else { /* Same country, same area code */
2052 what = dn_x[k] = DN_LOCAL; /* So it's a local call. */
2053 if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
2054 p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
2055 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
2058 sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
2060 sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
2061 sprintf(pdsfx,"%s%s",p2,sfx);
2064 ckmakxmsg(outbuf,256,
2065 npr,p,acptr,s,p2,sfx,
2066 NULL,NULL,NULL,NULL,NULL,NULL);
2068 ckmakxmsg(outbuf,256,
2070 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
2071 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2072 #endif /* COMMENT */
2074 } else { /* Dialing from a PBX and not TAPI */
2075 if (ndialpxx) { /* Is it internal? */
2077 i = (int) strlen(dialpxx);
2078 j = (int) strlen(s);
2081 x = ckstrcmp(dialpxx,s,i,0);
2085 j = (int) strlen(s);
2086 for (kx = 0; kx < ndialpxx; kx++) {
2087 i = (int) strlen(dialpxx[kx]);
2089 if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
2092 #endif /* COMMENT */
2094 char * icp, buf[32];
2095 makestr(&matchpxx,dialpxx[kx]);
2096 debug(F111,"dncvt matchpxx",matchpxx,kx);
2097 what = dn_x[kx] = DN_INTERN; /* Internal call. */
2099 /* Internal-call prefix */
2107 if (isupper(c)) c = tolower(c);
2108 if (c == 'v' || c == 'f') {
2111 zzstring(icp,&bp,&n);
2117 p = (prefix && icp) ? icp : "";
2119 sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx);
2121 ckmakmsg(outbuf,256,npr,p,s,sfx);
2122 #endif /* COMMENT */
2123 } else { /* External local call */
2125 p = (prefix && diallcp) ? diallcp : "";
2127 p2 = (prefix && diallcs) ? diallcs : "";
2130 sprintf(outbuf,"%s%s%s%s%s%s%s",
2131 dialpxo ? dialpxo : "",
2132 npr,p,acptr,s,p2,sfx);
2136 dialpxo ? dialpxo : "",
2141 ckmakxmsg(outbuf, 256,
2142 dialpxo ? dialpxo : "",
2143 npr,p,acptr,s,p2,sfx,
2144 NULL,NULL,NULL,NULL,NULL);
2146 ckmakxmsg(outbuf, 256,
2147 dialpxo ? dialpxo : "",
2149 NULL,NULL,NULL,NULL,NULL,NULL);
2150 #endif /* COMMENT */
2156 } else { /* Area code was not delimited */
2158 char xbuf[256]; /* Comparison based only on length */
2164 for (i = 0; i < 255; i++) {
2166 while (!isdigit(*s)) { /* Pay attention only to digits */
2174 x = 1; /* Assume LD */
2176 if (!dialfld) { /* If LD not forced */
2177 for (j = 0; j < nlocalac; j++) { /* check local AC list? */
2178 ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL);
2179 n = (int) strlen(ybuf);
2180 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
2185 if (x == 1) { /* Or exact match with local CC+AC? */
2186 ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL);
2187 n = (int) strlen(ybuf);
2188 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
2192 if (x == 0 || x == 2) { /* Local call */
2193 int xx,kx; /* Begin 1 Dec 2001... */
2194 /* Account for PBX internal calls */
2197 j = (int) strlen(ybuf);
2198 for (kx = 0; kx < ndialpxx; kx++) {
2199 i = (int) strlen(dialpxx[kx]);
2201 if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0)))
2206 char * icp, buf[32];
2207 makestr(&matchpxx,dialpxx[kx]);
2208 debug(F111,"dncvt matchpxx",matchpxx,kx);
2209 what = dn_x[kx] = DN_INTERN; /* Internal call. */
2211 icp = dialpxi; /* Internal-call prefix */
2218 if (isupper(c)) c = tolower(c);
2219 if (c == 'v' || c == 'f') {
2222 zzstring(icp,&bp,&n);
2228 p = (prefix && icp) ? icp : "";
2229 ckmakmsg(outbuf,256,npr,p,s,sfx);
2230 /* End 1 Dec 2001... */
2232 } else { /* Not PBX internal */
2235 p = (prefix && diallcp) ? diallcp : "";
2236 p2 = (suffix && diallcs) ? diallcs : "";
2237 s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
2238 ckmakxmsg(outbuf,256,
2240 NULL,NULL,NULL,NULL,NULL,NULL);
2241 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2243 } else { /* Not local */
2244 n = ckstrncpy(ybuf,diallcc,256);
2245 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
2247 p = (prefix && dialldp) ? dialldp : "";
2248 p2 = (suffix && diallds) ? diallds : "";
2250 while (*s == '-' || *s == '.')
2253 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
2254 sprintf(pdsfx,"%s%s",p2,sfx);
2256 ckmakxmsg(outbuf,256,
2258 NULL,NULL,NULL,NULL,NULL,NULL);
2259 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2260 #endif /* COMMENT */
2262 dn_x[k] = DN_INTL; /* International */
2266 "Error - No international dialing prefix defined\n"
2271 p = (prefix && dialixp) ? dialixp : "";
2272 p2 = (suffix && dialixs) ? dialixs : "";
2274 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
2275 sprintf(pdsfx,"%s%s",p2,sfx);
2277 ckmakxmsg(outbuf,256,
2278 pxo,npr,p,xbuf,p2,sfx,
2279 NULL,NULL,NULL,NULL,NULL,NULL);
2280 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2281 #endif /* COMMENT */
2286 if (tttapi && /* TAPI performs the conversions */
2288 tapiconv == CK_AUTO ||
2293 if (!cktapiConvertPhoneNumber(dn_p[k],&p))
2295 makestr(&dn_p2[k], p);
2299 #endif /* CK_TAPI */
2300 makestr(&dn_p2[k], outbuf);
2303 #endif /* CK_TAPI */
2309 ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
2310 char linebuf[1024], *s2; /* Buffers and pointers */
2314 char *info[8]; /* Pointers to words from entry */
2319 debug(F110,"ddcvt file",s,0);
2321 if (!s || !f) /* No filename or file */
2326 znewn(s,&s2); /* s2 = address of static buffer */
2327 debug(F110,"ddcvt newname",s2,0);
2330 /* In VMS, znewn() returns the same file name with a new version number */
2331 makestr(&temp,s); /* Swap - otherwise the new */
2332 s = s2; /* version has the older version */
2333 s2 = temp; /* number... */
2334 debug(F110,"ddcvt after swap s",s,0);
2335 debug(F110,"ddcvt after swap s2",s2,0);
2336 makestr(&(dialdir[n]),s); /* New file gets new version number */
2337 debug(F110,"ddcvt after makestr s2",s2,0);
2338 debug(F111,"ddcvt dialdir[n]",dialdir[n],n);
2340 if (zrename(s,s2) < 0) { /* Not VMS - rename old file */
2341 perror(s2); /* to new (wierd) name. */
2345 debug(F110,"ddcvt s2 (old)",s2,0);
2346 if ((f = fopen(s2,"r")) == NULL) { /* Reopen old file with wierd name */
2347 debug(F110,"ddcvt s2 open error",ck_errstr(),0);
2348 dirline = 0; /* (or in VMS, old version) */
2352 debug(F110,"ddcvt fopen(s2) OK",s2,0);
2354 debug(F110,"ddcvt s (new)",s,0);
2355 if ((f2 = fopen(s,"w")) == NULL) { /* Create new file with old name */
2356 debug(F110,"ddcvt s open error",ck_errstr(),0);
2357 perror(s); /* (or in VMS, new version) */
2360 debug(F110,"ddcvt fopen(s) OK",s,0);
2362 printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
2363 fprintf(f2,"; %s - Kermit dialing directory\n", s);
2364 fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
2365 "; Name","Number","Speed","Parity","Comment"
2369 linebuf[0] = NUL; /* Read a line */
2370 if (fgets(linebuf,1023,f) == NULL)
2372 debug(F110,"ddcvt linebuf",linebuf,0);
2373 if (!linebuf[0]) { /* Empty line */
2377 x = (int) strlen(linebuf); /* Strip line terminator, */
2378 while (x-- > 0) { /* if any. */
2379 if (linebuf[x] <= SP)
2384 xwords(linebuf,5,info,1); /* Parse it the old way */
2385 for (x = 1; x < 6; x++)
2386 if (!info[x]) info[x] = "";
2387 fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
2388 info[1],info[2],info[3],info[4],info[5]
2392 rc = 0; /* Success */
2397 if (temp) free(temp);
2402 int /* s = name to look up */
2403 #ifdef CK_ANSIC /* cx = index of command */
2404 ludial(char *s, int cx) /* (DIAL, LOOKUP, etc) */
2406 ludial(s, cx) char *s; int cx;
2407 #endif /* CK_ANSIC */
2410 int dd, n1, n2, n3, i, j, t; /* Workers */
2411 int olddir, newdir, oldentry, newentry;
2414 int ambiguous = 0; /* Flag for lookup was ambiguous */
2415 char *info[7]; /* Pointers to words from entry */
2416 char *pp; /* Pointer to element of array */
2418 char *line; /* File input buffer */
2420 /* #define LUDEBUG */
2424 #endif /* LUDEBUG */
2426 if (!s || ndialdir < 1) /* Validate arguments */
2429 if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */
2432 if (!(line = malloc(1024))) /* Allocate input buffer */
2436 if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
2437 #endif /* LUDEBUG */
2441 f = NULL; /* Dial directory file descriptor */
2442 t = dncount = 0; /* Dial-number match count */
2443 dd = 0; /* Directory counter */
2447 We need to recognize both old- and new-style directories.
2448 But we can't allow old-style and new-style entries in the same
2449 directory because there is no way to tell for sure the difference between
2450 an old-style entry like this:
2454 and a new-style literal entry like this:
2458 I.e. is the "9600" a speed, or part of the phone number?
2460 while (1) { /* We make one pass */
2461 if (!f) { /* Directory not open */
2462 if (dd >= ndialdir) /* No directories left? */
2464 debug(F111,"ludial dialdir[dd]",dialdir[dd],dd);
2465 if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
2466 perror(dialdir[dd]); /* Can't, print message saying why */
2471 dd++; /* Go on to next one, if any... */
2474 dirline = 0; /* Directory file line number */
2475 if (dialdpy && !pass)
2476 printf("Opening: %s...\n",dialdir[dd]);
2478 if (!oldflg) olddir = 0;
2484 if (getnct(line,1023,f,1) < 0) { /* Read a line */
2485 if (f) { /* f can be clobbered! */
2486 fclose(f); /* Close the file */
2487 f = NULL; /* Indicate next one needs opening */
2492 if (!line[0]) /* Empty line */
2495 if (zz) printf("LUDIAL 2 s[%s]\n",s);
2496 #endif /* LUDEBUG */
2498 /* Make a copy and parse it the old way */
2499 /* A copy is needed because xwords() pokes NULs into the string */
2501 if ((pp = malloc((int)strlen(line) + 1))) {
2502 strcpy(pp,line); /* safe */
2503 xwords(pp,5,info,0); /* Parse it the old way */
2506 if (zz) printf("LUDIAL 3 s[%s]\n",s);
2507 #endif /* LUDEBUG */
2511 if (*info[1] == ';') { /* If full-line comment, */
2512 newdir = 1; /* (only new directories have them) */
2513 continue; /* keep reading. */
2517 if (*info[2] == '+')
2520 if ((*info[4] == '=') ||
2521 !ckstrcmp(info[4],"none", 4,0) ||
2522 !ckstrcmp(info[4],"even", 4,0) ||
2523 !ckstrcmp(info[4],"space",5,0) ||
2524 !ckstrcmp(info[4],"mark", 4,0) ||
2525 !ckstrcmp(info[4],"odd", 3,0)
2535 /* Check consistency */
2537 if ((oldentry || olddir) && (newentry || newdir)) {
2539 "\nERROR: You seem to have old- and new-format entries mixed in your\n");
2541 "dialing directory. You'll have to edit it by hand to convert it to the\n");
2543 printf("new format. Type HELP DIAL for further information.\n\n");
2545 printf("new format.\n\n");
2553 if (!olddir && oldentry) {
2556 if (dialcvt == 2) { /* 2 == ASK */
2558 "WARNING: Old-style dialing directory detected:\n%s", line);
2559 convert = uq_ok(tmpbuf,
2560 "Shall I convert it for you? ",3,NULL,0);
2564 debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd);
2565 if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
2566 debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd);
2569 " Sorry, can't convert.");
2571 " Will ignore speed and parity fields, continuing...\n\n");
2573 olddir = newdir = 0;
2574 debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd);
2582 " OK, will ignore speed and parity fields, continuing...\n\n");
2588 if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
2589 #endif /* LUDEBUG */
2591 /* Now parse again for real */
2593 if (oldentry) /* Parse it the old way */
2594 xwords(line,5,info,0);
2595 else /* Parse it the new way */
2596 xwords(line,2,info,1);
2599 if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
2600 if (zz) printf("%s [%s]\n",info[1],info[2]);
2601 #endif /* LUDEBUG */
2603 if (info[1]) { /* First word is entry name */
2604 if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
2605 continue; /* If no first word, keep reading. */
2606 if (n3 < n1) /* Search name is longer */
2607 continue; /* Can't possibly match */
2608 if (ambiguous && n3 != n1)
2612 if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
2613 #endif /* LUDEBUG */
2615 if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
2619 if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
2620 #endif /* LUDEBUG */
2622 if (!info[2]) /* No phone number given */
2624 if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
2625 continue; /* Ignore empty phone numbers */
2629 if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
2630 printf("?internal error - ludial malloc 1\n");
2638 strcpy(pp,info[2]); /* safe */
2640 if (dncount > MAXDNUMS) {
2641 printf("Warning: %d matches found, %d max\n",
2648 dn_p[dncount++] = pp; /* Add pointer to array. */
2649 if (dncount == 1) { /* First one... */
2650 if (d_name) free(d_name);
2651 if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
2652 printf("?internal error - ludial malloc 2\n");
2660 t = n3; /* And its length */
2661 strcpy(d_name,info[1]); /* safe */
2662 } else { /* Second or subsequent one */
2666 printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
2667 #endif /* LUDEBUG */
2669 if ((int) strlen(info[1]) == t) /* Lengths compare */
2670 if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
2673 /* Name given by user matches entries with different names */
2675 if (ambiguous) /* Been here before */
2678 ambiguous = 1; /* Now an exact match is required */
2679 for (j = 0; j < dncount; j++) { /* Clean out previous list */
2685 pass++; /* Second pass... */
2686 goto lu_again; /* Do it all over again. */
2690 if (line) free(line);
2691 if (dncount == 0 && ambiguous) {
2692 printf(" Lookup: \"%s\" - ambiguous%s\n",
2694 cx == XXLOOK ? "" : " - dialing skipped"
2702 pncvt(s) char *s; { /* Phone number conversion */
2703 char *p = NULL; /* (just a wrapper for dncvt() */
2705 static char pnbuf[128];
2706 makestr(&p,dn_p[0]); /* Save these in case they are */
2707 makestr(&q,dn_p2[0]); /* being used */
2708 makestr(&dn_p[0],s); /* Copy the argument string to here */
2709 dncvt(0,XXLOOK,1,1); /* Convert it */
2710 if (!dn_p2[0]) /* Put result where can return it */
2713 ckstrncpy(pnbuf,dn_p2[0],127);
2714 makestr(&dn_p[0],p); /* Restore these */
2715 makestr(&dn_p2[0],q);
2716 makestr(&p,NULL); /* Free these */
2718 return((char *)pnbuf);
2722 dodial(cx) int cx; { /* DIAL or REDIAL */
2723 int i = 0, x = 0; /* Workers */
2724 int sparity = -1; /* For saving global parity value */
2729 int lufound = 0; /* Did any lookup succeed? */
2736 char *p = NULL, *s3 = NULL, * sav = NULL;
2737 int j = 0, t = 0, n = 0;
2741 debug(F101,"dodial cx","",cx);
2742 debug(F111,"dodial diallcc",diallcc,diallcc);
2743 #endif /* COMMENT */
2745 xretries = dialrtr; /* If retries not set, */
2746 if (diallcc) { /* choose default based on */
2747 xlcc = atoi(diallcc); /* local country code. */
2750 case 1: xretries = 10; break; /* No restrictions in NANP */
2751 /* Add other country codes here */
2752 /* that are known to have no restrictions on redialing. */
2753 default: xretries = 1;
2757 if (cx == XXPDIA) { /* Shortcut... */
2760 debug(F100,"PDIAL sets partial=1","",0);
2761 postfix = 0; /* Do not add postfix */
2764 debug(F100,"DIAL sets partial=0","",0);
2766 previous = dialsta; /* Status of previous call, if any */
2767 if (previous == DIA_PART) {
2768 prefix = 0; /* do not add prefix */
2770 s = NULL; /* Initialize user's dial string */
2771 if (cx == XXRED) { /* REDIAL or... */
2772 if ((y = cmcfm()) < 0)
2774 } else if (cx == XXANSW) { /* ANSWER or ... */
2775 if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
2778 if ((y = cmcfm()) < 0)
2780 } else { /* DIAL or LOOKUP */
2782 s3 = "Number to dial or entry from dial directory";
2784 s3 = "Number to dial";
2785 if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
2788 len = (int) strlen(s);
2789 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
2791 if (len > 1) { /* Strip outer braces if given */
2793 if (s[len-1] == '}') {
2801 s = brstrip(s); /* Strip outer braces or quotes */
2802 #endif /* COMMENT */
2806 if (cx != XXLOOK) { /* Not LOOKUP */
2809 printf("Sorry, dialing is disabled.\r\n");
2810 return(success = 0);
2814 if (tttapi && !tapipass) {
2815 ; /* Skip the modem test if TAPI */
2817 #endif /* CK_TAPI */
2818 if (mdmtyp < 1 && !dialtest) {
2822 #endif /* TN_COMPORT */
2824 printf("Please SET HOST first, and then SET MODEM TYPE\n");
2826 printf("Sorry, you must SET MODEM TYPE first\n");
2828 return(success = 0);
2830 if (!local && !dialtest) {
2831 printf("Sorry, you must SET %s or SET HOST first\n",
2839 return(success = 0);
2844 #endif /* TN_COMPORT */
2848 #endif /* CK_TAPI */
2851 && (strcmp(ttname,"/dev/null"))
2854 && (strcmp(ttname,"/nil"))
2858 printf("\nSorry, you must SET SPEED first\n");
2860 return(success = 0);
2864 for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
2865 if (!dialnum) { /* First time dialing */
2866 dn_p[j] = NULL; /* initialize all pointers. */
2868 } else if (dn_p[j]) { /* Not the first time, */
2869 free(dn_p[j]); /* free previous, if any, */
2870 dn_p[j] = NULL; /* then set to NULL. */
2874 } else break; /* Already NULL */
2882 printf("?Lookup what?\n");
2884 printf("%s\n", (cx == XXRED) ?
2885 "?No DIAL command given yet" :
2886 "?You must specify a number to dial"
2891 /* Now we have the "raw" dial or lookup string and s is not NULL */
2893 makestr(&dscopy,s); /* Put it in a safe place */
2897 debug(F111,"dodial",s,ndialdir);
2902 if (ndialdir > 0) { /* Do we have a dialing directory? */
2903 n = ludial(s,cx); /* Look up what the user typed */
2905 printf(" Lookup: \"%s\" - not found%s\n",
2907 cx == XXLOOK ? "" : " - dialing as given\n"
2910 debug(F101,"dodial",s,n);
2911 if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
2912 if (n == -1) /* -2 means ludial already gave msg */
2913 printf(" Lookup: fatal error - dialing skipped\n");
2917 if (n > 0) /* A successful lookup */
2919 } else if (*s == '=') { /* If number starts with = sign */
2921 literal = 1; /* remember this */
2922 while (*s == SP) s++; /* and then also any leading spaces */
2923 } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
2924 makelist(tmpbuf,dn_p,MAXDNUMS);
2925 makestr(&dscopy,tmpbuf);
2927 for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
2928 if (!dn_p[n]) break;
2931 if (cx == XXLOOK && !wasalpha && !braces) {
2932 /* We've been told to lookup a number or a quoted name */
2935 p = literal ? s : pncvt(dscopy);
2938 printf("%s => %s\n", dscopy, p);
2939 return(success = 1);
2941 printf("?Bad phone number\n");
2942 return(success = 0);
2945 /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
2946 /* But don't save pieces of partial dial ... */
2948 debug(F101,"DIAL save dialnum partial","",partial);
2949 debug(F101,"DIAL save dialnum previous","",previous);
2950 if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
2951 (cx == XXLOOK && n > 0)) {
2952 makestr(&dialnum,dscopy);
2953 if (!quiet && dscopy && !dialnum)
2954 printf("WARNING - memory allocation failure: redial number\n");
2957 if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
2958 if (!strcmp(d_name,s))
2959 printf(" Lookup: \"%s\" - exact match\n",s);
2961 printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
2966 if ((cx == XXLOOK) ||
2967 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
2968 printf(" %d telephone number%sfound for \"%s\"%s\n",
2970 (n == 1) ? " " : "s ",
2976 for (i = 0; i < n; i++) { /* Convert */
2978 if (dncvt(i,cx,prefix,postfix) < 0) {
2985 if (dialsrt && n > 1) { /* Sort into optimal order */
2986 for (i = 0; i < n-1; i++) {
2987 for (j = i+1; j < n; j++) {
2988 if (dn_x[j] < dn_x[i]) {
2996 dn_p2[j] = dn_p2[i];
3002 if ((cx == XXLOOK) ||
3003 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
3009 if (n > 12) nn = 12;
3010 for (i = 0; i < nn; i++) {
3011 printf("%3d. %-12s %-20s => %-20s (%d)\n",i+1,
3013 dn_p2[i] ? dn_p2[i] : "(processing failed)",
3017 if (cx != XXLOOK && n != nn)
3018 printf("And %d more...\n", n - nn);
3020 } else if (n == 0) { /* Not found in directory */
3021 makestr(&(dn_p[0]),literal ? s : dscopy);
3022 makestr(&d_name,literal ? s : dscopy);
3025 if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
3026 dialsta = DIA_DIR; /* portable-format number ... */
3033 /* It's not good that the networks directory depends on NOT-NODIAL.. */
3034 if (cx == XXLOOK && dscopy) { /* Networks here too... */
3035 extern char *nh_p[], *nh_p2[], *n_name;
3036 extern char *nh_px[4][MAXDNUMS+1];
3038 if (nnetdir > 0) { /* Do we have a network directory? */
3040 n = lunet(dscopy); /* Look up what the user typed */
3044 if (n > 0) /* A successful lookup */
3046 if (cx == XXLOOK && n == 0)
3047 printf(" Lookup: \"%s\" - not found\n",dscopy);
3049 printf("%s %d network entr%s found for \"%s\"%s\n",
3050 cx == XXLOOK ? " Lookup:" : "",
3052 (n == 1) ? "y" : "ies",
3057 for (i = 0; i < n; i++) {
3059 printf("%3d. %-12s => %-9s %s",
3060 i+1,n_name,nh_p2[i],nh_p[i]);
3061 for (k = 0; k < 4; k++) {
3063 printf(" %s",nh_px[k][i]);
3071 #endif /* NETCONN */
3074 return(success = lufound);
3075 } /* cx != XXANSW */
3078 conres(); /* So Ctrl-C/Y will work */
3081 Some modems do not react well to parity. Also, if we are dialing through a
3082 TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
3085 This should work even if the user interrupts the DIAL command, because the
3086 DIAL module has its own interrupt handler. BUT... if, for some reason, a
3087 dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
3088 parity should be used), this might prevent successful dialing. For that
3089 reason, we don't do this for V.25bis modems.
3091 sparity = parity; /* Save current parity */
3092 if ((dialcapas & CKD_V25) == 0) /* If not V.25bis... */
3093 parity = 0; /* Set parity to NONE */
3097 These modems use some kind of screwy flow control while in command mode,
3098 and do not present CTS as they should. So if RTS/CTS is set (or even if
3099 it isn't) disable flow control during dialing.
3102 if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
3103 flow = FLO_NONE; /* This is not enough */
3105 ttsetflow(FLO_NONE); /* Really turn it off */
3106 #endif /* CK_TTSETFLOW */
3108 #endif /* MINIDIAL */
3112 #endif /* TN_COMPORT */
3115 if ((x = ttgmdm()) > -1) {
3118 "WARNING - No modem signals detected. Is your modem turned on? If not,\n\
3119 use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n",
3125 if (flow == FLO_RTSC) {
3126 if (!(x & BM_CTS)) {
3129 "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
3130 Disabling flow control temporarily %s...\n",
3132 "while waiting for call" :
3140 if (cx == XXANSW) { /* ANSWER */
3141 success = ckdial("",0,0,1,0);
3145 /* Edit 192 adds the ability to dial repeatedly. */
3150 if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
3153 /* And the ability to dial alternate numbers. */
3154 /* Loop to dial each in a list of numbers for the same name... */
3155 for (j = 0; j < n && !success; j++) { /* until one answers. */
3156 s = dn_p2[j]; /* Next number in list */
3157 if (dn_x[j] >= dialrstr) { /* Dial restriction */
3158 printf("Restricted: %s, skipping...\n",dn_p[j]);
3161 xredial = (i == 0 && j == 0) ? 0 : 1;
3162 if (!s) s = dn_p[j];
3166 p = xdial(s); /* Apply DIAL macro now */
3167 if (p) if (*p) s = p;
3170 /* Dial confirmation */
3171 /* NOTE: the uq_xxx() calls allow for a GUI dialog */
3173 if (i == 0 && dialcnf) {
3175 ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL);
3176 x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0);
3180 x = uq_txt( /* Allow GUI dialog */
3182 " Please enter the correct number,\r\n or press Enter to skip.",
3184 " Please enter the correct number,\r\n or press Return to skip.",
3186 "Corrected phone number: ",
3194 if (x && atmbuf[0]) { /* They gave a new one */
3196 makestr(&(dn_p2[j]), s);
3202 extern int on_recall;
3203 #endif /* CK_RECALL */
3204 cmsavp(psave,PROMPTL);
3207 " Please enter the correct number,\r\n or press Enter to skip: "
3209 " Please enter the correct number,\r\n or press Return to skip: "
3214 if (pflag) prompt(NULL);
3217 #endif /* CK_RECALL */
3221 x = cmtxt("Corrected phone number","",&s,NULL);
3224 if ((int) strlen(s) < 1) {
3228 makestr(&(dn_p2[j]), s);
3231 #endif /* COMMENT */
3234 if (dialtest) { /* Just testing */
3236 printf("\nTESTING...\n");
3238 printf(" Number: \"%s\" => \"%s\"\n",sav,s);
3240 printf(" Number: \"%s\"\n",s);
3245 success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
3246 what &= ~(W_DIALING);
3248 if (dialsta < 8 || /* Break out if unrecoverable error */
3249 dialsta == DIA_INTR ||
3250 dialsta == DIA_ERR ||
3251 previous == DIA_PART
3257 if (success) /* Succeeded, leave the outer loop */
3259 if (dialsta < 8 || /* Break out if unrecoverable error */
3260 dialsta == DIA_INTR || /* Interrupted */
3261 dialsta == DIA_NODT || /* No dialtone */
3262 dialsta == DIA_NOAC || /* Access forbidden */
3263 dialsta == DIA_BLCK || /* Blacklisted */
3264 dialsta == DIA_DIR || /* Dialing directory error */
3265 dialsta == DIA_ERR || /* Modem command error */
3266 previous == DIA_PART)
3268 if (++i >= xretries) /* Break out if too many tries */
3270 if (!backgrd && !quiet) {
3273 "\nWill redial in %d second%s- press any key to redial immediately.\n",
3275 dialint == 1 ? " " : "s "
3277 printf("Ctrl-C to cancel...\n");
3279 x = dialint; /* Redial interval */
3281 if ((y = conchk()) > 0) { /* Did they type something? */
3282 while (y--) coninc(0); /* Yes, absorb it */
3283 break; /* And wake up */
3285 sleep(1); /* No interrupt, sleep a sec */
3293 bleep((short) BP_FAIL);
3295 bleep((short) BP_NOTE);
3297 setint(); /* Fix OS/2 interrupts */
3300 parity = sparity; /* Restore parity if we saved it */
3303 ttres(); /* Restore DIAL device */
3306 concb((char)escape); /* Restore console */
3309 { /* Set session title */
3310 char * p, name[72]; /* in window list. */
3313 q = "Incoming call";
3326 while (*p) { /* Uppercase it for emphasis. */
3333 os2settitle((char *) name, TRUE);
3339 if (reliable == SET_AUTO) { /* It's not a reliable connection. */
3341 debug(F101,"dodial reliable","",reliable);
3346 if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */
3347 extern int dialmhu, dialhng, dialdpy;
3348 extern char * dialmsg[];
3349 printf("\n*************************\n");
3350 printf("DIAL-class command failed.\n");
3351 printf("Modem type: %s\n", gmdmtyp());
3352 printf("Device: %s\n", ttname);
3353 printf("Speed: %ld\n", speed);
3354 printf("Dial status: %d",dialsta);
3355 if (dialsta < 35 && dialmsg[dialsta])
3356 printf(" [%s]",dialmsg[dialsta]);
3358 if (dialsta == DIA_TIMO ||
3359 dialsta == DIA_NRDY ||
3360 (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN)
3365 " . SET DIAL TIMEOUT to a greater value and try again.\n"
3372 " . Is the modem turned on?\n"
3375 " . Are you using the right communication port?\n"
3380 " . Is the modem connected to the telephone line?\n"
3383 if (mdmtyp == n_GENERIC) {
3385 " . Please choose a specific modem type with SET MODEM TYPE and try again.\n"
3388 " SET MODEM TYPE ? to see the list of known modem types.\n"
3392 " . Are you sure you have chosen the appropriate modem type?\n"
3395 if (speed > 19200L) {
3397 " . Maybe the interface speed (%ld) is too fast:\n", speed
3400 " SET SPEED to a lower speed and try again.\n"
3403 " SET SPEED ? to see the list of valid speeds.\n"
3409 " . SET MODEM HANGUP-METHOD RS232 and try again.\n"
3413 " . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n"
3416 " . If that doesn't work, try again with SET DIAL HANGUP OFF.\n"
3420 " . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n"
3425 " . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n"
3430 " . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n"
3436 " . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n"
3439 printf("(Use SET HINTS OFF to suppress future hints.)\n");
3440 printf("*************************\n\n");
3442 #endif /* NOHINTS */
3449 /* D O T Y P E -- Type (display) a file with various options... */
3452 #define TYPBUFL 16384
3455 #endif /* BIGBUFOK */
3457 int typ_lines = 0; /* \v(ty_ln) */
3458 int typ_mtchs = 0; /* \v(ty_lm) */
3459 static int typ_int = 0; /* Flag if TYPE interrupted */
3462 extern int fcharset, fileorder, byteorder, ucsorder;
3463 #define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4
3464 static char * mp = NULL;
3465 static char * mbuf = NULL;
3466 static long xn = 0L;
3472 storechar(c) char c;
3473 #endif /* CK_ANSIC */
3475 if (!mp) return(-1);
3476 if (++xn > TYPXBUFL)
3478 debug(F111,"storechar xn",ckitoa((int)c),xn);
3482 #endif /* UNICODE */
3484 static FILE * ofp = NULL; /* For /OUTPUT: file */
3487 typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
3490 debug(F011,"typeline buf",buf,len);
3491 /* debug(F101,"typeline outcs","",outcs); */
3496 /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */
3497 /* Len is its length in bytes. There is no line terminator. */
3498 /* outcs is the file character-set number (FC_xxx) of the target set */
3499 /* that was requested by the user. */
3500 if (!inserver && !k95stdout) {
3501 extern int wherex[], wherey[];
3502 extern unsigned char colorcmd;
3504 VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2,
3505 wherey[VCMD], wherex[VCMD], &colorcmd);
3509 #endif /* UNICODE */
3510 #endif /* NOLOCAL */
3513 /* In Unix, VMS, etc, the line has already been converted to the desired */
3514 /* character-set, if one was given. OR... on all platforms, including in */
3515 /* K95, we don't know the character set. In either case we dump the line */
3516 /* byte by byte in case it contains NULs (printf() would truncate). */
3519 for (i = 0; i < len; i++)
3522 for (i = 0; i < len; i++) {
3523 if (ofp == stdout) {
3529 #endif /* COMMENT */
3534 if (outcs == FC_UCS2) {
3535 if (ofp == stdout) {
3541 #endif /* UNICODE */
3542 if (ofp == stdout) {
3550 if (outcs == FC_UCS2) {
3551 if (ofp == stdout) {
3557 #endif /* UNICODE */
3558 if (ofp == stdout) {
3567 static int /* Get translated line */
3568 typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
3569 int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0;
3576 if (deblog && typ_lines == 0) {
3577 debug(F101,"typegetline incs","",incs);
3578 debug(F101,"typegetline outcs","",outcs);
3579 debug(F101,"typegetline feol","",feol);
3580 debug(F101,"typegetline byteorder","",byteorder);
3581 debug(F101,"typegetline ucsorder ","",ucsorder);
3582 debug(F111,"typegetline fileorder","1",fileorder);
3586 if (incs < 0) /* Shouldn't happen */
3589 if (outcs == -1) /* Can happen */
3592 if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */
3594 if (!mbuf) { /* Allocate buffer if not allocated */
3595 mbuf = (char *)malloc(TYPXBUFL+1); /* yet */
3597 printf("WARNING: Translation buffer allocation failure.\n");
3598 printf("Translation will be skipped...\n");
3603 if (xlate) { /* Translating... */
3604 mp = mbuf; /* Reset working buffer pointer */
3606 Here we call xgnbyte() in a loop, having it return UCS-2 bytes. In K95, we
3607 use UCS-2 directly. Elsewhere, we feed the UCS-2 bytes into xpnbyte() to
3608 convert them to the desired target character set. But since we are using
3609 UCS-2, we have several sources for confusion: (1) xgnbyte() might return in
3610 LE or BE byte order, with no explicit indication of what the order is; but
3611 (2) xpnbyte() wants BE; but (3) Windows wants LE.
3614 if (typ_int) /* Quit if interrupted */
3616 c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3617 debug(F000,"typegetline c0","",c0);
3618 if (c0 < 0) { /* EOF */
3622 c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3623 debug(F000,"typegetline c1","",c1);
3624 if (c1 < 0) { /* EOF */
3629 if (deblog && typ_lines == 0) {
3630 if (count == 0) /* Check fileorder after BOM */
3631 debug(F111,"typegetline fileorder","2",fileorder);
3636 /* Now we have the two UCS-2 bytes. Which order are they in? */
3638 if (fileorder > 0) { /* Little Endian */
3639 int t; /* So swap them */
3640 debug(F100,"typegetline swapping","",0);
3645 #endif /* COMMENT */
3646 if (c0 == 0 && c1 == 0x0D) /* Now see if we have EOL */
3649 if (c0 == 0 && c1 == 0x0A) /* Now see if we have EOL */
3652 count++; /* Count byte */
3654 /* Give the two bytes to xpnbyte() in BE order */
3656 if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1);
3657 if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1);
3659 if (xxn > -1) { /* Have end of line? */
3661 if (yyn == xxn - 2) /* Adjust for CRLF */
3663 break; /* And break out of loop. */
3667 if (xn > n) /* Can truncate here... */
3669 memcpy(buf,mbuf,xn);
3670 debug(F011,"typegetline xlate",buf,xn);
3671 return((eof && (xn == 0)) ? -1 : xn);
3673 #endif /* UNICODE */
3675 /* We can't use this because, stupidly, zsinl() doesn't return a length. */
3676 /* It could be changed but then we'd have to change all ck?fio.c modules */
3677 x = zsinl(ZIFILE,buf,n);
3679 /* So instead, we copy zsinl() to here... */
3680 /* But note: This does not necessarily handle UCS-2 alignment properly; */
3681 /* that's what the code in the first section of this routine is for. */
3682 /* But it does tolerate files that contain NULs. */
3688 a = -1; /* Current character, none yet. */
3689 debug(F101,"typegetline zsinl simulation","",n);
3690 while (n--) { /* Up to given length */
3693 if (feol) /* Previous character */
3695 #endif /* COMMENT */
3696 if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */
3697 debug(F101,"typegetline zchin fail","",count);
3699 x = -1; /* EOF or other error */
3703 if (feol) { /* Single-character line terminator */
3706 } else { /* CRLF line terminator */
3708 /* Debug log shows that in Windows, <CR><LF> is returned as <LF>. */
3709 /* Apparently we're not reading the file in binary mode. */
3711 if (a == '\015') /* CR, get next character */
3713 if (old == '\015') { /* Previous character was CR */
3714 if (a == '\012') { /* This one is LF, so we have a line */
3716 } else { /* Not LF, deposit CR */
3724 if (s[len] == CR) { /* This probably won't happen */
3731 #endif /* COMMENT */
3733 *s = a; /* Deposit character */
3737 *s = '\0'; /* Terminate the string */
3739 #endif /* COMMENT */
3740 return(x < 0 ? -1 : len);
3747 tytrap(int foo) /* TYPE interrupt trap */
3749 tytrap(foo) int foo;
3750 #endif /* CK_ANSIC */
3753 signal(SIGINT, SIG_ACK);
3755 debug(F100,"type tytrap SIGINT","",0);
3756 typ_int = 1; /* (Need arg for ANSI C) */
3762 dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z)
3763 char * file, * pat, * prefix; int paging, first, head, width, incs, outcs;
3764 char * outfile; int z;
3766 extern CK_OFF_T ffc;
3767 char buf[TYPBUFL+2];
3769 int rc = 1, lines = 0, ucs2 = 0;
3770 char ** tail = NULL;
3772 int tailing = 0, counting = 0;
3773 int x, c, n, i, j, k = 0;
3774 int number = 0, save, len, pfxlen = 0, evalpfx = 1;
3778 #endif /* UNICODE */
3786 SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
3788 SIGTYP (* volatile oldsig)(int);
3791 SIGTYP (* oldsig)();
3796 if (outfile == (char *)1) {
3802 if (!file) file = "";
3803 if (!*file) return(-2);
3805 if (ofp != stdout) { /* In case of previous interruption */
3806 if (ofp) fclose(ofp);
3809 if (!outfile) outfile = "";
3811 ofp = fopen(outfile,"w"); /* Open output file */
3813 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
3819 if (number && prefix) prefix = NULL;
3822 ucsbom_sav = ucsbom; /* We are not creating a file */
3823 ucsbom = 0; /* Do not use BOM bytes */
3824 #endif /* UNICODE */
3828 save = binary; /* Save file type */
3830 debug(F101,"dotype incs","",incs);
3831 debug(F101,"dotype outcs","",outcs);
3834 debug(F111,"dotype fileorder","A",fileorder);
3836 if (!inserver && !k95stdout)
3840 if (outcs == FC_UCS2) /* Output is UCS-2? */
3843 fileorder = ucsorder;
3844 debug(F111,"dotype fileorder","B",fileorder);
3845 #endif /* UNICODE */
3851 /* Check whether window size changed */
3852 if (ttgwsiz() > 0) {
3853 if (tt_rows > 0 && tt_cols > 0) {
3856 debug(F101,"dotype cmd_rows","",cmd_rows);
3857 debug(F101,"dotype cmd_cols","",cmd_cols);
3861 #endif /* CK_TTGWSIZ */
3864 pfxlen = strlen(prefix);
3866 if (paging < 0) { /* Count only, don't print */
3872 if (ucs2) /* Crude... */
3877 ckstrncpy(buf, file, TYPBUFL); /* Change / to \. */
3880 if (*p == '/') *p = '\\';
3890 if (zchki(file) == -2) { /* It's a directory */
3891 debug(F111,"dotype zchki failure",file,-2);
3893 printf("?Not a regular file: \"%s\"\n",file);
3899 if (!zopeni(ZIFILE, file)) { /* Not a directory, open it */
3900 debug(F111,"dotype zopeni failure",file,0);
3902 printf("?Can't open file: \"%s\"\n",file);
3912 oldsig = signal(SIGINT, tytrap); /* Save current interrupt trap. */
3913 /* debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig); */
3917 if (paging > -1) /* More-prompting */
3922 if (head < 0) { /* "tail" was requested */
3923 tailing = 1; /* Set flag */
3924 head = 0 - head; /* Get absolute number of lines */
3926 tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
3928 printf("?Memory allocation failure\n");
3932 tlen = (int *) malloc(head * sizeof(int));
3934 printf("?Memory allocation failure\n");
3938 for (i = 0; i < head; i++) { /* Initialize each pointer in list. */
3948 if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */
3950 initxlate(incs,outcs); /* Set up translation functions */
3952 #endif /* UNICODE */
3953 outcs = -1; /* Means we don't know the charset */
3955 debug(F101,"dotype ffc","",ffc);
3956 debug(F101,"dotype outcs 2","",outcs);
3958 debug(F111,"dotype fileorder","C",fileorder);
3959 #endif /* UNICODE */
3961 /* Allow the buffer to contain NULs */
3964 (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1;
3967 debug(F011,"dotype line",buf,len);
3969 if (typ_int) { /* Interrupted? */
3971 debug(F101,"type interrupted line","",lines);
3972 printf("^C...\n"); /* Print message */
3973 if (ofp != stdout) { /* Close any output file */
3974 if (ofp) fclose(ofp);
3980 typ_lines++; /* For \v(ty_ln) */
3981 if (pat) /* Matching? */
3982 if (!ckmatch(pat,buf,1,1+4)) /* Line matches pattern? */
3983 continue; /* No, skip it */
3986 if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
3989 buf[TYPBUFL+1] = NUL; /* Just in case... */
3990 if (prefix) { /* Add specified prefix to each line */
3995 if (evalpfx) { /* Prefix is a variable? */
3996 int n = 63; /* Maybe - evaluate it and see */
3998 zzstring(prefix,&p,&n); /* If there is no change */
3999 if (!strcmp(prefix,pbuf)) { /* it's not a variable */
4000 evalpfx = 0; /* So don't do this again. */
4001 } else { /* It was a variable */
4002 pp = pbuf; /* So substitute its value */
4003 pfxlen = 63 - n; /* and get its new length */
4007 if (len + pfxlen + 2 < TYPBUFL) {
4008 /* Shift right to make room for prefix */
4009 memcpy((char *)line+pfxlen,(char *)buf,len);
4010 lset((char *)line,pp,pfxlen,SP);
4011 debug(F110,"dotype prefix",line,pfxlen);
4013 memcpy((char *)buf,(char *)line,len);
4015 } else if (number) { /* Line numbers */
4017 sprintf(line,"%4d. ",typ_lines);
4020 if (len < LINBUFSIZ) {
4021 memcpy((char *)&line[x],(char *)buf,len);
4022 memcpy((char *)buf,(char *)line,len);
4025 if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
4026 char * obuf = line; /* But to do that first we must */
4027 int i,k,z; /* expand tabs; assume every 8 cols. */
4029 for (i = 0, k = 0; i < width; k++) { /* Character loop... */
4030 if (!buf[k]) /* No more chars in this line, done. */
4032 if (buf[k] != '\t') { /* If it's not a tab */
4033 if (i >= LINBUFSIZ) /* Check for overflow */
4035 obuf[i++] = buf[k]; /* and then deposit it. */
4036 obuf[i] = NUL; /* Keep it null-terminated */
4039 z = 8 - (i % 8); /* It's a tab, expand it. */
4041 for (j = 0; j < z && i < LINBUFSIZ; j++) {
4043 if (ucs2 && !ucsorder)
4045 #endif /* UNICODE */
4048 if (ucs2 && ucsorder)
4050 #endif /* UNICODE */
4055 obuf[width] = NUL; /* Now truncate at given width. */
4057 /* This doesn't work for UCS-2 because it contains NULs */
4058 ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
4060 memcpy((char *)buf,(char *)obuf,i); /* Copy it back */
4061 #endif /* COMMENT */
4062 len = (i > width) ? width : i; /* Spare us another strlen()... */
4064 if (tailing) { /* If /TAIL:n... */
4065 k = lines % head; /* save this line in circular buffer */
4067 if (tail[k]) free(tail[k]);
4068 tail[k] = malloc(len+2);
4070 printf("?Memory allocation failure\n");
4073 memcpy(tail[k],buf,len);
4078 if (counting) /* If only counting */
4079 continue; /* we're done with this line */
4081 if (paging) { /* Displaying this line... */
4083 u = len; /* Length in BYTES */
4084 if (ucs2) /* If outputting in UCS-2 */
4085 u /= 2; /* convert length to CHARACTERS */
4086 x = (u / cmd_cols) + 1; /* Crudely allow for wrap */
4087 if (cmd_rows > 0 && cmd_cols > 0)
4088 n += x; /* This assumes terminal will wrap */
4093 unsigned short * uch = (unsigned short *)buf;
4094 for ( i=0; i<len/2; i++)
4095 gui_text_popup_append(uch[i]);
4096 gui_text_popup_append(CR);
4097 gui_text_popup_append(LF);
4101 typeline(buf,len,outcs,ofp); /* Print line, length based */
4103 debug(F101,"dotype n","",n);
4104 if (paging > 0 && ofp == stdout) { /* Pause at end of screen */
4105 if (cmd_rows > 0 && cmd_cols > 0) {
4106 if (n > cmd_rows - 3) {
4114 #endif /* CK_TTGWSIZ */
4120 "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
4123 "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
4126 if (tailing && tail) { /* Typing tail of file? */
4127 if (lines < head) { /* Yes, show the lines we saved */
4128 k = 0; /* Show all lines */
4129 } else { /* More lines than tail number */
4130 lines = k; /* Last line to show */
4131 k++; /* First line to show */
4135 n = first; /* Output line counter */
4136 for (i = k ;; i++) { /* Loop thru circular buffer */
4138 if (typ_int) { /* Interrupted? */
4139 printf("^C...\n"); /* Print message */
4143 j = i % head; /* Index of this line */
4144 s = tail[j]; /* Point to line to display */
4145 if (!s) /* (shouldn't happen...) */
4147 if (paging) { /* Crudely allow for line wrap */
4150 x = x / cmd_cols + 1;
4151 if (cmd_rows > 0 && cmd_cols > 0)
4154 typeline(s,tlen[j],outcs,ofp); /* Display this line */
4155 if (paging && ofp == stdout) { /* Pause at end of screen */
4156 if (cmd_rows > 0 && cmd_cols > 0) {
4157 if (n > cmd_rows - 3) {
4166 free(s); /* Free the line */
4167 if (i % head == lines) /* When to stop */
4170 free((char *)tail); /* Free the list */
4172 if (tlen) free((char *)tlen);
4176 /* Come here when finished or on SIGINT */
4181 signal(SIGINT,oldsig); /* Put old signal action back. */
4184 if (tailing && tail) {
4185 for (i = 0; i < head; i++) { /* Free each line. */
4189 free((char *)tail); /* Free list pointer */
4193 x = zclose(ZIFILE); /* Done, close the input file */
4194 if (ofp != stdout) { /* Close any output file */
4195 if (ofp) fclose(ofp);
4198 binary = save; /* Restore text/binary mode */
4200 ucsbom = ucsbom_sav; /* Restore BOM usage */
4201 #endif /* UNICODE */
4205 gui_text_popup_wait(-1); /* Wait for user to close the dialog */
4212 #define GREP_CASE 0 /* /CASE */
4213 #define GREP_COUN 1 /* /COUNT */
4214 #define GREP_DOTF 2 /* /DOTFILES */
4215 #define GREP_NAME 3 /* /NAMEONLY */
4216 #define GREP_NOBK 4 /* /NOBACKUP */
4217 #define GREP_NODO 5 /* /NODOTFILES */
4218 #define GREP_NOLI 6 /* /NOLIST */
4219 #define GREP_NOMA 7 /* /INVERT = /NOMATCH */
4220 #define GREP_NOPA 8 /* /NOPAGE */
4221 #define GREP_NUMS 9 /* /LINENUMBERS */
4222 #define GREP_PAGE 10 /* /PAGE */
4223 #define GREP_RECU 11 /* /RECURSIVE */
4224 #define GREP_TYPE 12 /* /TYPE: */
4225 #define GREP_OUTP 13 /* /OUTPUTFILE: */
4226 #define GREP_EXCP 14 /* /EXCEPT: */
4228 static struct keytab greptab[] = {
4229 { "/count", GREP_COUN, CM_ARG },
4230 { "/dotfiles", GREP_DOTF, 0 },
4231 { "/except", GREP_EXCP, CM_ARG },
4232 { "/linenumbers", GREP_NUMS, 0 },
4233 { "/nameonly", GREP_NAME, 0 },
4234 { "/nobackupfiles",GREP_NOBK, 0 },
4235 { "/nocase", GREP_CASE, 0 },
4236 { "/nodotfiles", GREP_NODO, 0 },
4237 { "/nolist", GREP_NOLI, 0 },
4238 { "/nomatch", GREP_NOMA, 0 },
4239 { "/nopage", GREP_NOPA, 0 },
4240 { "/output", GREP_OUTP, CM_ARG },
4241 { "/page", GREP_PAGE, 0 },
4242 { "/quiet", GREP_NOLI, CM_INV },
4244 { "/recursive", GREP_RECU, 0 },
4245 #endif /* RECURSIVE */
4246 { "/type", GREP_TYPE, CM_ARG },
4249 static int ngreptab = sizeof(greptab)/sizeof(struct keytab)-1;
4251 static char * grep_except = NULL;
4255 int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0;
4256 int fline = 0, sline = 0, wild = 0, len = 0;
4257 int xmode = -1, scan = 0;
4258 char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
4261 int /* Switch values and defaults */
4274 g_matchdot = matchdot; /* Save global matchdot setting */
4276 makestr(&grep_except,NULL);
4278 if (ofp != stdout) { /* In case of previous interruption */
4279 if (ofp) fclose(ofp);
4282 cmfdbi(&sw, /* First FDB - command switches */
4284 "String or pattern to search for, or switch",
4286 "", /* addtl string data */
4287 ngreptab, /* addtl numeric data 1: tbl size */
4288 4, /* addtl numeric data 2: 4 = cmswi */
4289 xxstring, /* Processing function */
4290 greptab, /* Keyword table */
4291 &fl /* Pointer to next FDB */
4293 cmfdbi(&fl, /* Anything that doesn't match */
4297 "", /* addtl string data */
4298 0, /* addtl numeric data 1 */
4299 0, /* addtl numeric data 2 */
4300 xxstring, /* xxstring */
4304 while (1) { /* Parse 0 or more switches */
4305 x = cmfdb(&sw); /* Parse something */
4308 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
4311 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4312 printf("?This switch does not take an argument\n");
4315 if ((cmresult.nresult != GREP_COUN) && !getval &&
4316 (cmgkwflgs() & CM_ARG)) {
4317 printf("?This switch requires an argument\n");
4320 switch (cmresult.nresult) {
4324 if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
4330 case GREP_CASE: gr_case=0; break;
4331 case GREP_NAME: gr_name++; gr_noli=0; break;
4332 case GREP_NOBK: gr_nobk++; break;
4333 case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break;
4334 case GREP_NOMA: gr_noma++; break;
4335 case GREP_NOPA: gr_page=0; break;
4336 case GREP_NUMS: gr_nums++; gr_noli=0; break;
4337 case GREP_PAGE: gr_page++; gr_noli=0; break;
4348 #endif /* RECURSIVE */
4350 extern struct keytab txtbin[];
4351 if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
4353 if (x == 2) { /* ALL */
4355 } else { /* TEXT or BINARY only */
4361 case GREP_OUTP: /* Send output to file */
4362 if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0)
4364 ckstrncpy(outfile,s,CKMAXPATH);
4366 case GREP_EXCP: /* Exception pattern */
4368 if ((x = cmfld("Exception pattern",
4375 makestr(&grep_except,s);
4380 ofp = fopen(outfile,"w"); /* Open output file */
4382 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
4388 s = cmresult.sresult;
4389 s = brstrip(s); /* Strip braces from pattern */
4391 printf("?Pattern required\n");
4394 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save pattern */
4395 if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) {
4397 printf("?File specification required\n");
4402 s = brstrip(s); /* Strip braces from filename */
4404 ckstrncpy(line,s,LINBUFSIZ);
4405 #endif /* ZXREWIND */
4406 if ((y = cmcfm()) < 0)
4410 xaskmore = gr_page; /* Paging... */
4412 p = tmpbuf; /* Point to pattern */
4414 /* Now this is done in ckmatch */
4415 if (*p == '^') { /* '^' anchors pattern to beginning */
4417 } else if (*p != '*') { /* Otherwise prepend implied '*' */
4421 x = strlen(p); /* Get length of result */
4422 if (x > 0 && x < TMPBUFSIZ) { /* '$' at end anchors pattern to end */
4423 if (p[x-1] == '$') {
4425 } else if (p[x-1] != '*') {
4430 #endif /* COMMENT */
4431 debug(F111,"grep pat",p,x);
4434 fc = zxrewind(); /* Rewind the file list */
4437 int flags = ZX_FILONLY; /* Expand file list */
4438 if (matchdot) flags |= ZX_MATCHDOT;
4439 if (recursive) flags |= ZX_RECURSE;
4440 fc = nzxpand(line,flags);
4442 #endif /* ZXREWIND */
4444 sh_sort(mtchs,NULL,fc,0,0,filecase);
4447 debug(F101,"grep cmd_rows","",cmd_rows);
4448 debug(F101,"grep cmd_cols","",cmd_cols);
4450 while (1) { /* Loop for each file */
4451 znext(name); /* Get next file */
4452 if (!name[0]) /* No more, done */
4454 if (gr_nobk) /* Skipping backup files? */
4455 if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */
4456 continue; /* Yes, skip */
4457 if (scan) { /* /TYPE: given? */
4458 switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */
4469 #endif /* UNICODE */
4474 fp = fopen(name,"r"); /* Open */
4475 if (!fp) /* Can't */
4476 continue; /* Skip */
4477 count = 0; /* Match count, this file */
4478 fline = 0; /* Line count, this file */
4479 while (1) { /* Loop for each line */
4480 if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */
4483 debug(F100,"GREP EOF","",0);
4486 fline++; /* Count this line */
4487 line[LINBUFSIZ] = NUL; /* Make sure it's terminated */
4488 debug(F111,"GREP",line,fline);
4489 len = (int)strlen(line); /* Get length */
4490 while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
4491 line[--len] = NUL; /* Chop off terminators */
4492 match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
4493 if (match && gr_excp) {
4494 if (ckmatch(grep_except,line,gr_case,1+4))
4497 if (gr_noma) /* Invert match sense if requested */
4499 if (match) { /* Have a matching line */
4500 mc++; /* Total match count */
4501 count++; /* Match count this file */
4502 if (gr_name) { /* Don't care how many lines match */
4503 fclose(fp); /* Close the file */
4504 fp = NULL; /* and quit the line-reading loop. */
4507 if (gr_coun || gr_noli) /* Not listing each line */
4508 continue; /* so don't print anything now. */
4509 if (wild) { /* If searching multiple files */
4510 fprintf(ofp,"%s:",name); /* print filename. */
4511 len += (int)strlen(name) + 1;
4513 if (gr_nums) { /* If line numbers wanted */
4515 len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
4516 fprintf(ofp,"%s",nbuf);
4518 if (cmd_rows > 0 && cmd_cols > 0)
4519 sline += (len / cmd_cols) + 1;
4520 fprintf(ofp,"%s\n",line); /* Print the line. */
4521 if (sline > cmd_rows - 3) {
4522 if (!askmore()) goto xgrep; else sline = 0;
4526 if (!gr_noli) { /* If not not listing... */
4528 if (gr_coun) { /* Show match count only */
4529 fprintf(ofp,"%s:%d\n",name,count);
4531 } else if (gr_name && count > 0) { /* Show name only */
4532 fprintf(ofp,"%s\n",name);
4536 if (++sline > cmd_rows - 3) {
4537 if (!askmore()) goto xgrep; else sline = 0;
4541 bigcount += count; /* Overall count */
4545 if (gr_coun && cv) { /* /COUNT:blah */
4546 addmac(cv,ckitoa(bigcount)); /* set the variable */
4547 makestr(&cv,NULL); /* free this */
4550 if (fp) fclose(fp); /* close input file if still open */
4551 if (ofp != stdout) { /* Close any output file */
4552 if (ofp) fclose(ofp);
4555 return(success = mc ? 1 : 0);
4558 /* System-independent directory */
4560 static char ** dirlist = NULL;
4561 static int ndirlist = 0;
4567 for (i = 0; i < ndirlist; i++) {
4571 free((char *)dirlist);
4577 static struct keytab dirswtab[] = { /* DIRECTORY command switches */
4578 { "/after", DIR_AFT, CM_ARG },
4579 { "/all", DIR_ALL, 0 },
4581 { "/array", DIR_ARR, CM_ARG },
4583 { "/ascending", DIR_ASC, 0 },
4584 { "/backup", DIR_BUP, 0 },
4585 { "/before", DIR_BEF, CM_ARG },
4586 { "/brief", DIR_BRF, 0 },
4587 { "/count", DIR_COU, CM_ARG },
4588 { "/descending", DIR_DSC, CM_INV },
4589 { "/directories", DIR_DIR, 0 },
4590 { "/dotfiles", DIR_DOT, 0 },
4591 { "/englishdate", DIR_DAT, 0 },
4592 { "/except", DIR_EXC, CM_ARG },
4593 { "/files", DIR_FIL, 0 },
4594 { "/heading", DIR_HDG, 0 },
4595 { "/isodate", DIR_ISO, 0 },
4596 { "/larger-than", DIR_LAR, CM_ARG },
4598 { "/followlinks", DIR_LNK, 0 },
4599 #endif /* CKSYMLINK */
4600 { "/message", DIR_MSG, CM_ARG },
4601 { "/nobackupfiles",DIR_NOB, 0 },
4602 { "/nodotfiles", DIR_NOD, 0 },
4604 { "/nofollowlinks",DIR_NLK, 0 },
4605 #endif /* CKSYMLINK */
4606 { "/noheading", DIR_NOH, 0 },
4608 { "/nolinks", DIR_NOL, 0 },
4609 #endif /* CKSYMLINK */
4610 { "/nomessage", DIR_NOM, 0 },
4612 { "/nopage", DIR_NOP, 0 },
4613 #endif /* CK_TTGWSIZ */
4615 { "/norecursive", DIR_NOR, 0 },
4618 { "/norecursive", DIR_NOR, 0 },
4621 { "/norecursive", DIR_NOR, 0 },
4622 #endif /* datageneral */
4624 #endif /* RECURSIVE */
4625 { "/nosort", DIR_NOS, 0 },
4626 { "/not-after", DIR_NAF, CM_ARG },
4627 { "/not-before", DIR_NBF, CM_ARG },
4628 { "/not-since", DIR_NAF, CM_INV|CM_ARG },
4629 { "/noxfermode", DIR_NOT, 0 },
4630 { "/output", DIR_OUT, CM_ARG },
4632 { "/page", DIR_PAG, 0 },
4633 #endif /* CK_TTGWSIZ */
4635 { "/recursive", DIR_REC, 0 },
4638 { "/recursive", DIR_REC, 0 },
4641 { "/recursive", DIR_REC, 0 },
4642 #endif /* datageneral */
4644 #endif /* RECURSIVE */
4645 { "/reverse", DIR_DSC, 0 },
4646 { "/since", DIR_AFT, CM_ARG|CM_INV },
4647 { "/smaller-than",DIR_SMA, CM_ARG },
4648 { "/sort", DIR_SRT, CM_ARG },
4649 { "/summary", DIR_SUM, 0 },
4650 { "/top", DIR_TOP, CM_ARG },
4651 { "/type", DIR_BIN, CM_ARG },
4652 { "/xfermode", DIR_TYP, 0 },
4653 { "/verbose", DIR_VRB, 0 },
4656 static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
4658 static struct keytab dirsort[] = { /* DIRECTORY /SORT: options */
4659 { "date", DIRS_DT, 0 },
4660 { "name", DIRS_NM, 0 },
4661 { "size", DIRS_SZ, 0 }
4663 static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
4665 static int dir_date = -1; /* Option defaults (-1 means none) */
4666 static int dir_page = -1;
4667 static int dir_verb = 1;
4668 static int dir_msg = -1;
4670 static int dir_sort = -1; /* Names are already sorted in VMS */
4671 static int dir_rvrs = -1;
4673 static int dir_sort = 1; /* Sort by default */
4674 static int dir_rvrs = 0; /* Not in reverse */
4676 static int dir_skey = DIRS_NM; /* By name */
4678 static int dir_recu = -1;
4679 #endif /* RECURSIVE */
4680 static int dir_mode = -1;
4681 static int dir_show = -1; /* Show all files by default */
4682 int dir_dots = -1; /* Except dot files */
4685 static char * dirmsg = NULL;
4686 static int dirmsglen = 0;
4692 extern int optlines;
4693 prtopt(&optlines,"DIRECTORY");
4695 prtopt(&optlines,(dir_show == 1) ? "/FILES" :
4696 ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
4699 prtopt(&optlines,"/ALL");
4702 if (dir_verb > -1) {
4703 prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
4706 if (dir_page > -1) {
4707 prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
4710 if (dir_date > -1) {
4711 prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
4714 if (dir_dots > -1) {
4715 prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
4718 if (dir_back > -1) {
4719 prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
4722 if (dir_head > -1) {
4723 prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
4727 if (dir_recu > -1) {
4728 prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
4731 #endif /* RECURSIVE */
4732 if (dir_mode > -1) {
4733 prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
4736 if (dir_sort == 0) {
4738 prtopt(&optlines,"/NOSORT ");
4739 } else if (dir_sort > 0) {
4741 if (dir_skey == DIRS_NM) s = "/SORT:NAME";
4742 else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
4743 else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
4744 prtopt(&optlines,s);
4746 if (dir_rvrs > -1) {
4747 prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
4752 prtopt(&optlines,"/NOMESSAGE");
4754 ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL);
4755 prtopt(&optlines,tmpbuf);
4759 if (!x) prtopt(&optlines,"(no options set)");
4760 prtopt(&optlines,"");
4765 setdiropts() { /* Set DIRECTORY option defaults */
4766 int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
4767 int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
4771 if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
4778 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4779 printf("?This switch does not take an argument\n");
4782 if (!getval && (cmgkwflgs() & CM_ARG)) {
4783 printf("?This switch requires an argument\n");
4787 case DIR_BRF: xv = 0; break;
4788 case DIR_VRB: xv = 1; break;
4789 case DIR_PAG: xp = 1; break;
4790 case DIR_NOP: xp = 0; break;
4791 case DIR_ISO: xd = 0; break;
4792 case DIR_DAT: xd = 1; break;
4793 case DIR_HDG: xh = 1; break;
4794 case DIR_NOH: xh = 0; break;
4795 case DIR_DOT: xf = 1; break;
4796 case DIR_NOD: xf = 0; break;
4797 case DIR_ALL: xa = 3; break;
4798 case DIR_DIR: xa = 2; break;
4799 case DIR_FIL: xa = 1; break;
4803 if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
4808 case DIR_NOS: xs = 0; break;
4809 case DIR_ASC: xx = 0; break;
4810 case DIR_DSC: xx = 1; break;
4811 case DIR_REC: xr = 1; break;
4812 case DIR_NOR: xr = 0; break;
4813 case DIR_TYP: xm = 1; break;
4814 case DIR_NOT: xm = 0; break;
4815 case DIR_BUP: xb = 1; break;
4816 case DIR_NOB: xb = 0; break;
4817 case DIR_NOM: xg = 0; break;
4820 if ((x = cmfld("Message to append to each line",
4827 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
4830 printf("?This option can not be set\n");
4834 if ((x = cmcfm()) < 0) /* Get confirmation */
4836 if (xv > -1) dir_verb = xv; /* Confirmed, save defaults */
4837 if (xp > -1) dir_page = xp;
4838 if (xd > -1) dir_date = xd;
4839 if (xh > -1) dir_head = xh;
4840 if (xs > -1) dir_sort = xs;
4841 if (xk > -1) dir_skey = xk;
4842 if (xx > -1) dir_rvrs = xx;
4843 if (xf > -1) dir_dots = xf;
4844 if (xa > -1) dir_show = xa;
4845 if (xm > -1) dir_mode = xm;
4846 if (xb > -1) dir_back = xb;
4848 if (xr > -1) dir_recu = xr;
4849 #endif /* RECURSIVE */
4850 if (xg > -1) dir_msg = xg;
4852 makestr(&dirmsg,tmpbuf);
4853 return(success = 1);
4857 domydir(cx) int cx; { /* Internal DIRECTORY command */
4858 extern char *months[];
4860 _PROTOTYP( char * zrelname, (char *,char *) );
4864 char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
4865 char linebuf[CKMAXPATH+256];
4866 char * mstr = NULL, * dstr = NULL, * s2 = NULL, * cv = NULL;
4867 CK_OFF_T len = (CK_OFF_T)0, nbytes = (CK_OFF_T)0;
4868 CK_OFF_T minsize = (CK_OFF_T)-1, maxsize = (CK_OFF_T)-1;
4869 long ndirs = 0, nfiles = 0, nmatches = 0;
4870 int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0;
4871 int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
4872 int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
4873 int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
4877 int cmifn1 = 1, cmifn2 = 0;
4878 int dir_top = 0, dir_cou = 0;
4879 int dontshowlinks = 0;
4880 int dontfollowlinks = 0;
4881 int arrayindex = -1;
4882 struct FDB sw, fi, fl;
4883 char dbuf[32], xbuf[32];
4897 debug(F101,"domydir cx","",cx);
4899 g_matchdot = matchdot; /* Save global matchdot setting */
4901 nolinks = 2; /* (it should already be 2) */
4902 #endif /* COMMENT */
4903 outfile[0] = NUL; /* No output file yet */
4905 if (ofp != stdout) { /* In case of previous interruption */
4906 if (ofp) fclose(ofp);
4909 for (i = 0; i < 16; i++) xlist[i] = NULL;
4913 freedirlist(); /* In case not freed last time */
4914 page = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
4915 engdate = dir_date > -1 ? dir_date : 0;
4916 verbose = dir_verb > -1 ? dir_verb : 1;
4917 heading = dir_head > -1 ? dir_head : 0;
4918 xsort = dir_sort > -1 ? dir_sort : 0;
4919 sortby = dir_skey > -1 ? dir_skey : 0;
4920 reverse = dir_rvrs > -1 ? dir_rvrs : 0;
4921 msg = dir_msg > -1 ? dir_msg : 0;
4923 if (dir_dots > -1) matchdot = dir_dots;
4924 #endif /* UNIXOROSK */
4925 xfermod = dir_mode > -1 ? dir_mode : 0;
4926 backup = dir_back > -1 ? dir_back : 1;
4928 recursive = dir_recu > -1 ? dir_recu : 0;
4929 #endif /* RECURSIVE */
4930 show = dir_show > -1 ? dir_show : 3;
4932 if (cx == XXWDIR) { /* WDIRECTORY */
4933 debug(F100,"domydir WDIRECTORY","",0);
4934 reverse = 1; /* Reverse chronological order */
4937 } else if (cx == XXHDIR) { /* HDIRECTORY */
4938 debug(F100,"domydir HDIRECTORY","",0);
4939 reverse = 1; /* Reverse order by size */
4942 } else if (cx == XXTOUC) {
4949 ttgcwsz(); /* Screen length for more-prompting */
4951 /* Check whether window size changed */
4952 if (ttgwsiz() > 0) {
4953 if (tt_rows > 0 && tt_cols > 0) {
4959 #endif /* CK_TTGWSIZ */
4962 cmifn1 = nolinks | 1; /* 1 = files or directories */
4963 cmifn2 = 0; /* 0 = not directories only */
4967 cmfdbi(&sw, /* First FDB - command switches */
4969 "Enter or Return to confirm the command, or\n\
4970 file specification, or switch",
4972 "", /* addtl string data */
4973 ndirswtab, /* addtl numeric data 1: tbl size */
4974 4, /* addtl numeric data 2: 4 = cmswi */
4975 xxstring, /* Processing function */
4976 dirswtab, /* Keyword table */
4977 &fi /* Pointer to next FDB */
4979 cmfdbi(&fi, /* 2nd FDB - filespec to match */
4981 "File specification", /* hlpmsg */
4983 "+", /* Default filespec is wildcard */
4984 #else /* that matches all files... */
4990 #endif /* datageneral */
4991 "", /* addtl string data */
4993 cmifn2, /* 1 = only dirs; 0 files or dirs */
4998 cmfdbi(&fl, /* Anything that doesn't match */
5002 "", /* addtl string data */
5003 0, /* addtl numeric data 1 */
5004 0, /* addtl numeric data 2 */
5009 while (1) { /* Parse 0 or more switches */
5010 x = cmfdb(&sw); /* Parse something */
5011 debug(F101,"domydir cmfdb","",x);
5014 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
5017 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5018 printf("?This switch does not take an argument\n");
5021 k = cmresult.nresult;
5023 (cmgkwflgs() & CM_ARG) && k != DIR_TOP && k != DIR_COU) {
5024 printf("?This switch requires an argument\n");
5031 if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
5037 case DIR_BRF: verbose = 0; break;
5038 case DIR_VRB: verbose = 1; break;
5040 case DIR_PAG: page = 1; break;
5041 case DIR_NOP: page = 0; break;
5042 #endif /* CK_TTGWSIZ */
5043 case DIR_ISO: engdate = 0; break;
5044 case DIR_DAT: engdate = 1; break;
5045 case DIR_HDG: heading = 1; break;
5046 case DIR_NOH: heading = 0; break;
5048 case DIR_DOT: matchdot = 1; break;
5049 case DIR_NOD: matchdot = 0; break;
5050 #endif /* UNIXOROSK */
5068 if (c == ':' || c == '=')
5069 if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
5075 case DIR_BUP: backup = 1; fs++; break;
5076 case DIR_NOB: backup = 0; fs++; break;
5078 case DIR_NOS: xsort = 0; break;
5079 case DIR_ASC: reverse = 0; break;
5080 case DIR_DSC: reverse = 1; break;
5082 case DIR_REC: recursive = 1; diractive = 1; break;
5083 case DIR_NOR: recursive = 0; diractive = 0; break;
5084 #endif /* RECURSIVE */
5085 case DIR_TYP: xfermod = 1; break;
5086 case DIR_NOT: xfermod = 0; break;
5089 case DIR_LNK: /* Follow links */
5091 /* A command switch shouldn't be setting a global value! */
5093 #endif /* COMMENT */
5095 dontfollowlinks = 0;
5097 case DIR_NLK: /* Don't follow links */
5100 #endif /* COMMENT */
5102 dontfollowlinks = 1;
5104 case DIR_NOL: /* Don't show links at all */
5107 #endif /* CKSYMLINK */
5109 case DIR_NOM: msg = 0; break;
5111 if (c == ':' || c == '=')
5112 if ((x = cmfld("Message to append to each line",
5119 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
5126 if ((x = cmnumw("File size in bytes","0",10,&y,xxstring)) < 0)
5130 switch (cmresult.nresult) {
5131 case DIR_SMA: minsize = y; break;
5132 case DIR_LAR: maxsize = y; break;
5139 if ((x = cmnum("How many lines to show","10",10,&y,xxstring))< 0)
5146 if (c != ':' && c != '=') {
5147 printf("?Array name required\n");
5150 if ((x = cmfld("Array name (a single letter will do)",
5156 printf("?Array name required\n");
5162 printf("?Array name required\n");
5166 if (*s == CMDQ) s++;
5169 printf("?Bad array name - \"%s\"\n",s2);
5173 if (isupper(array)) array = tolower(array);
5174 if (*s && (*s != '[' || *(s+1) != ']')) {
5175 printf("?Bad array name - \"%s\"\n",s2);
5185 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
5187 printf("?Date-time required\n");
5195 case DIR_AFT: makestr(&dir_aft,s); break;
5196 case DIR_BEF: makestr(&dir_bef,s); break;
5197 case DIR_NAF: makestr(&dir_naf,s); break;
5198 case DIR_NBF: makestr(&dir_nbf,s); break;
5203 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5205 printf("?Pattern required\n");
5212 makestr(&dir_exc,s);
5219 extern struct keytab txtbin[];
5220 extern int xfiletype;
5222 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) {
5235 if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0)
5237 ckstrncpy(outfile,s,CKMAXPATH+1);
5241 printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
5245 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
5247 /* ^^^ START MULTIPLE */
5250 x = cmfld("Another filespec or Enter","",&s,xxstring);
5255 ckstrncat(line,",",LINBUFSIZ);
5256 ckstrncat(line,s,LINBUFSIZ);
5259 ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL);
5260 ckstrncpy(line,tmpbuf,LINBUFSIZ);
5261 cmresult.nresult = 1;
5262 cmresult.fcode = _CMIFI;
5264 /* ^^^ END MULTIPLE */
5268 if ((x = cmcfm()) < 0) /* Get confirmation */
5272 Command is TOUCH and file doesn't exist.
5274 if (touch) { /* TOUCH */
5275 if ((cmresult.fcode == _CMIFI && zchki(s) == (CK_OFF_T)-1)) {
5281 s = tilde_expand(s);
5283 fp = fopen(s,"w"); /* Create file */
5285 printf("?TOUCH %s: %s\n",s,ck_errstr());
5290 cx = XXDIR; /* Now maybe list it. */
5291 multiple++; /* Force new directory scan */
5296 if (cmresult.fcode != _CMIFI) { /* Nothing matched */
5298 Note - this never gets executed because after the "begin
5299 multiple" hack above, the result is always _CMIFI).
5304 m = "does not match switch or name of accessible file";
5307 m = "does not match switch or name of accessible file";
5309 m = "no switches match";
5311 #endif /* UNIXOROSX */
5313 m = "not found or not accessible";
5314 printf("\"%s\" - %s\n",s,m);
5319 /* This can't be right because it's based on _CMCFM */
5320 wild = cmresult.nresult; /* Wildcard was given? */
5321 debug(F111,"domydir cmifi2",s,wild);
5324 #endif /* COMMENT */
5326 if (outfile[0]) { /* If an output file was specified */
5327 ofp = fopen(outfile,"w"); /* open it */
5329 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
5338 if (zchki(s) == -2) { /* Found a directory */
5339 p = s + (int)strlen(s) - 1; /* Yes */
5340 if (*p == '\\' || *p == '/')
5346 wild = 1; /* Now it's wild */
5350 if (!wild) if (isdir(s)) { /* Is it a directory? */
5351 p = s + (int)strlen(s) - 1; /* Yes */
5354 /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
5355 char buf[CKMAXPATH+1];
5356 debug(F000,"domydir directory 0",s,*p);
5357 if (cvtdir(s,buf,CKMAXPATH) > 0)
5358 ckstrncpy(line,buf,LINBUFSIZ);
5361 debug(F000,"domydir directory 1",s,*p);
5363 if (*p == ']' || *p == '>' || *p == ':')
5377 #endif /* STRATUS */
5378 #endif /* datageneral */
5380 wild = 1; /* Now it's wild */
5381 debug(F000,"domydir directory 2",s,*p);
5386 /* cmifi() already called nzxpand so we can just re-use the same list. */
5388 x = zxrewind(); /* Rewind the list */
5389 debug(F111,"domydir zxrewind",s,x);
5391 #endif /* ZXREWIND */
5393 In case we gave multiple filespecs they are now in {a,b,c} list format.
5394 Which is a valid wildcard. We pass it to nzxpand() to get back the list
5395 of files that match. This is fine for DIRECTORY but it's not find for
5396 TOUCH because we want TOUCH to see those names so it can create the files.
5397 So for now at least, if TOUCH is to be used to create files -- as opposed
5398 to changing the timestamps of existing files -- it can only do one file
5401 nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
5402 (show == ZX_FILONLY ? ZX_FILONLY : 0);
5403 if (matchdot) nzxopts |= ZX_MATCHDOT;
5404 if (recursive) nzxopts |= ZX_RECURSE;
5405 x = nzxpand(s,nzxopts); /* Expand file list */
5406 debug(F111,"domydir nzxpand",s,x);
5409 #endif /* ZXREWIND */
5414 n = (x < 0) ? 0 : x;
5415 if ((xx = dclarray(array,n)) < 0) {
5416 printf("?Array declaration failure\n");
5421 ap = a_ptr[xx]; /* Pointer to list of elements */
5422 if (ap) /* Set element 0 to dimension */
5423 makestr(&(ap[0]),"0"); /* which so far is zero */
5424 if (n < 1) { /* No files matched, done. */
5430 if (!touch && x < 1) {
5432 extern int ckrooterr;
5434 printf("?Off limits: %s\n",s);
5437 if (x == 0 && isdir(s))
5438 printf("?Empty directory - \"%s\"\n", s);
5440 printf("?%s %s match - \"%s\"\n",
5441 (x == 0) ? "No" : "Too many",
5442 (show == 2) ? "directories" : "files",
5448 nx = x; /* Remember how many files */
5449 if (nx < 2) xsort = 0; /* Skip sorting if none or one */
5452 makestr(&dirmsg,tmpbuf);
5453 dirmsglen = strlen(tmpbuf);
5457 cdp = zgtdir(); /* Get current directory */
5458 debug(F110,"domydir VMS zgtdir",cdp,0);
5461 if (xsort && verbose) { /* If sorting, allocate space */
5462 if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
5464 printf("* Warning: Failure to allocate memory for sorting.\n");
5465 printf("* Will proceed without sorting...\n");
5469 debug(F101,"domydir sort malloc","",xsort);
5472 /* Display the listing */
5475 if (array) /* Storing instead of printing */
5479 if (heading) { /* If /HEADING print heading */
5480 zfnqfp(s,TMPBUFSIZ,tmpbuf);
5481 fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf);
5484 if (page > -1) /* Paging */
5487 if (!verbose && !touch) { /* /BRIEF */
5488 if (outfile[0]) { /* To file */
5491 while (name[0]) { /* One line per file */
5493 if (fs) if (fileselect(name,
5494 dir_aft,dir_bef,dir_naf,dir_nbf,
5495 minsize,maxsize,!backup,16,xlist) < 1) {
5499 fprintf(ofp,"%s\n",name);
5503 fprintf(ofp,"Files: %d\n\n",k);
5507 rc = xfilhelp(x,"","",n,0,1,
5508 dir_aft,dir_bef,dir_naf,dir_nbf,
5509 minsize,maxsize,!backup,16,xlist);
5512 if (heading && rc > 0)
5513 fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */
5518 ndirs = nfiles = 0L; /* Initialize counters */
5519 nbytes = (CK_OFF_T)0;
5521 if (dir_exc) /* Have exception list? */
5522 makelist(dir_exc,xlist,16); /* Yes, convert to array */
5525 znext(name); /* Get next file */
5526 while (name[0]) { /* Loop for each file */
5527 if (fs) if (fileselect(name,
5528 dir_aft,dir_bef,dir_naf,dir_nbf,
5529 minsize,maxsize,!backup,16,xlist) < 1) {
5533 len = zgetfs(name); /* Get file length */
5534 debug(F111,"domydir zgetfs",name,len);
5536 itsadir = zgfs_dir; /* See if it's a directory */
5538 itsadir = (len == (CK_OFF_T)-2 || isdir(name));
5539 #endif /* VMSOUNIX */
5540 debug(F111,"domydir itsadir",name,itsadir);
5541 if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
5545 /* Get here when we know we have selected this file */
5548 if (itsadir) { /* Accumulate totals for summary */
5555 if (cx == XXTOUC) { /* Command was TOUCH, not DIRECTORY */
5558 dstr = ckcvtdate("",0);
5560 xx.date.len = (int)strlen(xx.date.val);
5561 xx.lprotect.len = 0;
5562 debug(F110,"domydir touch",name,0);
5563 debug(F110,"domydir touch",dstr,0);
5564 if (zstime(name,&xx,0) < 0) {
5565 printf("?TOUCH %s: %s\n",name,ck_errstr());
5569 if (!verbose) { /* No listing so skip detail */
5574 if (summary) { /* Summary only, no detail */
5581 debug(F111,"domydir array",name,nfiles);
5583 makestr(&(ap[nmatches]),name);
5590 NOTE: The sprintf's in this routine should be safe. They involve
5591 permission strings, date/time strings, and filenames, all of which have
5592 known maximum lengths; none of these items is input from users. The
5593 destination buffers are large enough to hold maximum sizes for any and
5594 all items. NOTE 2: If command was TOUCH, dstr was already set just
5597 if (!dstr) { /* Get file's modification date/time */
5598 dstr = zfcdat(name);
5599 debug(F111,"domydir zcfdat",dstr,0);
5601 if (!dstr) dstr = "";
5604 Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings
5605 about possible out-of-bounds dstr[] array refs do not apply. This block of
5606 code is to stifle the warnings and also allows for any out-of-spec
5607 zfcdat() implementations.
5610 char * p = "00000000 00:00:00";
5611 x = ckstrncpy(xbuf,dstr,32);
5612 if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x);
5615 if (engdate) { /* English date requested? */
5616 short month, day, year, hour, minute, seconds;
5617 month = (dstr[4]-48)*10 + (dstr[5]-48);
5618 mstr = (month > 0 && month <= 12) ? months[month-1] : "xxx";
5619 day = (dstr[6]-48)*10 + (dstr[7]-48);
5620 year = (((dstr[0]-48)*10 +
5624 hour = (dstr[9]-48)*10 + (dstr[10]-48);
5625 minute = (dstr[12]-48)*10 + (dstr[13]-48);
5626 seconds = (dstr[15]-48)*10 + (dstr[16]-48);
5627 sprintf(dbuf, /* SAFE */
5628 "%2d-%s-%4d %02d:%02d:%02d",
5629 day,mstr,year,hour,minute,seconds
5632 } else { /* ISO date */
5633 dbuf[0] = dstr[0]; /* yyyy */
5638 dbuf[5] = dstr[4]; /* mm (numeric) */
5641 dbuf[8] = dstr[6]; /* dd */
5643 strcpy(dbuf+10,dstr+8); /* hh:mm:ss */
5646 dlen = strlen(dbuf); /* Length of date */
5647 name[CKMAXPATH] = NUL;
5650 p = ziperm(name); /* Get permissions */
5651 debug(F110,"ziperm perms",p,0);
5654 debug(F110,"zgperm perms",p,0);
5655 #endif /* VMSORUNIX */
5658 debug(F110,"NULL perms",p,0);
5659 #endif /* CK_PERMS */
5662 /* Get relative name to save space -- VMS fullnames are long... */
5663 ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
5666 if (itsadir && len < (CK_OFF_T)0) { /* Directory */
5668 sprintf(linebuf,"%-22s%-10s %s %s",p,"<DIR>",dstr,name);
5671 sprintf(linebuf,"%10s%-10s %s %s",p,"<DIR>",dstr,name);
5673 sprintf(linebuf,"%-10s %s %s", "<DIR>", dstr, name);
5675 } else { /* Regular file */
5677 sprintf(linebuf,"%-22s%10s %s %s", p, ckfstoa(len), dstr, name);
5680 sprintf(linebuf,"%10s%10s %s %s", p, ckfstoa(len), dstr, name);
5682 sprintf(linebuf,"%10s %s %s", ckfstoa(len), dstr, name);
5687 if (zgfs_link) { /* If it's a symlink */
5688 if (dontshowlinks) { /* If /NOLINKS don't show it */
5693 if (zgfs_link && !dontfollowlinks) { /* Symlink and following links */
5694 int n, m; /* Show what the link points to */
5695 extern char linkname[];
5696 n = strlen(linebuf);
5697 m = strlen(linkname) + n;
5698 if (m < CKMAXPATH + 58)
5699 strcpy(linebuf+n, " -> "); /* safe (checked) */
5700 if (m + 4 < CKMAXPATH - 58)
5701 strcpy(linebuf+n+4, linkname); /* safe (checked) */
5703 #endif /* CKSYMLINK */
5705 if (xfermod) { /* Show transfer mode */
5709 x = scanfile(name,&y,nscanfile);
5711 case FT_TEXT: s = " (T)"; break;
5712 case FT_7BIT: s = " (T)(7BIT)"; break;
5713 case FT_8BIT: s = " (T)(8BIT)"; break;
5715 case FT_UTF8: s = " (T)(UTF8)"; break;
5717 s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)";
5719 #endif /* UNICODE */
5720 case FT_BIN: s = " (B)"; break;
5723 s = binary ? " (B)" : " (T)";
5727 n = strlen(linebuf);
5728 if (n + 4 < CKMAXPATH - 58)
5729 strcpy(linebuf+n, s); /* safe (checked) */
5732 if (msg && dirmsg) {
5734 n = strlen(linebuf);
5735 if (n + dirmsglen + 2 < CKMAXPATH)
5736 sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */
5738 if (xsort) { /* Sorting - save line */
5739 i = strlen(linebuf);
5740 if ((ndirlist >= nx) ||
5741 !(dirlist[ndirlist] = (char *)malloc(i+1))) {
5742 printf("?Memory allocation error - try /NOSORT\n");
5746 strcpy(dirlist[ndirlist],linebuf); /* safe */
5749 znext(name); /* Peek ahead to next file */
5751 if (!touch || (touch && verbose))
5752 fprintf(ofp,"%s\n",linebuf);
5753 if (page && (name[0] || heading)) { /* If /PAGE */
5755 int x = strlen(linebuf);
5757 y = (x % cmd_cols) ? 1 : 0;
5758 n += x / cmd_cols + y;
5763 if (n > (cmd_rows - 3)) { /* Do more-prompting */
5770 #endif /* CK_TTGWSIZ */
5777 makestr(&(ap[0]),ckitoa(nmatches));
5786 namepos = dlen + 35;
5788 case DIRS_NM: skey = namepos; break;
5789 case DIRS_DT: skey = 33; break;
5790 case DIRS_SZ: skey = 21;
5794 namepos = dlen + 24;
5796 case DIRS_NM: skey = namepos; break;
5797 case DIRS_DT: skey = 22; break;
5798 case DIRS_SZ: skey = 10;
5801 namepos = dlen + 14;
5803 case DIRS_NM: skey = namepos; break;
5804 case DIRS_DT: skey = 12; break;
5805 case DIRS_SZ: skey = 0;
5809 sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
5810 if (dir_top > 0 && dir_top < ndirlist)
5812 for (i = 0; i < ndirlist; i++) {
5813 fprintf(ofp,"%s\n",dirlist[i]);
5814 if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */
5816 int x = strlen(dirlist[i]);
5818 y = (x % cmd_cols) ? 1 : 0;
5819 n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
5824 if (n > (cmd_rows - 3)) { /* Do more-prompting */
5831 #endif /* CK_TTGWSIZ */
5836 if (heading || summary) {
5839 #endif /* CKFLOAT */
5840 fprintf(ofp,"\n%ld director%s, %ld file%s, %s byte%s",
5842 (ndirs == 1) ? "y" : "ies",
5844 (nfiles == 1) ? "" : "s",
5846 (nbytes == 1) ? "" : "s"
5849 gm = ((CKFLOAT) nbytes ) / 1000000.0;
5851 fprintf(ofp," (%0.2fGB)",(gm / 1000.0));
5852 else if (gm >= 0.01)
5853 fprintf(ofp," (%0.2fMB)",gm);
5854 #endif /* CKFLOAD */
5855 fprintf(ofp,"\n\n");
5856 } else if (dir_cou && !cv) {
5857 fprintf(ofp,"\n Files: %ld\n\n",nfiles);
5861 if (dir_cou && cv) { /* /COUNT:var */
5862 addmac(cv,ckitoa(nfiles)); /* set the variable */
5863 makestr(&cv,NULL); /* free this */
5865 if (ap) { /* If we have a result array */
5866 if (a_dim[arrayindex] > nmatches) /* but it was not filled */
5867 a_dim[arrayindex] = nmatches; /* adjust dimension */
5870 if (g_matchdot > -1) {
5871 matchdot = g_matchdot; /* Restore these... */
5875 if (ofp != stdout) { /* Close any output file */
5876 if (ofp) fclose(ofp);
5885 dodir(cx) int cx; { /* Do the DIRECTORY command */
5889 return(domydir(cx));
5892 #ifdef DOMYDIR /* Builds that domydir() by default */
5893 || (cx == XXDIR || cx == XXLDIR || cx == XXWDIR ||
5894 cx == XXHDIR || cx == XXTOUC)
5895 #endif /* DOMYDIR */
5897 return(domydir(cx)); /* Built-in directory command */
5899 /* Use the system's directory command. */
5901 msg = (cx == XXLS) ?
5902 "Arguments for ls" :
5903 "Directory and/or file specification";
5904 if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
5907 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy the filespec */
5910 if ((y = cmcfm()) < 0) return(y);
5913 if (!(dc = getenv("CK_DIR")))
5915 ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL);
5916 debug(F110,"DIR",line,0);
5922 concb((char)escape);
5924 return(success = (x < 1) ? 0 : 1);
5930 /* Do the ENABLE and DISABLE commands */
5933 doenable(y,x) int y, x; {
5935 if (isguest) /* IKSD: Don't let guests */
5936 return(0); /* enable anything that's disabled */
5937 #endif /* CK_LOGIN */
5940 en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
5941 en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
5943 en_who = en_mai = en_pri = y;
5944 en_mkd = en_rmd = y;
5948 #endif /* datageneral */
5950 if (!nopush && !inserver)
5954 en_asg = en_que = y;
5961 In Data General AOS/VS Kermit can't log out its superior process.
5964 #endif /* datageneral */
5972 if (inserver && y == 0) {
5978 case EN_DEL: /* Deleting of files */
6028 printf("?Sorry, not valid for guests\n");
6031 #endif /* CK_LOGIN */
6037 printf("?Sorry, not valid for guests\n");
6040 #endif /* CK_LOGIN */
6053 if (((y & 1) && !(en_ena & 1)) ||
6054 ((y & 2) && !(en_ena & 2))) {
6055 printf("?Sorry, DISABLE ENABLE can not be undone\n");
6066 #endif /* NOFRILLS */
6067 #endif /* NOSERVER */
6071 static int del_lis = 0;
6072 static int del_dot = 0;
6073 static int del_hdg = 0;
6074 static int del_pag = -1;
6075 static int del_ask = 0;
6081 extern int optlines;
6082 prtopt(&optlines,"");
6083 prtopt(&optlines,"DELETE");
6085 prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
6090 prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
6093 #endif /* UNIXOROSK */
6095 prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
6099 prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
6104 prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
6107 #endif /* CK_TTGWSIZ */
6108 if (!x) prtopt(&optlines,"(no options set)");
6109 prtopt(&optlines,"");
6116 int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
6120 if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
6127 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
6128 printf("?This switch does not take an argument\n");
6131 if (!getval && (cmgkwflgs() & CM_ARG)) {
6132 printf("?This switch requires an argument\n");
6158 #endif /* CK_TTGWSIZ */
6172 printf("?Sorry, this option can not be set\n");
6176 if ((x = cmcfm()) < 0) /* Get confirmation */
6178 if (x_pag > -1) del_pag = x_pag;
6179 if (x_dot > -1) del_dot = x_dot;
6180 if (x_hdg > -1) del_hdg = x_hdg;
6181 if (x_lis > -1) del_lis = x_lis;
6182 if (x_ask > -1) del_ask = x_ask;
6183 return(success = 1);
6187 static char ** xmtchs = NULL;
6188 static int xmtchn = 0;
6192 dodel() { /* DELETE */
6194 int fs = 0; /* Need to call fileselect() */
6197 int getval = 0, asking = 0;
6198 int simulate = 0, rc = 0;
6199 CK_OFF_T minsize = -1L, maxsize = -1L;
6200 int havename = 0, confirmed = 0;
6207 int xmode = -1, scan = 0, skip = 0;
6210 #endif /* COMMENT */
6213 char safebuf[CKMAXPATH+1];
6214 struct FDB sw, fi, fl;
6228 for (i = 0; i < 8; i++) dxlist[i] = NULL;
6230 g_matchdot = matchdot;
6232 if (del_lis > -1) x_lis = del_lis;
6233 if (del_dot > -1) matchdot = del_dot;
6234 if (del_hdg > -1) x_hdg = del_hdg;
6235 if (del_pag > -1) xaskmore = del_pag;
6236 if (del_ask > -1) asking = del_ask;
6239 nolinks = 2; /* By default don't follow links */
6241 cmfdbi(&sw, /* First FDB - command switches */
6243 "File specification;\n or switch",
6245 "", /* addtl string data */
6246 ndeltab, /* addtl numeric data 1: tbl size */
6247 4, /* addtl numeric data 2: 4 = cmswi */
6248 xxstring, /* Processing function */
6249 deltab, /* Keyword table */
6250 &fi /* Pointer to next FDB */
6252 cmfdbi(&fl, /* Anything that doesn't match */
6256 "", /* addtl string data */
6257 0, /* addtl numeric data 1 */
6258 0, /* addtl numeric data 2 */
6264 cmfdbi(&fi, /* 2nd FDB - file to delete */
6266 "File(s) to delete", /* hlpmsg */
6267 deldef, /* default */
6268 "", /* addtl string data */
6269 nolinks | deldirs, /* 0 = files, 1 = files or dirs */
6270 0, /* 1 = dirs only */
6275 while (!havename && !confirmed) {
6276 x = cmfdb(&sw); /* Parse something */
6277 if (x < 0) { /* Error */
6280 if (x == -2 || x == -9)
6281 printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
6284 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
6286 c = cmgbrk(); /* Get break character */
6287 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
6288 printf("?This switch does not take an argument\n");
6292 if (!getval && (cmgkwflgs() & CM_ARG)) {
6293 printf("?This switch requires an argument\n");
6297 switch (k = cmresult.nresult) {
6303 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
6305 printf("?Date-time required\n");
6314 case DEL_AFT: makestr(&del_aft,s); break;
6315 case DEL_BEF: makestr(&del_bef,s); break;
6316 case DEL_NAF: makestr(&del_naf,s); break;
6317 case DEL_NBF: makestr(&del_nbf,s); break;
6329 deldef = "*.*"; /* UNIX, Windows, OS/2 */
6332 deldef = "+"; /* AOS/VS */
6334 deldef = "*"; /* UNIX, Windows, OS/2, VMS... */
6335 #endif /* datageneral */
6340 recursive = 1; /* Fall through purposely... */
6346 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6348 printf("?Pattern required\n");
6356 makestr(&del_exc,s);
6365 #endif /* RECURSIVE */
6384 #endif /* CK_TTGWSIZ */
6396 if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
6400 switch (cmresult.nresult) {
6401 case DEL_SMA: minsize = y; break;
6402 case DEL_LAR: maxsize = y; break;
6417 extern struct keytab txtbin[];
6419 if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
6421 if (x == 2) { /* ALL */
6423 } else { /* TEXT or BINARY only */
6430 printf("?Not implemented yet - \"%s\"\n",atmbuf);
6434 if (qflag && (cmresult.fcode == _CMFLD)) {
6435 if ((x = cmcfm()) < 0)
6438 return(success = 0);
6440 if (cmresult.fcode != _CMIFI) {
6443 if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
6444 printf("?No files match: %s\n",brstrip(atmbuf));
6445 else if ((x = zchki(atmbuf)) == -1)
6446 printf("?File not found: %s\n",brstrip(atmbuf));
6448 printf("?Not a regular file: %s\n",atmbuf);
6450 /* printf("?Not a deletable file: %s\n",atmbuf); */
6453 printf("?A file specification is required\n");
6458 ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
6460 ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH);
6462 len = zgetfs(tmpbuf); /* Is it a directory name? */
6463 argisdir = zgfs_dir; /* Then because of how zxpand() */
6464 if (argisdir && zgfs_link) /* works, we have to add it to */
6465 argisdir = 0; /* the list. */
6469 len = zchki(tmpbuf);
6471 argisdir = isdir(tmpbuf);
6472 #endif /* VMSORUNIX */
6474 debug(F110,"DELETE file",tmpbuf,0);
6475 if ((x = cmcfm()) < 0)
6480 if (inserver && isguest) {
6481 printf("?Sorry, DELETE unavailable to guests\n");
6484 #endif /* CK_LOGIN */
6489 printf("?Sorry, /SIMULATE not implemented on this platform\n");
6492 #endif /* OS2ORUNIX */
6496 if (!iswild(tmpbuf)) {
6502 case -2: m = "Not a regular file"; break;
6503 case -1: m = "File not found or not accessible"; break;
6504 default: m = errno ? ck_errstr() : "Can't delete";
6506 printf("?%s: \"%s\"\n",m,tmpbuf);
6510 #endif /* COMMENT */
6512 makelist(del_exc,dxlist,8);
6514 /* tmpbuf[] has the name - now do any needed conversions on it */
6517 { /* Lower level functions change / to \, not good for CMD.EXE. */
6519 while (*p) { /* Change them back to \ */
6520 if (*p == '/') *p = '\\';
6527 if (iswild(tmpbuf)) {
6529 /* Does not handle '.' as version separator */
6539 if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ);
6541 j = 0; x = 0; /* for end_dot and number of dots */
6543 if (tmpbuf[i] == ';') {
6544 ckstrncat(tmpbuf,"0",TMPBUFSIZ);
6546 if (tmpbuf[i--] == '.')
6548 for (; i >= 0; i--) {
6549 if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
6550 tmpbuf[i] == ']' || tmpbuf[i] == '>')
6552 else if (tmpbuf[i] == '.')
6555 if (tmpbuf[i] != ';') { /* dot may have been used */
6556 if (j) { /* last char is dot */
6557 if (x) /* second is version separator */
6558 ckstrncat(tmpbuf,"0",TMPBUFSIZ);
6560 ckstrncat(tmpbuf,";0",TMPBUFSIZ);
6561 } else if (x == 1) /* lacking a version separator */
6562 ckstrncat(tmpbuf,";0",TMPBUFSIZ);
6563 else if (x == 0) /* x == 2 has a version */
6564 ckstrncat(tmpbuf,".*;0",TMPBUFSIZ);
6567 #endif /* COMMENT */
6571 debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
6573 #ifndef OS2ORUNIX /* No built-in DELETE code... */
6574 /* Construct system command. */
6575 ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL);
6578 if (asking) { /* Maybe overwrite in VMS */
6579 if (x_lis) /* if options are needed... */
6580 ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL);
6582 ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL);
6584 ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL);
6588 debug(F110,"dodel line",line,0);
6589 #endif /* OS2ORUNIX */
6592 success = (zdelet(tmpbuf) == 0);
6594 #else /* !MAC ... */
6609 /* Check whether window size changed */
6610 if (ttgwsiz() > 0) {
6611 if (tt_rows > 0 && tt_cols > 0) {
6617 #endif /* CK_TTGWSIZ */
6619 if (x_hdg > 0 && !summary) {
6620 printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
6624 z = zxrewind(); /* Rewind file list */
6627 nzxopts = ZX_FILONLY;
6628 if (recursive) nzxopts |= ZX_RECURSE;
6629 if (matchdot) nzxopts |= ZX_MATCHDOT;
6631 z = nzxpand(s,nzxopts); /* Expand file list */
6632 #endif /* ZXREWIND */
6633 debug(F111,"dodel",s,z);
6635 /* If deleting directories, sort in reverse order */
6636 /* so we delete the files first, then the directory. */
6639 /* In K95, we have no mtchs array, nor any control over */
6640 /* the order in which znext() returns filenames, so we */
6641 /* must copy the array and sort it. */
6644 if (xmtchs) { /* Free previous list in case */
6645 debug(F101,"dodel freeing previous list","",xmtchn);
6646 for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */
6652 xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */
6654 printf("?Memory allocation failure\n");
6657 for (i = 0; i < z; i++) {
6662 makestr(&(xmtchs[i]),tmpbuf);
6664 printf("?Memory allocation failure\n");
6669 /* debug(F111,"dodel add",xmtchs[i],i); */
6672 debug(F101,"dodel xmtchn","",xmtchn);
6673 sh_sort(xmtchs,NULL,z,0,deldirs,0);
6677 sh_sort(mtchs,NULL,z,0,deldirs,filecase);
6696 ) { /* Loop for all files */
6698 ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ);
6700 znext(tmpbuf); /* Get next file */
6702 if (!*tmpbuf) { /* No more */
6703 if (deldirs && recursive && argisdir) {
6704 ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ);
6705 argisdir = 0; /* (only do this once) */
6712 if (fileselect(tmpbuf,
6713 del_aft,del_bef,del_naf,del_nbf,
6714 minsize,maxsize,0,8,dxlist) < 1) {
6718 if (!skip && scan && itsadir) {
6721 if (!skip && scan) {
6722 switch (scanfile(tmpbuf,&y,nscanfile)) {
6733 #endif /* UNICODE */
6738 if (!skip && asking) {
6740 ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL);
6741 x = getyesno(line,3);
6743 case 0: continue; /* no */
6744 case 1: break; /* yes */
6745 case 2: goto xdelete; /* quit */
6746 case 3: asking = 0; break; /* go */
6750 len = zgetfs(tmpbuf); /* Get length and accessibility */
6752 if (itsadir && zgfs_link) { /* Treat links to directories */
6753 itsadir = 0; /* as regular files */
6754 if (scan) /* But not if /TYPE: was given */
6757 if (itsadir) /* (emulate non-Unix code) */
6760 len = zchki(tmpbuf); /* Get accessibility */
6761 if (len < 0) /* See if it's a directory */
6762 itsadir = isdir(tmpbuf);
6763 #endif /* VMSORUNIX */
6766 #ifdef COMMENT /* Too verbose */
6769 printf(" %s (SKIPPED)\n",tmpbuf);
6771 if (++n > cmd_rows - 3)
6772 if (!askmore()) goto xdelete; else n = 0;
6773 #endif /* CK_TTGWSIZ */
6775 #endif /* COMMENT */
6779 debug(F111,"DELETE len",tmpbuf,len);
6785 printf(" %s (SELECTED)\n",tmpbuf);
6786 if (++n > cmd_rows - 3) {
6789 if (!xx) goto xdelete; else n = 0;
6792 } else if (len >= 0 || !itsadir) { /* Regular file */
6793 zdelet(tmpbuf); /* or symlink, etc... */
6794 if (zchki(tmpbuf) < 0) {
6799 printf(" %s (OK)\n",tmpbuf);
6800 if (++n > cmd_rows - 3)
6801 if (!askmore()) goto xdelete; else n = 0;
6808 printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr());
6809 if (++n > cmd_rows - 3)
6810 if (!askmore()) goto xdelete; else n = 0;
6813 } else if (/* pass > 0 && */ deldirs && itsadir) {
6814 /* It's a directory */
6815 if (zrmdir(tmpbuf) > -1) { /* Only works if empty */
6819 printf(" %s (OK)\n",tmpbuf);
6820 if (++n > cmd_rows - 3)
6821 if (!askmore()) goto xdelete; else n = 0;
6827 printf(" %s (FAILED: %s)\n",
6830 if (++n > cmd_rows - 3)
6831 if (!askmore()) goto xdelete; else n = 0;
6834 } else if (x_lis > 0) {
6837 printf(" %s (FAILED: directory)\n",tmpbuf);
6839 printf(" %s (FAILED: not a regular file)\n",tmpbuf);
6840 if (++n > cmd_rows - 3)
6841 if (!askmore()) goto xdelete; else n = 0;
6847 if (++n > cmd_rows - 3)
6848 if (!askmore()) goto xdelete; else n = 0;
6849 printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
6851 count != 1 ? "s" : "",
6852 simulate ? "would be " : "",
6854 filespace != 1 ? "s" : "",
6855 simulate ? "would be " : "",
6856 simulate ? " (maybe)" : ""
6859 if (!x_lis && !success && !quiet) {
6860 printf("?DELETE failed for %d file%s \
6861 (use DELETE /LIST to see details)\n",
6862 bad, bad == 1 ? "" : "s"
6865 } else if (x_lis > 0) {
6867 printf("?%s: %s\n",ck_errstr(), tmpbuf);
6869 printf("?Can't delete: %s\n",tmpbuf);
6872 #else /* OS2ORUNIX */
6873 #ifndef VMS /* Others - let the system do it. */
6875 x = nzxpand(tmpbuf,nzxopts);
6876 success = (x > 0) ? 0 : 1;
6878 printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
6882 x = xsystem(line); /* zshcmd returns 1 for success */
6883 success = (x > 0) ? 1 : 0;
6884 if (x_hdg > 0 && !asking)
6885 printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
6886 concb((char)escape);
6888 #endif /* OS2ORUNIX */
6891 if (g_matchdot > -1) {
6892 matchdot = g_matchdot; /* Restore these... */
6898 debug(F101,"dodel freeing list","",xmtchn);
6899 for (i = 0; i < xmtchn; i++)
6900 if (xmtchs[i]) free(xmtchs[i]);
6906 debug(F101,"dodel result","",rc);
6907 return((rc < 0) ? rc : success);
6909 #endif /* NOFRILLS */
6911 #ifndef NOSPL /* The ELSE command */
6912 _PROTOTYP( VOID pushqcmd, (char *) );
6916 if (!ifcmd[cmdlvl]) {
6917 printf("?ELSE doesn't follow IF\n");
6922 Wrong. This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
6926 #endif /* COMMENT */
6927 if (!iftest[cmdlvl]) { /* If IF was false do ELSE part */
6928 if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
6929 debug(F100,"doelse pushing","",0);
6931 pushcmd(NULL); /* save rest of command. */
6933 /* This fixes certain obscure problems */
6934 /* but breaks many other constructions that must work. */
6936 #endif /* COMMENT */
6937 } else { /* If interactive, */
6938 cmini(ckxech); /* just start a new command */
6939 printf("\n"); /* (like in MS-DOS Kermit) */
6940 if (pflag) prompt(xxstring);
6942 } else { /* Condition is false */
6943 if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
6944 return(y); /* Gobble up rest of line */
6953 char *lp, *ap; /* Macro argument pointer */
6954 int len = 0, x, y, pp = 0;
6957 /* Get variable name */
6964 y = cmfld("Variable name","",&s,xxstring);
6965 debug(F111,"doswitch cmfld",s,y);
6967 if (y == -3) /* Because brstrip() writes */
6968 s = brbuf; /* into its argument. */
6972 debug(F110,"doswitch A",s,0);
6973 if (!strcmp(s,"(")) {
6975 if ((y = cmfld("Variable name","",&s,xxstring)) < 0) {
6980 debug(F110,"doswitch B",s,0);
6983 len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
6984 if (tmpbuf[0] == CMDQ) {
6985 if (chkvar(s) < 1) {
6986 printf("?Variable name required\n");
6990 if (pp > 0) { /* If open paren given parse closing */
6991 if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
6993 if (strcmp(atmbuf,")")) {
6994 printf("?Closing parenthesis required\n");
6999 x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */
7002 debug(F010,"SWITCH a",line,0);
7005 x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */
7007 { /* variable name + SP */
7010 if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') {
7011 tmpbuf[len-1] = NUL;
7015 x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," ");
7017 #endif /* COMMENT */
7018 debug(F010,"SWITCH b",line,0);
7023 if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
7024 if ((y = (int)strlen(s)) < 1) return(-2);
7025 if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
7026 ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
7029 if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
7030 printf("?Unbalanced braces\n");
7033 debug(F010,"SWITCH c",line,0);
7035 x = mlook(mactab,"_switx",nmac); /* Look up SWITCH macro definition */
7036 if (x < 0) { /* Not there? */
7037 addmmac("_switx",sw_def); /* Put it back. */
7038 if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
7039 printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
7040 return(success = 0);
7043 debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */
7044 success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC);
7045 debug(F101,"SWITCH status","",success);
7050 dofor() { /* The FOR command. */
7051 int i, fx, fy, fz; /* loop variables */
7052 char *ap, *di; /* macro argument pointer */
7053 int pp = 0; /* Paren level */
7056 for (i = 0; i < 2; i++) {
7057 if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
7059 printf("?Variable name required\n");
7069 if ((y = parsevar(s,&x,&z)) < 0) /* Check variable. */
7072 if (*s == CMDQ) /* If loop variable starts with */
7073 mustquote++; /* backslash, mustquote is > 0. */
7074 #endif /* COMMENT */
7076 lp = line; /* Build a copy of the command */
7077 ckstrncpy(lp,"_forx ",LINBUFSIZ);
7078 lp += (int)strlen(line); /* "_for" macro. */
7079 ap = lp; /* Save pointer to macro args. */
7081 if (*s == CMDQ) s++; /* Skip past backslash if any. */
7082 while ((*lp++ = *s++)) ; /* copy it */
7083 lp--; *lp++ = SP; /* add a space */
7085 if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
7086 if (y == -3) return(-2);
7089 debug(F101,"dofor fx","",fx);
7090 s = atmbuf; /* Copy the atom buffer */
7092 if ((int)strlen(s) < 1) goto badfor;
7094 In edit 192, we change the loop variables to be evaluated at loop entry,
7095 not each time through the loop. This was required in order to allow
7096 \v(argc) to be used as a loop variable, or in a loop-variable expression.
7097 Thus, we can't have FOR loops that modify their own exit conditions by
7098 changing the final value or the increment. The problem with \v(argc) was
7099 that it is on the macro stack; after entry into the _forx macro, it is at
7102 sprintf(tmpbuf,"%d",fx); /* (SAFE) Substitute actual value */
7104 while ((*lp++ = *s++)) ; /* (what they actually typed) */
7108 debug(F110,"FOR A",line,0);
7111 if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
7112 if (y == -3) return(-2);
7115 debug(F101,"dofor fy","",fy);
7116 s = atmbuf; /* Same deal */
7117 if ((int)strlen(s) < 1)
7120 sprintf(tmpbuf,"%d",fy); /* SAFE */
7122 while ((*lp++ = *s++)) ;
7127 debug(F110,"FOR B",line,0);
7130 x_ifnum = 1; /* Increment or parenthesis */
7131 di = (fx < fy) ? "1" : "-1"; /* Default increment */
7132 if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
7133 debug(F111,"dofor increment",atmbuf,y);
7135 if (y == -3) { /* Premature termination */
7137 } else if (y == -2) { /* Maybe closing paren */
7138 if (!strcmp(atmbuf,")")) {
7139 pp--; /* Count it */
7140 s = di; /* supply default interval */
7142 } else /* Not closing paren, invalid */
7144 } else /* Other error */
7146 } else { /* Number */
7148 debug(F101,"dofor fz","",fz);
7149 s = atmbuf; /* Use it */
7151 if ((int)strlen(s) < 1)
7154 sprintf(tmpbuf,"%d",fz); /* (SAFE) Same deal */
7156 while ((*lp++ = *s++)) ;
7161 debug(F110,"FOR C",line,0);
7164 /* Insert the appropriate comparison operator */
7173 debug(F110,"FOR D",line,0);
7176 if (pp > 0) { /* If open paren given parse closing */
7177 if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
7179 if (strcmp(atmbuf,")")) {
7180 printf("?Closing parenthesis required\n");
7184 if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
7185 if ((y = (int)strlen(s)) < 1) return(-2);
7186 if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
7187 ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
7190 if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
7191 printf("?Unbalanced braces\n");
7196 debug(F110,"FOR E",line,0);
7202 printf("?Zero increment not allowed\n");
7205 #endif /* COMMENT */
7207 In version 8.0 we decided to allow macro names anyplace a numeric-valed
7208 variable could appear. But this caused trouble for the FOR loops because
7209 the quoting in for_def[] assumed a \%i-style loop variable. We account
7210 for this here in the if (mustquote)...else logic by invoking separate
7211 FOR macro definitions in the two cases.
7213 if (mustquote) { /* \%i-style loop variable */
7214 x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */
7215 if (x < 0) { /* Not there? */
7216 addmmac("_forx",for_def); /* Put it back. */
7217 if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
7218 printf("?FOR macro definition gone!\n");
7219 return(success = 0);
7222 } else { /* Loop variable is a macro */
7223 x = mlook(mactab,"_forz",nmac);
7225 addmmac("_forz",foz_def);
7226 if ((x = mlook(mactab,"_forz",nmac)) < 0) {
7227 printf("?FOR macro definition gone!\n");
7228 return(success = 0);
7232 debug(F010,"FOR command",line,0); /* Execute the FOR macro. */
7233 return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
7236 printf("?Incomplete FOR command\n");
7244 /* T O D 2 S E C -- Convert time of day as hh:mm:ss to secs since midnite */
7246 Call with a string hh:mm or hh:mm:ss.
7247 Returns a 0 to 86400 on success, or a negative number on failure.
7250 tod2sec(t) char * t; {
7252 long hh = 0L, mm = 0L, ss = 0L;
7257 debug(F110,"tod2sec",t,0);
7259 if (isdigit(*t)) /* Get hours from argument */
7264 hh = hh * 10 + *t++ - '0';
7268 #endif /* COMMENT */
7276 if (isdigit(*t)) /* Minutes */
7281 mm = mm * 10 + *t++ - '0';
7291 if (isdigit(*t)) /* Seconds */
7296 ss = ss * 10 + *t++ - '0';
7300 if (*t > 32) /* No trailing junk allowed */
7305 t2 = hh * 3600L + mm * 60L + ss; /* Seconds since midnight from arg */
7306 debug(F101,"tod2sec t2","",t2);
7311 int waitinterval = 1;
7315 #endif /* OLDWAIT */
7320 dopaus(cx) int cx; {
7322 extern int sleepcan;
7326 x_ifnum = 1; /* Turn off internal complaints */
7328 y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
7329 else if (cx == XXPAU)
7330 y = cmnum("seconds to pause, or time of day hh:mm:ss",
7331 "1",10,&x,xxstring);
7333 y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
7334 "100",10,&x,xxstring);
7337 if (y == -2) { /* Invalid number or expression */
7338 char *p = tmpbuf; /* Retrieve string from atmbuf */
7341 zzstring(atmbuf,&p,&n); /* Evaluate in case it's a variable */
7342 zz = tod2sec(tmpbuf); /* Convert to secs since midnight */
7344 printf("?Number, expression, or time of day required\n");
7347 char now[32]; /* Current time */
7352 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
7353 if (zz < tnow) /* User's time before now */
7354 zz += 86400L; /* So make it tomorrow */
7355 zz -= tnow; /* Seconds from now. */
7362 case XXPAU: /* PAUSE */
7363 case XXMSL: /* MSLEEP */
7364 if ((y = cmcfm()) < 0) return(y);
7366 case XXWAI: /* WAIT */
7367 z = 0; /* Modem signal mask */
7368 while (1) { /* Read zero or more signal names */
7369 y = cmkey(mstab,nms,"modem signal","",xxstring);
7370 if (y == -3) break; /* -3 means they typed CR */
7371 if (y < 0) return(y); /* Other negatives are errors */
7372 z |= y; /* OR the bit into the signal mask */
7374 if ((y = cmcfm()) < 0) return(y);
7377 default: /* Shouldn't happen */
7381 /* Command is entered, now do it. */
7383 if (zz > -1L) { /* Time of day given? */
7385 if (zz != (long) x) {
7387 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
7392 if (cx == XXMSL) { /* Millisecond sleep */
7393 msleep(zz < 0 ? x : x * 1000);
7394 return(success = 1);
7396 if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
7398 return(success = 1);
7401 /* WAIT, or else SLEEP with cancellation allowed... */
7403 do { /* Sleep loop */
7405 if (sleepcan) { /* Keyboard cancellation allowed? */
7406 if (y = conchk()) { /* Did they type something? */
7408 while (y--) coninc(0); /* Yes, gobble it all up */
7410 /* There is a debate over whether PAUSE should absorb */
7411 /* its cancelling character(s). There are several */
7412 /* reasons why it should gobble at least one character: */
7413 /* (1) MS-DOS Kermit does it */
7414 /* (2) if not, subsequent PAUSE commands will terminate */
7416 /* (3) if not, subsequent ASK commands will use it as */
7417 /* valid input. If \13, then it will get no input */
7418 /* (4) if not, then the character appears on the command */
7419 /* line after all enclosing macros are complete. */
7420 kbchar = coninc(0); /* Gobble one up */
7421 #endif /* COMMENT */
7422 break; /* And quit PAUSing or WAITing */
7425 if (cx == XXWAI) { /* WAIT (z == modem signal mask) */
7426 debug(F101,"WAIT x","",x);
7427 if (z > 0) { /* Looking for any modem signals? */
7428 mdmsig = ttgmdm(); /* Yes, get them */
7429 if (mdmsig < 0) /* Failed */
7430 return(success = 0);
7431 if ((mdmsig & z) == z) /* Got what we wanted? */
7432 return(success = 1); /* Succeed */
7434 if (x == 0) /* WAIT 0 and didn't get our signals */
7437 sleep(1); /* No interrupt, sleep one second */
7440 if (cx == XXWAI) /* If WAIT and loop exhausted */
7441 success = (z == 0); /* Fail. */
7443 success = (x == 0); /* Set SUCCESS/FAILURE for PAUSE. */
7446 #else /* New code uses chained FDBs and allows FILE waits... */
7448 char * m = ""; /* Help message */
7449 struct FDB nu, fl; /* Parse function descriptor blocks */
7451 int mdmsig = 0, fs = 0;
7457 case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
7458 case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
7459 case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
7463 _CMNUM, /* Number */
7464 m, /* Help message */
7465 (cx == XXMSL) ? "100" : "1", /* Default */
7469 xxstring, /* Processing function */
7473 cmfdbi(&fl, /* Time of day */
7477 "", /* addtl string data */
7478 0, /* addtl numeric data 1 */
7479 0, /* addtl numeric data 2 */
7480 xxstring, /* processing func */
7484 x = cmfdb(&nu); /* Parse a number or a field */
7490 switch (cmresult.fcode) {
7491 case _CMNUM: /* Number */
7492 x = cmresult.nresult;
7494 case _CMFLD: /* Field */
7495 zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */
7497 printf("?Number, expression, or time of day required\n");
7500 char now[32]; /* Current time */
7505 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
7506 if (zz < tnow) /* User's time before now */
7507 zz += 86400L; /* So make it tomorrow */
7508 zz -= tnow; /* Seconds from now. */
7511 debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
7513 case XXPAU: /* PAUSE */
7514 case XXMSL: /* MSLEEP */
7515 if ((y = cmcfm()) < 0) return(y);
7517 case XXWAI: /* WAIT */
7518 z = 0; /* Modem signal mask */
7519 y = cmkey(waittab,nwaittab,"","",xxstring);
7522 if ((y = cmcfm()) < 0)
7528 if (y == WAIT_FIL) { /* FILE */
7530 if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
7533 if (filewait == WF_MOD || filewait == WF_DEL)
7534 z = cmifi("Filename","",&s,&wild,xxstring);
7536 z = cmfld("Filename","",&s,xxstring);
7539 if (wild || ((filewait == WF_CRE) && iswild(s))) {
7540 printf("?Wildcards not valid here\n");
7543 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
7544 if ((z = cmcfm()) < 0)
7547 } else if (y != WAIT_MDM) { /* A modem signal */
7548 z |= y; /* OR the bit into the signal mask */
7550 if (!filewait) { /* Modem signals... */
7551 while (1) { /* Get zero or more signal names */
7552 y = cmkey(mstab,nms,"modem signal","",xxstring);
7553 if (y == -3) break; /* -3 means they typed CR */
7554 if (y < 0) return(y); /* Other negatives are errors */
7555 z |= y; /* OR the bit into the signal mask */
7557 if ((y = cmcfm()) < 0) return(y);
7561 default: /* Shouldn't happen */
7565 /* Command is entered, now do it. */
7567 if (zz > -1L) { /* Time of day given? */
7569 if (zz != (long) x) {
7571 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
7577 concb((char)escape); /* Ensure single-char wakeup */
7579 if (cx == XXMSL) { /* Millisecond sleep */
7580 msleep(zz < 0 ? x : x * 1000);
7581 return(success = 1);
7583 if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
7585 return(success = 1);
7587 if (filewait) { /* FILE... */
7588 fs = zchki(tmpbuf); /* Check if file exists */
7592 return(success = 1);
7596 printf("?File does not exit: %s\n",tmpbuf);
7599 s = zfcdat(tmpbuf); /* Get current modification date */
7601 if (ckstrncpy(filedate,s,32) != 17) {
7602 printf("?Can't get modification time: %s\n",tmpbuf);
7608 return(success = 1);
7612 do { /* Polling loop */
7613 if (sleepcan) { /* Keyboard cancellation allowed? */
7614 if ((y = conchk()) > 0) { /* Did they type something? */
7615 kbchar = coninc(0); /* Yes, get first char they typed */
7616 debug(F000,"WAIT kbchar","",kbchar);
7618 while (--y > 0) /* Gobble the rest up */
7620 #endif /* COMMENT */
7621 return(success = 0); /* And quit PAUSing or WAITing */
7624 if (filewait == 0) {
7625 if (cx == XXWAI) { /* WAIT for modem signals */
7627 mdmsig = ttgmdm(); /* Get them. */
7628 debug(F101,"WAIT ttgmdm","",mdmsig);
7629 if (mdmsig < 0) /* Failure to get them? */
7630 return(success = 0); /* Fail. */
7631 if ((mdmsig & z) == z) /* Got desired ones? */
7632 return(success = 1); /* Succeed. */
7634 return(success = 0);
7636 } else { /* FILE... */
7637 fs = zchki(tmpbuf); /* Get file status */
7638 if (filewait == WF_MOD) { /* Wait for modification */
7639 if (fs == -1) /* Failure to get status */
7640 return(success = 0); /* so WAIT fails. */
7641 s = zfcdat(tmpbuf); /* Get current modification time */
7642 if (!s) s = ""; /* And compare with the time */
7643 if (strcmp(s,filedate)) /* when the WAIT started */
7644 return(success = 1);
7645 } else if (filewait == WF_DEL) { /* Wait for deletion */
7646 if (fs == -1) /* If file doesn't exist, */
7647 return(success = 1); /* succeed. */
7648 } else if (filewait == WF_CRE) { /* Wait for creation */
7649 if (fs != -1) /* If file exists */
7650 return(success = 1); /* succeed. */
7653 if (x < 1) /* SLEEP/WAIT/PAUSE 0 */
7655 sleep(waitinterval); /* No interrupt, sleep */
7656 x -= waitinterval; /* Deduct sleep time */
7659 if (cx == XXWAI) /* WAIT time expired */
7660 success = (z == 0); /* Succeed if no modem signals */
7661 else /* For SLEEP or PAUSE, success */
7662 success = (x == 0); /* depends on whether it was */
7663 return(success); /* interrupted from the keyboard. */
7664 #endif /* OLDWAIT */
7669 _PROTOTYP(int zcmpfn,(char *, char *));
7670 #endif /* OS2ORUNIX */
7676 /* Parse a file or a directory name */
7677 int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
7680 cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
7682 "Filename or switch", /* hlpmsg */
7684 "", /* addtl string data */
7685 nqvswtab, /* addtl numeric data 1: tbl size */
7686 4, /* addtl numeric data 2: 4 = cmswi */
7687 xxstring, /* Processing function */
7688 qvswtab, /* Keyword table */
7689 &fi /* Pointer to next FDB */
7692 cmfdbi(&fi, /* 1st FDB - file to type */
7696 "", /* addtl string data */
7697 3, /* addtl numeric data 1 */
7698 0, /* addtl numeric data 2 */
7705 x = cmfdb(&sw); /* Parse something */
7706 if (x < 0) /* Error */
7708 switch (cmresult.fcode) {
7710 switch (cmresult.nresult) {
7722 s = cmresult.sresult;
7729 wild = cmresult.nresult; /* Source specification wild? */
7731 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
7735 wild = iswild(line);
7737 p = tmpbuf; /* Place for new name */
7738 if ((x = cmofi(wild ? "Target directory" : "New name",
7739 "",&s,xxstring)) < 0) { /* Get new name */
7741 printf("?%s required\n", wild ? "Target directory" : "New name");
7745 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
7746 if ((y = cmcfm()) < 0) return(y);
7748 if (!wild) { /* Just one */
7749 if (listing) printf("%s => %s ",line,p);
7750 if (zlink(line,p) < 0) {
7751 if (listing) printf("(FAILED: %s\n",ck_errstr());
7754 if (listing) printf("(OK)\n");
7756 return(success = rc);
7758 if (!isdir(p)) { /* Multiple */
7759 printf( /* if target is not a directory */
7760 "?Multiple source files not allowed if target is not a directory.\n");
7764 else { /* Show full path of target */
7765 char buf[CKMAXPATH]; /* (too much) */
7766 if (zfnqfp(p,CKMAXPATH,buf))
7767 ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
7769 #endif /* COMMENT */
7772 conres(); /* Let Ctrl-C work. */
7774 debug(F110,"dolink line",line,0);
7777 z = zxrewind(); /* Rewind file list */
7779 z = nzxpand(s,0); /* Expand file list */
7780 #endif /* ZXREWIND */
7781 debug(F111,"dolink p",p,z);
7785 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
7789 if (!(z == 0 && !wild))
7793 if (listing) printf("%s => %s ",line,p);
7794 if (zlink(line,p) < 0) {
7795 if (listing) printf("(FAILED: %s\n",ck_errstr());
7798 if (listing) printf("(OK)\n");
7802 concb((char)escape);
7804 return(success = rc);
7811 int i, x, listing = 0, nolist = 0, havename = 0, getval;
7814 int overwrite = OVW_ALWAYS;
7815 int targetisdir = 0;
7825 char newname[CKMAXPATH], * nm;
7828 cmfdbi(&sw, /* 1st FDB - switches */
7830 "Filename or switch", /* hlpmsg */
7832 "", /* addtl string data */
7833 ncopytab, /* addtl numeric data 1: tbl size */
7834 4, /* addtl numeric data 2: 4 = cmswi */
7835 xxstring, /* Processing function */
7836 copytab, /* Keyword table */
7837 &fi /* Pointer to next FDB */
7839 cmfdbi(&fi, /* 2nd FDB - file to copy */
7843 "", /* addtl string data */
7844 0, /* addtl numeric data 1 */
7845 0, /* addtl numeric data 2 */
7852 x = cmfdb(&sw); /* Parse something */
7853 if (x < 0) /* Error */
7855 switch (cmresult.fcode) {
7857 c = cmgbrk(); /* Get break character */
7858 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
7859 printf("?This switch does not take an argument\n");
7863 if (!getval && (cmgkwflgs() & CM_ARG)) {
7864 printf("?This switch requires an argument\n");
7868 switch (cmresult.nresult) {
7889 if ((x = cmkey(ovwtab,novwtab,
7890 "When to overwrite existing destination file",
7906 s = cmresult.sresult;
7913 wild = cmresult.nresult;
7914 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
7916 p = tmpbuf; /* Place for new name */
7918 /* Get destination name */
7919 if ((x = cmofi("destination name and/or directory",
7925 ,&s,xxstring)) < 0) {
7927 printf("?Name for destination file required\n");
7931 ckstrncpy(p,s,TMPBUFSIZ); /* Safe copy of destination name */
7932 if ((y = cmcfm()) < 0) return(y);
7933 if (appending && swapping) {
7934 printf("?Sorry, /APPEND and /SWAP conflict\n");
7939 This unreasonably prevented "COPY /APPEND *.* bigfile" from concatenating
7940 a bunch of files into one big file.
7942 if (appending && wild) {
7943 printf("?Sorry, /APPEND can be used only with single files\n");
7946 #endif /* COMMENT */
7947 targetisdir = isdir(p);
7951 if (p[x-1] != '/') {
7952 ckstrncat(p,"/",TMPBUFSIZ);
7957 if (p[x-1] != '/') {
7958 ckstrncat(p,"/",TMPBUFSIZ);
7963 if (p[x-1] != '>') {
7964 ckstrncat(p,">",TMPBUFSIZ);
7969 if (p[x-1] != ':') {
7970 ckstrncat(p,":",TMPBUFSIZ);
7974 if (p[x-1] != '/') {
7975 ckstrncat(p,"/",TMPBUFSIZ);
7978 #endif /* datageneral */
7979 #endif /* STRATUS */
7981 #endif /* UNIXOROSK */
7985 if (!appending) { /* If /APPEND not given */
7986 if (wild && !targetisdir) { /* No wildcards allowed */
7987 printf( /* if target is not a directory */
7988 "?Multiple source files not allowed if target is not a directory.\n");
7994 conres(); /* Let Ctrl-C work. */
7996 debug(F110,"docopy line",line,0);
7997 debug(F110,"docopy p",p,0);
7998 debug(F110,"docopy nm",nm,0);
8001 z = zxrewind(); /* Rewind file list */
8003 z = nzxpand(s,0); /* Expand file list */
8004 #endif /* ZXREWIND */
8008 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
8012 if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */
8013 if (inserver && (!ENABLED(en_del)
8016 #endif /* CK_LOGIN */
8018 printf("?Sorry, overwriting existing files is disabled\n");
8024 if (tob64 && fromb64) { /* To and from B64 = no conversion */
8028 debug(F110,"COPY dest",p,0);
8036 errno = 0; /* Reset errno */
8040 ckmakmsg(newname,CKMAXPATH,p,nm,NULL,NULL);
8045 if (overwrite) { /* Overwrite checking? */
8046 if (zchki(nm) >= (CK_OFF_T)0) { /* Destination file exists? */
8052 i = strlen(line); /* Isolate source filename */
8053 for (; i >= 0; i--) {
8054 if (ISDIRSEP(line[i])) {
8059 debug(F110,"COPY n1", n1, 0);
8060 i = strlen(nm); /* And destination filename */
8061 for (; i >= 0; i--) {
8062 if (ISDIRSEP(nm[i])) {
8067 debug(F110,"COPY n2", n2, 0);
8068 if (!strcmp(n1,n2)) { /* Same name? */
8069 if (overwrite == OVW_NEVER) { /* Never overwrite? */
8070 if (listing) /* Skip */
8071 if (listing) printf("%s => %s (SKIPPED)\n",line,nm);
8074 ckstrncpy(d1,zfcdat(line),20); /* Source file timestamp */
8075 d2 = zfcdat(nm); /* Timestamp of dest file */
8076 x = strcmp(d1,d2); /* Compare them */
8077 if (((overwrite == OVW_NEWER) && (x < 0)) ||
8078 ((overwrite == OVW_OLDER) && (x > 0))) {
8080 if (listing) printf("%s => %s (SKIPPED)\n",line,nm);
8086 if (listing) printf("%s => %s ",line,nm);
8089 if (!swapping && !appending && !fromb64 && !tob64) {
8090 debug(F110,"COPY zcopy",line,0);
8092 if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
8093 debug(F111,"COPY not OK",line,x);
8097 printf("(FAILED: Not a regular file)\n");
8099 printf("?Not a regular file - %s\n",line);
8104 printf("(FAILED: Not found or not accessible)\n");
8106 printf("?Not found or not accessible - %s\n",line);
8111 printf("(FAILED: Permission denied)\n");
8113 printf("?Permission denied - %s\n",line);
8118 printf("(Source and destination are the same file)\n");
8121 "?Source and destination are the same file - %s\n",
8127 printf("(FAILED: Input/Output error)\n");
8129 printf("?Input/Output error - %s\n",line);
8134 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8136 printf("?%s - %s\n",ck_errstr(),p);
8141 printf("(FAILED: %s)\n",ck_errstr());
8143 printf("?%s\n",ck_errstr());
8146 } else { /* Regular copy succeeded */
8147 debug(F110,"COPY OK..",newname,0);
8149 if (preserve) { /* Handle /PRESERVE */
8150 char * pstr = ""; /* File permissions string */
8151 struct zattr xx; /* File attribute structure */
8152 extern char * cksysid;
8154 initattr(&xx); /* Initialize the struct */
8156 xx.systemid.val = cksysid; /* Set our system ID */
8157 xx.systemid.len = (int)strlen(cksysid);
8159 pstr = zgperm(line); /* Get source file's permissions */
8160 #endif /* CK_PERMS */
8161 xx.lprotect.val = pstr;
8162 xx.lprotect.len = (int)strlen(pstr);
8163 xx.date.val = zfcdat(line); /* Source file's timestamp */
8164 xx.date.len = (int)strlen(xx.date.val);
8165 if (zstime(nm,&xx,0) < 0) {
8166 printf("?COPY /PRESERVE %s: %s\n",nm,ck_errstr());
8171 if (listing && rc > -1)
8175 } else { /* Special options */
8177 int prev, y, x = 0; /* Variables needed for them */
8184 if ((in = fopen(line,"r")) == NULL) { /* Open input file */
8186 printf("(FAILED: %s)\n",ck_errstr());
8188 printf("?%s - %s)\n",ck_errstr(),line);
8192 if (targetisdir) { /* Target is directory */
8193 char * buf = NULL; /* so append this filename to it */
8197 ckstrncat(p,buf,TMPBUFSIZ);
8200 if (zcmpfn(line,p)) { /* Input and output are same file? */
8202 printf("(FAILED: Source and destination identical)\n");
8204 printf("?Source and destination identical - %s\n", line);
8208 #endif /* OS2ORUNIX */
8209 if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
8212 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8214 printf("?%s - %s\n",p,ck_errstr());
8219 if (tob64) { /* Converting to Base-64 */
8221 debug(F110,"COPY tob64",line,0);
8223 while (1) { /* Loop... */
8225 if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */
8232 printf("(FAILED: Phase error at %d)\n",prev);
8234 printf("?Phase error at %d\n",prev);
8241 printf("(FAILED: Swap error)\n");
8243 printf("?Swap error\n");
8247 for (i = 0; i < x; i+=2) {
8249 ibuf[i] = ibuf[i+1];
8253 if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
8255 printf("(FAILED: Encoding error)\n");
8257 printf("?Encoding error\n");
8261 fprintf(out,"%s\n",obuf);
8264 } else if (fromb64) { /* Converting from Base 64 */
8266 debug(F110,"COPY fromb64",line,0);
8268 if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
8271 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8273 printf("?%s - %s\n",p,ck_errstr());
8279 x = fread(ibuf,1,80,in);
8280 if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
8282 printf("(FAILED: Decoding error)\n");
8284 printf("?Decoding error\n");
8291 printf("(FAILED: Swap error)\n");
8293 printf("?Swap error\n");
8297 for (i = 0; i < y; i+=2) {
8299 obuf[i] = obuf[i+1];
8304 if (fwrite(obuf,1,y,out) < 1) {
8306 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8308 printf("?%s - %s\n",p,ck_errstr());
8318 if (swapping) { /* Swapping bytes */
8323 debug(F110,"COPY swapping",line,0);
8326 x = fread((char *)c,1,2,in);
8331 } else if (x == 1) {
8335 "(WARNING: Odd byte count)");
8336 if (!listing) printf("\n");
8338 if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
8340 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8342 printf("?%s - %s\n",p,ck_errstr());
8348 } else if (appending) { /* Appending to target file */
8352 debug(F110,"COPY appending",line,0);
8355 x = fread(&c,1,1,in);
8361 if (fwrite(&c,1,1,out) < 1) {
8363 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8365 printf("?%s - %s\n",p,ck_errstr());
8371 if (out) fclose(out);
8375 concb((char)escape);
8376 #endif /* VMSORUNIX */
8378 if (rc > -1) success = rc;
8382 #endif /* NOFRILLS */
8386 static struct keytab * xfcstab = NULL; /* For RENAME /CONVERT: */
8387 static char cvtbufin[CKMAXPATH+8] = { NUL, NUL };
8388 static char cvtbufout[CKMAXPATH+8] = { NUL, NUL };
8389 static char * pcvtbufin = NULL;
8390 static char * pcvtbufout = NULL;
8392 static int /* Input function xgnbyte() */
8399 _PROTOTYP(int cvtfnout,(char)); /* Output function for xpnbyte() */
8405 #endif /* CK_ANSIC */
8407 if (pcvtbufout - cvtbufout >= CKMAXPATH)
8414 /* Convert a string from any charset to any other charset */
8417 cvtstring(s,csin,csout) char * s; int csin, csout; {
8419 extern CK_OFF_T ffc;
8421 ckstrncpy(cvtbufin,s,CKMAXPATH); /* Put it in a public place */
8422 pcvtbufin = cvtbufin; /* with public pointers */
8423 pcvtbufout = cvtbufout;
8426 if (csin == csout) /* If the two sets are the same */
8427 return((char *)cvtbufin); /* don't bother converting */
8429 initxlate(csin,csout); /* Initialize the translator */
8431 while ((c = xgnbyte(FC_UCS2,csin,cvtfnin)) > -1) { /* Loop thru string */
8432 if (xpnbyte(c,TC_UCS2,csout,cvtfnout) < 0) {
8437 /* ffc is touched by xgnbyte() but this is not file transfer */
8438 /* so we have to undo it */
8440 return((char *)cvtbufout);
8442 #endif /* NOUNICODE */
8443 #endif /* NOCSETS */
8449 /* The RENAME command - expanded and improved in 8.0.212 April 2006 */
8451 static char * ren_sub[4] = { NULL,NULL,NULL,NULL }; /* For RENAME /REPLACE */
8453 int ren_list = 0; /* Default listing action for RENAME */
8454 int ren_coll = RENX_OVWR; /* Default collision action */
8460 case RENX_FAIL: s = "fail"; break;
8461 case RENX_OVWR: s = "overwrite"; break;
8462 case RENX_SKIP: s = "proceed"; break;
8464 printf(" rename collision: %s\n",s);
8465 printf(" rename list: %s\n",showoff(ren_list));
8470 setrename() { /* Parse SET RENAME options */
8472 if ((x = cmkey(renamset,nrenamset,"","", xxstring)) < 0)
8475 case REN_OVW: /* COLLISION */
8476 if ((x = cmkey(r_collision,nr_collision,"","", xxstring)) < 0)
8478 if ((y = cmcfm()) < 0)
8482 case DEL_LIS: /* LIST */
8483 return(seton(&ren_list));
8485 return(success = 1);
8488 /* Reverse a string - Assumes a single-byte character set */
8491 gnirts(s1, s2, len) char * s1, * s2; int len; {
8493 if (!s1) /* Null source pointer, fail */
8495 n = (int) strlen(s1);
8496 if (n > len-1) /* Source longer than dest, fail */
8498 s2[n--] = NUL; /* Deposit null byte at end of dest */
8499 for (; n >= 0; n--) { /* Copy the rest backwards */
8509 Worker function to rename one file for dorenam() (below).
8510 old = name of file or directory to be renamed
8511 new = new name (not required for /UPPER, /LOWER, and /REPLACE)
8512 replacing = 1 if doing string replacement on the name
8513 casing = 1 if converting name to lowercase, 2 if to uppercase
8514 all = if doing case conversion on all names, not just monocase ones
8515 converting = 1 if converting character sets
8516 cset1 = character set to convert from (File Character Set index)
8517 cset2 = character set to convert to (ditto, see ck?xla.h)
8518 listing = 1 to show results of rename
8519 nolist = 1 to be completely silent (don't even print error messages)
8520 op = 1 means simulate, 2 means check for collision, 0 means rename
8521 size = length of result buffer.
8522 collision = action to take if destination file already exists:
8524 1 = overwrite and succeed
8525 2 = skip and succeed
8527 0: on failure to rename or when a forbidden collision would have occurred.
8528 1: on success (file was renamed or did not need to be renamed).
8530 If this code is ever built on any platform that is not Unix, Windows,
8531 VMS, or OS/2, this routine might need some adjustment.
8534 /* Opcodes for op... */
8535 #define REN_OP_SIM 1 /* Simulate */
8536 #define REN_OP_CHK 2 /* Check for collisions */
8540 replacing,casing,all,converting,cset1,cset2,
8541 listing,nolist,op,size,collision)
8543 int replacing,casing,all,converting,cset1,cset2,
8544 listing,nolist,op,size,collision;
8546 char buf[CKMAXPATH]; /* Temporary filename buffer */
8547 char out[CKMAXPATH]; /* Buffer for new name */
8548 char dir[CKMAXPATH]; /* Destination directory */
8549 char pat[CKMAXPATH]; /* Path segment on old filename */
8551 char * destdir; /* Destination directory, if any */
8552 char * srcpath; /* Source path, if any */
8553 int rc = 1, flag = 0, skip = 0; /* Control */
8554 int honorcase = 0, replaced = 0;
8555 int anchor = 0; /* 1 = beginning, 2 = end */
8556 int occur = 0; /* Occurrence */
8557 int minus = 0; /* Occurrence is negative */
8558 int allbut = 0; /* Occurrence is "all but" */
8559 int arg2isfile = 0; /* Arg2 ("new") is a filename */
8561 debug(F110,"RENAMEONE old",old,0);
8562 debug(F110,"RENAMEONE new",new,0);
8563 debug(F110,"RENAMEONE ren_sub[0]",ren_sub[0],0);
8564 debug(F110,"RENAMEONE ren_sub[1]",ren_sub[1],0);
8565 debug(F110,"RENAMEONE ren_sub[2]",ren_sub[2],0);
8567 if (op == REN_OP_SIM && !nolist) /* For convenience */
8570 honorcase = inpcas[cmdlvl]; /* Inherit SET CASE value */
8579 if (!old) old = ""; /* In case of bad args */
8581 if (!*old) return(success = 0);
8582 ckstrncpy(out,new,CKMAXPATH); /* So we don't write into */
8583 new = out; /* our argument... */
8586 pat[0] = NUL; /* Assume no path in source file.. */
8589 int n; /* If the old name includes a path */
8590 n = (int)strlen(old) - 1; /* put it in a separate place. */
8591 for (; n >= 0; n--) { /* We are renaming the file only. */
8592 if (ISDIRSEP(old[n])) {
8593 ckstrncpy(pat,old,CKMAXPATH);
8600 debug(F110,"RENAMEONE old 2",old,0);
8601 debug(F110,"RENAMEONE pat 2",pat,0);
8603 dir[0] = NUL; /* Assume no destination directory */
8605 if (*new) { /* If Arg2 given */
8606 if (isdir(new)) { /* If it's a directory */
8607 ckstrncpy(dir,new,CKMAXPATH); /* put it here */
8608 } else { /* otherwise */
8609 arg2isfile++; /* flag that it's a filename */
8612 if (!casing && !replacing && !converting) {
8614 return(success = 0);
8615 if (!arg2isfile) { /* Destination is a directory? */
8616 if (!isdir(old)) { /* and source is not? */
8618 int n, x = 0; /* Concatenate them */
8619 if ((n = strlen(new)) > 0) /* so we can check for */
8620 if (ISDIRSEP(new[n-1])) /* collisions. */
8622 ckmakmsg(buf,size,new,x ? "" : "/", old, "");
8624 ckmakmsg(buf,size,new, old, NULL, NULL);
8626 debug(F110,"RENAMEONE new new",new,0);
8631 } else if (*new) { /* Directory to move file to */
8632 int n, x = 0; /* after changing its name */
8634 return(success = 0);
8636 if ((n = strlen(new)) > 0)
8637 if (ISDIRSEP(new[n-1]))
8639 ckmakmsg(dir,CKMAXPATH,new,x ? "" : "/", "", "");
8641 ckstrncpy(dir,new,CKMAXPATH);
8648 new = cvtstring(old,cset1,cset2);
8650 #endif /* NOUNICODE */
8651 #endif /* NOCSETS */
8653 if (replacing) { /* Replacing strings */
8655 int len0, len1, len2;
8656 char c, *p, *s, *bp[3];
8658 bp[0] = old; /* Original name */
8659 bp[1] = ren_sub[0]; /* String to be replaced */
8660 bp[2] = ren_sub[1]; /* What to replace it with */
8661 if (!bp[2]) bp[2] = "";
8663 len0 = (int)strlen(bp[0]); /* length of original filename */
8664 len1 = (int)strlen(bp[1]); /* length of target substring */
8665 len2 = (int)strlen(bp[2]); /* Length of replacement string */
8667 if (ren_sub[2]) { /* Optional options */
8669 while ((c = *p++)) {
8672 anchor = 1; occur = 0; minus = 0; allbut = 0; break;
8674 anchor = 2; occur = 0; minus = 0; allbut = 0; break;
8675 case 'A': honorcase = 1; minus = 0; allbut = 0; break;
8676 case 'a': honorcase = 0; minus = 0; allbut = 0; break;
8677 case '-': minus = 1; break;
8678 case '~': allbut = 1; break;
8682 if (minus) occur = 0 - occur;
8689 if (anchor) { /* Anchored replacement... */
8694 case 1: /* Anchored at beginning */
8695 if (!ckstrcmp(bp[1],bp[0],len1,honorcase)) {
8696 x = ckstrncpy(new,bp[2],size);
8697 (VOID) ckstrncpy(new+x,bp[0]+len1,size-x);
8701 case 2: /* Anchored at end */
8702 if (!ckstrcmp(bp[1],bp[0]+y,len1,honorcase)) {
8703 x = ckstrncpy(new,bp[0],y+1);
8704 (VOID) ckstrncpy(new+y,bp[2],size-x);
8711 ckstrncpy(new,old,size); /* Keep old name */
8714 } else { /* Replace all occurrences */
8715 int j, n = 0; /* or a particular occurrence */
8718 char * s0 = NULL, * s1 = NULL, * s2 = NULL;
8719 p = new; /* Pointer to new name */
8721 if (occur < 0) { /* nth occurrence from the right */
8723 s0 = (char *)malloc(len0+1); /* Reverse original string */
8725 (VOID) gnirts(bp[0],s0,len0+1);
8728 s1 = (char *)malloc(len1+1); /* Reverse target string */
8730 (VOID) gnirts(bp[1],s1,len1+1);
8733 s2 = (char *)malloc(len2+1); /* Reverse replacement string */
8735 (VOID) gnirts(bp[2],s2,len2+1);
8738 debug(F111,"RENAMEONE s0",s0,len0);
8739 debug(F111,"RENAMEONE s1",s1,len1);
8740 debug(F111,"RENAMEONE s2",s2,len2);
8742 s = bp[0]; /* Pointer to old name */
8743 p = new; /* Pointer to new name */
8744 j = len0 - len1 + 1; /* How much to scan */
8745 while (j-- > 0) { /* For each character... */
8746 if (!ckstrcmp(bp[1],s,len1,honorcase)) { /* Match? */
8747 n++; /* Occurrence counter */
8748 todo = (occur == 0) ||
8749 (!allbut && n == occur) ||
8750 (allbut && n != occur);
8751 if (!todo) { /* Desired occurrence? */
8752 size -= ckstrncpy(p,bp[1],size); /* No... */
8753 p += len1; /* Copy target string */
8754 s += len1; /* instead of replacement string */
8757 if (len2) { /* If replacement string not empty */
8758 size -= ckstrncpy(p,bp[2],size); /* Copy it */
8761 s += len1; /* Advance source position */
8762 } else { /* No match */
8763 *p++ = *s++; /* just copy this character */
8767 while ((*p++ = *s++)); /* Done copy the rest */
8768 replaced = 1; /* Remember we changed the name */
8769 if (s0) { /* Were we doing "all but"? */
8770 debug(F110,"RENAMEONE new1",new,0);
8771 x = (int)strlen(new); /* Unreverse the result */
8772 if ((p = (char *)malloc(x+2))) {
8773 (VOID) gnirts(new,p,x+2);
8774 debug(F110,"RENAMEONE new2",new,0);
8775 ckstrncpy(new,p,x+2);
8778 if (s0) free(s0); /* Free the temporary strings */
8781 debug(F110,"RENAMEONE new3",new,0);
8785 if (casing) { /* Changing case? */
8786 char c, * t; /* See if mixed case. */
8788 ckstrncpy(new,old,size); /* Copy old name to new name */
8790 while ((c = *t++)) {
8791 if (islower(c)) flag |= 1; /* Have a lowercase letter */
8792 else if (isupper(c)) flag |= 2; /* Have an uppercase letter */
8793 if (flag == 3) break; /* Have a mixed-case name */
8795 if (all || flag < 3) { /* Not skipping or not mixed case */
8796 if (casing == 1 && flag != 1) /* Change case to lower */
8797 (VOID) cklower(new);
8798 else if (casing == 2 && flag != 2) /* Change case to upper */
8799 (VOID) ckupper(new);
8802 debug(F110,"XXX 1 new",new,0);
8803 debug(F110,"XXX 1 old",old,0);
8804 debug(F110,"XXX 1 srcpath",srcpath,0);
8805 debug(F110,"XXX 1 destdir",destdir,0);
8807 if (*destdir && !arg2isfile) { /* Moving without renaming */
8808 ckstrncat(srcpath,old,CKMAXPATH);
8811 } else if (*destdir || *srcpath) { /* Were there any pathnames? */
8812 char tmp[CKMAXPATH];
8813 ckmakmsg(tmp,CKMAXPATH,srcpath,old,NULL,NULL);
8814 ckstrncpy(old,tmp,CKMAXPATH);
8815 if (*destdir) { /* Directory-to-move-to given? */
8816 ckstrncat(destdir,new,CKMAXPATH);
8818 } else if (*srcpath && !arg2isfile) { /* Or was there a source path? */
8819 ckstrncat(srcpath,new,CKMAXPATH);
8823 debug(F110,"XXX 2",new,0);
8825 skip = 0; /* Can we skip this one? */
8827 if (casing && !replaced) {
8828 skip = (((all == 0) && (flag == 3)) || (flag == casing)) ? 1 : 0;
8829 if (!skip && destdir) skip = 0;
8831 #endif /* COMMENT */
8833 if (!ckstrcmp(old,new,-1,1))
8836 if (op == 0 && !skip && (collision != RENX_OVWR)) {
8837 if (zchki(new) > (CK_OFF_T)-1) { /* New file already exists? */
8838 switch (collision) { /* Yes, take specified action */
8839 case RENX_SKIP: /* Skip this one and proceed */
8842 case RENX_FAIL: /* Or fail. */
8844 if (!listing && !nolist)
8845 printf("?File already exists: %s\n",new);
8849 debug(F110,"RENAMEONE new",new,0);
8850 debug(F101,"RENAMEONE flag","",flag);
8851 debug(F101,"RENAMEONE skip","",skip);
8852 debug(F100,"RENAMEONE ----------------","",0);
8855 if (listing) printf("%s => %s (SKIPPED: %s already exists)\n",
8858 } else if (skip) { /* Skipping this one */
8859 if (listing) printf("%s => %s (%s)\n",
8861 (skip == 2) ? "COLLISION: SKIPPED" : "SKIPPED");
8862 } else { /* Have to rename this one */
8863 if (op == REN_OP_CHK) { /* Checking for collisions */
8864 return((zchki(new) > (CK_OFF_T)-1) ? 0 : 1 );
8865 } else if (op == REN_OP_SIM) { /* Simulating */
8866 if (listing) printf("%s => %s (SIMULATED)\n",old,new);
8867 } else { /* Really renaming */
8868 if (listing) printf("%s => %s ",old,new);
8869 if (zrename(old,new) < 0) {
8872 printf("(FAILED: %s)\n",ck_errstr());
8874 printf("?%s\n",ck_errstr());
8876 if (listing) printf("(OK)\n");
8880 return(success = rc); /* Succeeds also if nothing needed to be renamed */
8888 extern struct keytab fcstab[];
8889 extern struct csinfo fcsinfo[];
8890 #endif /* NOUNICODE */
8891 #endif /* NOCSETS */
8892 int cset1 = 0, cset2 = 0;
8894 int i, x, z, fn, listing = 0, havename = 0, wild = 0, rc = 1, noarg = 0;
8895 int nolist = 0, all = 0, casing = 0, replacing = 0, getval = 0, sim = 0;
8896 int converting = 0, collision = 0;
8901 collision = ren_coll; /* Inherit SET RENAME COLLISION */
8902 listing = ren_list; /* Inhereit SET RENAME LIST */
8904 if (ren_sub[0]) makestr(&(ren_sub[0]),NULL);
8905 if (ren_sub[1]) makestr(&(ren_sub[1]),NULL);
8906 if (ren_sub[2]) makestr(&(ren_sub[2]),NULL);
8910 cmfdbi(&sw, /* 1st FDB - switches */
8912 "Filename or switch", /* hlpmsg */
8914 "", /* addtl string data */
8915 nrenamsw, /* addtl numeric data 1: tbl size */
8916 4, /* addtl numeric data 2: 4 = cmswi */
8917 xxstring, /* Processing function */
8918 renamsw, /* Keyword table */
8919 &fi /* Pointer to next FDB */
8922 cmfdbi(&fi, /* 2nd FDB - file or directory name */
8926 "", /* addtl string data */
8928 0, /* 0 = Parse file or directory names */
8935 printf("?File or directory name required\n");
8940 x = cmfdb(&sw); /* Parse something */
8941 if (x == -3) { /* They hit Enter prematurely */
8942 printf("?Command incomplete\n");
8944 } else if (x < 0) { /* Other error */
8947 if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
8948 printf("?No files match: %s\n",brstrip(atmbuf));
8949 else if (zchki(atmbuf) == -1)
8950 printf("?File not found: %s\n",brstrip(atmbuf));
8952 printf("?Error with switch or filename: %s\n",brstrip(atmbuf));
8955 fn = cmresult.nresult; /* For brevity */
8956 switch (cmresult.fcode) { /* Handle each kind of field */
8957 case _CMKEY: /* Keyword (switch) */
8959 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
8960 printf("?This switch does not take an argument\n");
8963 if (!getval && (cmgkwflgs() & CM_ARG))
8964 noarg = 1; /* Remember arg is missing */
8965 switch (cmresult.nresult) { /* Handle the switch */
8966 case DEL_LIS: /* /LIST */
8967 case DEL_VRB: /* /VERBOSE */
8970 case DEL_NOL: /* /NOLIST */
8971 case DEL_QUI: /* /QUIET */
8975 case DEL_SIM: /* /SIMULATE */
8978 case REN_UPP: /* /UPPER: */
8979 case REN_LOW: /* /LOWER */
8982 if ((x = cmkey((fn == REN_UPP) ? r_upper : r_lower,
8983 2, "","all",xxstring)) < 0) {
8991 /* 0 = don't convert; 1 = convert to lower; 2 = to upper */
8992 casing = (fn == REN_UPP) ? 2 : 1;
8995 case REN_OVW: /* /COLLISION */
8997 if ((x = cmkey(r_collision,
8998 nr_collision,"","overwrite",xxstring))<0) {
9007 case REN_RPL: /* /REPLACE: */
9009 printf("?This switch requires an argument\n");
9012 if ((x = cmfld("String to remove, or {{String1}{String2}}",
9013 "",&s,xxstring)) < 0) {
9015 printf("?Target string required\n");
9021 if (s[0] == '{' && s[1] == '{') /* Get the list */
9022 makelist(s,ren_sub,3);
9024 makestr(&(ren_sub[0]),s);
9029 case REN_SPA: /* /FIXSPACES: */
9031 if ((x = cmfld("Character or string to replace spaces with",
9032 "_",&s,xxstring)) < 0)
9037 makestr(&(ren_sub[0])," ");
9038 makestr(&(ren_sub[1]),noarg ? "_" : brstrip(s));
9039 makestr(&(ren_sub[3]),NULL);
9045 case REN_XLA: /* /CONVERT:cset1:cset2 */
9046 if (!xfcstab) { /* Make a copy of the file charset */
9047 int i, x; /* table with CM_ARG set for each */
9048 x = (nfilc + 1) * sizeof(struct keytab);
9049 xfcstab = (struct keytab *)malloc(x);
9051 printf("?Memory allocation failure\n");
9054 for (i = 0; i < nfilc; i++) {
9055 xfcstab[i].kwd = fcstab[i].kwd;
9056 xfcstab[i].kwval = fcstab[i].kwval;
9057 xfcstab[i].flgs = fcstab[i].flgs | CM_ARG;
9060 if ((x = cmswi(xfcstab,nfilc,
9061 "Character-set of old name","",xxstring)) < 0) {
9063 printf("?Pair of character-set names required\n");
9071 printf("?Secondcharacter-set name required\n");
9074 if ((x = cmkey(fcstab,nfilc,
9075 "Character-set of new name","",xxstring)) < 0) {
9077 printf("?Second character-set name required\n");
9086 makestr(&(ren_sub[0]),NULL);
9088 makestr(&(ren_sub[1]),NULL);
9090 makestr(&(ren_sub[2]),NULL);
9093 #endif /* NOUNICODE */
9094 #endif /* NOCSETS */
9097 case _CMIFI: /* File or directory name */
9098 s = cmresult.sresult;
9102 printf("?File or directory name required\n");
9107 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
9109 printf("?Internal error\n");
9110 return(-9); /* Shouldn't happen */
9112 wild = cmresult.nresult; /* Source specification wild? */
9114 wild = iswild(line);
9116 debug(F111,"RENAME WILD",line,wild);
9118 p = tmpbuf; /* Place for new name */
9120 replacing = ren_sub[0] ? 1 : 0;
9123 if (!(casing || replacing || converting)) {
9124 if ((x = cmofi(wild ? "Target directory" : "New name",
9125 "",&s,xxstring)) < 0) { /* Get new name */
9127 printf("?%s required\n",
9128 wild ? "Target directory" : "New name");
9132 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
9135 if ((x = cmofi(wild ? "Target directory" : "New name",
9136 "",&s,xxstring)) < 0) { /* Get new name */
9138 if (casing || replacing || converting) {
9141 printf("?%s required\n",
9142 wild ? "Target directory" : "New name");
9147 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
9148 #endif /* COMMENT */
9150 if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
9155 printf(" From: %s\n",fcsinfo[cset1].keyword);
9156 printf(" To: %s\n",fcsinfo[cset2].keyword);
9158 #endif /* NOUNICODE */
9160 printf("CASING: %s\n", (casing == 1) ? "LOWER" : "UPPER");
9163 printf("REPLACING: '%s' with '%s'\n",
9165 ren_sub[1] ? ren_sub[1] : "");
9167 #endif /* COMMENT */
9170 if (!wild) /* Just one */
9173 replacing,casing,all,converting,cset1,cset2,
9174 listing,nolist,sim,TMPBUFSIZ,collision));
9176 if (!casing && !replacing && !converting) { /* Multiple files */
9178 printf( /* if target is not a directory */
9179 "?Multiple source files not allowed if target is not a directory.\n");
9184 else { /* Show full path of target */
9185 char buf[CKMAXPATH]; /* (too much) */
9186 if (zfnqfp(p,CKMAXPATH,buf))
9187 ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
9189 #endif /* COMMENT */
9192 conres(); /* Let Ctrl-C work. */
9194 debug(F110,"dorename line",line,0);
9197 z = zxrewind(); /* Rewind file list */
9199 z = nzxpand(s,0); /* Expand file list */
9200 #endif /* ZXREWIND */
9201 debug(F111,"dorename p",p,z);
9205 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
9208 /* For /COLLISION:FAIL make a silent pass to see if there would be any */
9210 if (collision == RENX_FAIL) {
9212 char line[CKMAXPATH+2];
9214 if (!(z == 0 && !wild))
9218 if (!renameone((char *)line,p,
9219 replacing,casing,all,converting,cset1,cset2,
9220 0,1,REN_OP_CHK,TMPBUFSIZ,RENX_FAIL))
9224 printf("?Failed: %d file%s would be overwritten\n",
9225 n, (n != 1) ? "s" : "");
9227 concb((char)escape);
9229 return(success = 0);
9231 /* Get the file list back. */
9236 #endif /* ZXREWIND */
9238 while (z-- > 0 && rc > 0) {
9239 char line[CKMAXPATH+2];
9240 if (!(z == 0 && !wild))
9244 rc = renameone((char *)line,p,
9245 replacing,casing,all,converting,cset1,cset2,
9246 listing,nolist,sim,TMPBUFSIZ,collision);
9249 concb((char)escape);
9251 return(success = rc);
9253 #endif /* ZRENAME */
9254 #endif /* NOFRILLS */
9255 #endif /* NORENAME */
9259 /* Do the RETURN command */
9262 doreturn(s) char *s; {
9268 printf("\n?Can't return from level %d\n",maclvl);
9269 return(success = 0);
9271 line = malloc(LINBUFSIZ);
9273 return(success = 0);
9274 lp = line; /* Expand return value now */
9277 debug(F110,"RETURN s",s,0);
9278 if (zzstring(s,&lp,&x) > -1) {
9280 debug(F110,"RETURN zzstring",s,0);
9283 /* Pop from all FOR/WHILE/SWITCH/XIFs */
9284 while ((maclvl > 0) &&
9285 (m_arg[maclvl-1][0]) &&
9286 (cmdstk[cmdlvl].src == CMD_MD) &&
9287 (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
9288 !strncmp(m_arg[maclvl-1][0],"_for",4) ||
9289 !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
9290 !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
9291 debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl);
9292 dogta(XXPTA); /* Put args back */
9293 popclvl(); /* Pop up two levels */
9296 if (tra_asg) { /* If tracing show return value */
9298 printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
9300 printf("<<< %s: (null)\n", m_arg[maclvl][0]);
9302 popclvl(); /* Pop from enclosing TAKE or macro */
9303 debug(F111,"RETURN tolevel",s,maclvl);
9306 makestr(&(mrval[maclvl+1]),s); /* Set the RETURN value */
9308 return(success = 1); /* Macro succeeds if we RETURN */
9313 /* Do the OPEN command */
9316 doopen() { /* OPEN { append, read, write } */
9317 int x, y, z = 0; char *s;
9318 static struct filinfo fcb; /* (must be static) */
9319 if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
9321 printf("?Mode required\n");
9326 case OPN_FI_R: /* Old file (READ) */
9327 if (chkfn(ZRFILE) > 0) {
9328 printf("?Read file already open\n");
9331 if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
9333 printf("?Input filename required\n");
9337 if (y) { /* No wildcards allowed */
9338 printf("\n?Please specify a single file\n");
9341 ckstrncpy(line,s,LINBUFSIZ);
9342 if ((int)strlen(line) < 1) return(-2);
9343 if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
9346 printf("?Positive number required\n");
9349 if ((z = cmcfm()) < 0) return(z);
9352 free((char *)readbuf);
9353 if (!(readbuf = (CHAR *) malloc(readblock+1))) {
9354 printf("?Can't allocate read buffer\n");
9357 return(success = zopeni(ZRFILE,line));
9361 case OPN_PI_R: /* Pipe/Process (!READ) */
9363 printf("?Read from pipe disabled\n");
9366 if (chkfn(ZRFILE) > 0) {
9367 printf("?Read file already open\n");
9370 if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
9372 printf("?Command name required\n");
9376 ckstrncpy(line,brstrip(s),LINBUFSIZ);
9377 if (!line[0]) return(-2);
9378 if ((y = cmcfm()) < 0) return(y);
9380 if (!(readbuf = (CHAR *) malloc(readblock+1))) {
9381 printf("?Can't allocate read buffer\n");
9385 return(success = zxcmd(ZRFILE,line));
9387 case OPN_PI_W: /* Write to pipe */
9389 printf("?Write to pipe disabled\n");
9392 if (chkfn(ZWFILE) > 0) {
9393 printf("?Write file already open\n");
9396 if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
9398 printf("?Command name required\n");
9402 ckstrncpy(line,brstrip(s),LINBUFSIZ);
9403 if (!line[0]) return(-2);
9404 if ((y = cmcfm()) < 0) return(y);
9405 success = zxcmd(ZWFILE,line);
9406 if (!success && msgflg)
9407 printf("Can't open process for writing: %s\n",line);
9412 case OPN_FI_W: /* New file (WRITE) */
9413 case OPN_FI_A: /* (APPEND) */
9414 if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
9416 printf("?Filename required\n");
9421 printf("?Sorry, %s is a directory name\n",s);
9424 if (chkfn(ZWFILE) > 0) {
9425 printf("?Write/Append file already open\n");
9428 fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
9430 fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
9431 ckstrncpy(line,s,LINBUFSIZ);
9432 if ((int)strlen(line) < 1) return(-2);
9433 if ((y = cmcfm()) < 0) return(y);
9434 return(success = zopeno(ZWFILE,line,NULL,&fcb));
9437 case OPN_SER: /* OPEN PORT or LINE */
9438 case OPN_NET: { /* OPEN HOST */
9439 extern int didsetlin, ttnproto;
9444 if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
9452 #endif /* NOLOCAL */
9455 printf("?Not implemented");
9462 /* D O X G E T -- GET command parser with switches */
9467 #endif /* CK_LABELED */
9470 doxget(cx) int cx; {
9471 extern int /* External variables we need */
9474 #endif /* RECURSIVE */
9475 xfermode, fdispla, protocol, usepipes,
9476 g_binary, g_xfermode, g_displa, g_rpath, g_usepipes;
9477 extern char * rcv_move; /* Directory to move new files to */
9478 extern char * rcv_rename; /* What to rename new files to */
9479 extern char * rcvexcept[]; /* RECEIVE / GET exception list */
9480 int opkt = 0; /* Flag for O-Packet needed */
9483 extern int pipesend;
9484 extern char * rcvfilter;
9485 #endif /* PIPESEND */
9486 extern struct keytab rpathtab[];
9487 extern int nrpathtab;
9488 extern CK_OFF_T calibrate;
9489 int asname = 0; /* Flag for have as-name */
9490 int konly = 0; /* Kermit-only function */
9491 int c, i, n, confirmed = 0; /* Workers */
9492 int getval = 0; /* Whether to get switch value */
9493 int rcvcmd = 0; /* Whether it is the RECEIVE command */
9494 int mget = 0; /* Whether it is the MGET command */
9495 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
9496 struct FDB sw, fl, cm; /* FDBs for each parse function */
9497 char * cmdstr = "this command";
9500 if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) {
9502 extern int ftpisopen();
9503 if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) {
9506 debug(F101,"doftpget return","",x);
9509 debug(F101,"doftpget success","",success);
9515 debug(F101,"xget cx","",cx);
9520 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
9523 pv[i].wval = (CK_OFF_T)-1;
9525 /* Preset switch values based on top-level command that called us */
9528 case XXREC: /* RECEIVE */
9531 case XXGET: /* GET */
9536 case XXREGET: /* REGET */
9539 pv[SND_BIN].ival = 1; /* Implies /BINARY */
9540 pv[SND_RES].ival = 1; break;
9541 #endif /* CK_RESEND */
9542 case XXRETR: /* RETRIEVE */
9543 cmdstr = "RETRIEVE";
9545 pv[SND_DEL].ival = 1; break;
9547 case XXCREC: /* CRECEIVE */
9548 cmdstr = "CRECEIVE";
9551 pv[SND_CMD].ival = 1; break;
9552 case XXCGET: /* CGET */
9555 pv[SND_CMD].ival = 1; break;
9556 #endif /* PIPESEND */
9558 case XXMGET: /* MGET */
9564 debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
9565 debug(F101,"xget konly","",konly);
9568 if (!rcvcmd && protocol != PROTO_K) {
9569 printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
9574 /* Set up chained parse functions... */
9576 cmfdbi(&sw, /* First FDB - command switches */
9579 "Optional name/template to store incoming files under, or switch" :
9580 "Remote filename, or switch", /* hlpmsg */
9582 "", /* addtl string data */
9583 rcvcmd ? nrcvtab : ngettab, /* addtl numeric data 1: tbl size */
9584 4, /* addtl numeric data 2: 4 = cmswi */
9585 xxstring, /* Processing function */
9586 rcvcmd ? rcvtab : gettab, /* Keyword table */
9587 &fl /* Pointer to next FDB */
9589 if (rcvcmd || mget) /* RECEIVE or MGET */
9592 rcvcmd ? /* hlpmsg */
9593 "Output filename or Command" : /* Output filename */
9594 "File(s) to GET", /* Files we are asking for */
9596 "", /* addtl string data */
9597 0, /* addtl numeric data 1 */
9598 0, /* addtl numeric data 2 */
9601 (protocol == PROTO_X || protocol == PROTO_XC) ?
9603 (rcvcmd ? (xx_strp)0 : xxstring)
9605 rcvcmd ? (xx_strp)0 : xxstring /* Processing function */
9608 xxstring /* Always evaluate - fdc 2006/02/01 */
9609 #endif /* COMMENT */
9615 cmfdbi(&fl, /* Remote filename or command */
9617 "Remote filename", /* hlpmsg */
9619 "", /* addtl string data */
9620 0, /* addtl numeric data 1 */
9621 0, /* addtl numeric data 2 */
9626 cmfdbi(&cm, /* Confirmation */
9630 "", /* addtl string data */
9631 0, /* addtl numeric data 1 */
9632 0, /* addtl numeric data 2 */
9638 /* (See doxsend() for fuller commentary) */
9640 while (1) { /* Parse 0 or more switches */
9641 x = cmfdb(&sw); /* Parse something */
9642 debug(F101,"xget cmfdb","",x);
9643 if (x < 0) /* Error */
9644 goto xgetx; /* or reparse needed */
9645 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
9647 c = cmgbrk(); /* Get break character */
9648 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
9649 printf("?This switch does not take an argument\n");
9653 if (!getval && (cmgkwflgs() & CM_ARG)) {
9654 printf("?This switch requires an argument\n");
9658 n = cmresult.nresult; /* Numeric result = switch value */
9659 debug(F101,"xget switch","",n);
9661 switch (n) { /* Process the switch */
9663 case SND_CMD: /* These take no args */
9665 printf("?Sorry, system command access is disabled\n");
9668 } else if (rcvfilter) {
9670 "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
9675 sw.hlpmsg = "Command, or switch"; /* Change help message */
9677 #endif /* PIPESEND */
9679 case SND_REC: /* /RECURSIVE */
9680 pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
9681 pv[n].ival = 1; /* Set the recursive flag */
9684 case SND_RES: /* /RECOVER */
9685 pv[SND_BIN].ival = 1; /* Implies /BINARY */
9686 pv[n].ival = 1; /* Set the resend flag */
9689 case SND_DEL: /* /DELETE */
9690 case SND_SHH: /* /QUIET */
9691 case SND_CAL: /* /CALIBRATE */
9692 case SND_XPA: /* /TRANSPARENT */
9693 pv[n].ival = 1; /* Just set the appropriate flag */
9696 case SND_PIP: /* /PIPES:{ON,OFF} */
9701 if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
9707 /* File transfer modes - each undoes the others */
9709 case SND_BIN: /* Binary */
9710 case SND_TXT: /* Text */
9711 case SND_IMG: /* Image */
9712 case SND_LBL: /* Labeled */
9713 pv[SND_BIN].ival = 0; /* Unset all */
9714 pv[SND_TXT].ival = 0;
9715 pv[SND_IMG].ival = 0;
9716 pv[SND_LBL].ival = 0;
9717 pv[n].ival = 1; /* Set the requested one */
9720 case SND_EXC: /* Excludes */
9722 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
9724 printf("?Pattern required\n");
9729 if (pv[n].sval) free(pv[n].sval);
9732 printf("?Pattern too long - 256 max\n");
9736 pv[n].sval = malloc(y+1);
9738 strcpy(pv[n].sval,s); /* safe */
9744 /* Not implemented */
9745 case SND_PRI: /* GET to printer */
9748 if ((x = cmfld("Print options","",&s,xxstring)) < 0)
9750 pv[n].sval = malloc((int)strlen(s)+1);
9752 strcpy(pv[n].sval,s); /* safe */
9754 #endif /* COMMENT */
9756 case SND_MOV: /* MOVE after */
9757 case SND_REN: /* RENAME after */
9759 if ((x = cmfld(n == SND_MOV ?
9760 "device and/or directory for source file after sending" :
9761 "new name for source file after sending",
9764 n == SND_MOV ? xxstring : NULL
9767 printf("%s\n", n == SND_MOV ?
9768 "?Destination required" :
9769 "?New name required"
9782 pv[n].sval = malloc(y+1);
9784 strcpy(pv[n].sval,s); /* safe */
9790 case SND_ASN: /* As-name */
9793 printf("?Sorry, as-name not allowed with MGET\n");
9799 (x = cmfld("Name to store it under","",&s,NULL))
9801 (x = cmfld("Name to store it under","",&s,xxstring))
9802 #endif /* COMMENT */
9806 if ((y = strlen(s)) > 0) {
9807 if (pv[n].sval) free(pv[n].sval);
9808 pv[n].sval = malloc(y+1);
9810 strcpy(pv[n].sval,s); /* safe */
9817 case SND_FLT: /* Filter */
9818 debug(F101,"xget /filter getval","",getval);
9820 if ((x = cmfld("Filter program to receive through",
9827 if (*s) s = brstrip(s);
9829 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
9830 if (s[x] != '\\') continue;
9831 if (s[x+1] == 'v') break;
9835 "?Filter must contain a replacement variable for filename.\n"
9845 if ((y = strlen(s)) > 0) {
9846 if ((pv[n].sval = malloc(y+1)))
9847 strcpy(pv[n].sval,s); /* safe */
9850 #endif /* PIPESEND */
9852 case SND_PTH: /* Pathnames */
9854 pv[n].ival = PATH_REL;
9857 if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
9859 pv[n].ival = x; /* Ditto */
9862 case SND_NAM: /* Filenames */
9864 if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
9869 case SND_PRO: /* Protocol to use */
9871 if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
9878 debug(F111,"xget /proto",atmbuf,x);
9880 if (konly && x != PROTO_K) {
9882 "?Sorry, this command works only with Kermit protocol\n"
9890 printf("?Unexpected switch value - %d\n",cmresult.nresult);
9895 debug(F101,"xget cmresult fcode","",cmresult.fcode);
9897 cmarg = line; /* Initialize string pointers */
9900 line[0] = NUL; /* and buffers. */
9903 switch (cmresult.fcode) { /* How did we get out of switch loop */
9904 case _CMFLD: /* (3) Remote filespec */
9905 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
9907 case _CMTXT: /* (4) As-name */
9909 ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
9910 if ((int)strlen(tmpbuf) > 0)
9913 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
9915 case _CMCFM: /* (6) Confirmation */
9919 printf("?Unexpected function code: %d\n",cmresult.fcode);
9923 debug(F110,"xget string",cmarg,0);
9924 debug(F101,"xget confirmed","",confirmed);
9926 cmarg = brstrip(cmarg); /* Strip any braces */
9928 if (!confirmed) { /* CR not typed yet, get more fields */
9929 if (pv[SND_CMD].ival > 0) {
9930 debug(F100,"xget calling cmtxt","",0);
9931 x = cmtxt("Local command to pipe into","",&s,NULL);
9932 if (x < 0 && x != -3) goto xgetx;
9934 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
9937 } else if (!rcvcmd) {
9939 /* cmofi() fails if you give it a directory name */
9940 x = cmfld("Name or directory for incoming file","",&s,NULL);
9941 debug(F111,"xget cmfld",s,x);
9943 x = cmofi("Name or directory for incoming file","",&s,NULL);
9944 debug(F111,"xget cmofi",s,x);
9946 if (x < 0 && x != -3) goto xgetx;
9948 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
9949 if ((x = cmcfm()) < 0) goto xgetx;
9954 /* Arrive here with cmarg and cmarg2 all set */
9956 debug(F111,"xget asname",cmarg2,asname);
9958 if (pv[SND_ASN].sval)
9959 ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
9963 cmarg2 = brstrip(cmarg2); /* Strip outer braces if any. */
9964 debug(F110,"xget cmarg",cmarg,0);
9965 debug(F110,"xget cmarg2",cmarg2,0);
9968 (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
9969 printf("?A remote file specification is required\n");
9974 if (pv[SND_CMD].ival > 0) { /* /COMMAND sets pipesend flag */
9977 printf("?Command required\n");
9979 } else if (nopush) {
9980 printf("?Sorry, system command access is disabled\n");
9982 } else if (rcvfilter) {
9983 printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
9988 debug(F101,"xget /COMMAND pipesend","",pipesend);
9989 #endif /* PIPESEND */
9992 if (pv[SND_RES].ival > 0) { /* REGET or GET /RECOVER */
9994 if (pv[SND_REC].ival > 0) { /* RECURSIVE */
9996 printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
10001 #endif /* COMMENT */
10003 #endif /* RECURSIVE */
10004 if (pv[SND_DEL].ival > 0) { /* /DELETE */
10006 printf("?Unsupported option combination: /RECOVER /DELETE\n");
10011 #endif /* COMMENT */
10014 #endif /* CK_RESEND */
10016 if (pv[SND_EXC].ival > 0) /* /EXCEPT */
10017 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
10022 && protocol == PROTO_K
10023 #endif /* CK_XYZ */
10025 if (!iks_wait(KERMIT_REQ_START,1)) {
10027 "?A Kermit Server is not available to process this command\n");
10028 x = -9; /* correct the return code */
10032 #endif /* IKS_OPTION */
10036 int po, pg; /* (for clarity) */
10037 po = pv[SND_PRO].ival; /* /PROTOCOL option */
10038 pg = protocol; /* Protocol global */
10039 if ((rcvcmd && !*cmarg2) && /* If no as-name was given */
10040 /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */
10041 ((po < 0 && (pg == PROTO_X || pg == PROTO_XC)) ||
10042 (po > -1 && (po == PROTO_X || po == PROTO_XC)))
10045 "Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
10051 #endif /* CK_XYZ */
10054 if (pv[SND_REC].ival > 0) { /* RECURSIVE */
10056 pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames too */
10058 #endif /* RECURSIVE */
10060 if (pv[SND_PIP].ival > -1) {
10061 g_usepipes = usepipes;
10062 usepipes = pv[SND_PIP].ival;
10065 /* Save global protocol parameters */
10067 g_proto = protocol;
10069 g_lf_opts = lf_opts; /* Save labeled transfer options */
10070 #endif /* CK_LABELED */
10071 g_urpsiz = urpsiz; /* Receive packet length */
10072 g_spsizf = spsizf; /* Send packet length flag */
10073 g_spsiz = spsiz; /* Send packet length */
10074 g_spsizr = spsizr; /* etc etc */
10077 g_prefixing = prefixing;
10080 g_fnspath = fnspath;
10081 g_fnrpath = fnrpath;
10084 if (pv[SND_PRO].ival > -1) { /* Change according to switch */
10085 protocol = pv[SND_PRO].ival;
10086 if (ptab[protocol].rpktlen > -1) /* copied from initproto() */
10087 urpsiz = ptab[protocol].rpktlen;
10088 if (ptab[protocol].spktflg > -1)
10089 spsizf = ptab[protocol].spktflg;
10090 if (ptab[protocol].spktlen > -1) {
10091 spsiz = ptab[protocol].spktlen;
10093 spsizr = spmax = spsiz;
10095 if (ptab[protocol].winsize > -1)
10096 wslotr = ptab[protocol].winsize;
10097 if (ptab[protocol].prefix > -1)
10098 prefixing = ptab[protocol].prefix;
10099 if (ptab[protocol].fnca > -1)
10100 fncact = ptab[protocol].fnca;
10101 if (ptab[protocol].fncn > -1)
10102 fncnv = ptab[protocol].fncn;
10103 if (ptab[protocol].fnsp > -1)
10104 fnspath = ptab[protocol].fnsp;
10105 if (ptab[protocol].fnrp > -1)
10106 fnrpath = ptab[protocol].fnrp;
10108 debug(F101,"xget protocol","",protocol);
10109 debug(F111,"xget cmarg2",cmarg2,xfermode);
10111 g_xfermode = xfermode;
10113 if (pv[SND_BIN].ival > 0) { /* Change according to switch */
10114 xfermode = XMODE_M;
10115 binary = XYFT_B; /* FILE TYPE BINARY */
10116 omode = GMOD_BIN; /* O-Packet mode */
10117 debug(F101,"doxget /BINARY xfermode","",xfermode);
10118 } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */
10119 xfermode = XMODE_M;
10122 debug(F101,"doxget /TEXT xfermode","",xfermode);
10123 } else if (pv[SND_IMG].ival > 0) {
10124 xfermode = XMODE_M;
10131 debug(F101,"doxget /IMAGE xfermode","",xfermode);
10134 else if (pv[SND_LBL].ival > 0) {
10135 xfermode = XMODE_M;
10138 debug(F101,"doxget /LABELED xfermode","",xfermode);
10140 #endif /* CK_LABELED */
10141 debug(F101,"xget binary","",binary);
10142 debug(F101,"xget omode","",omode);
10144 if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */
10145 xfrxla = 0; /* Don't translate character sets */
10148 if (pv[SND_FLT].ival > 0)
10149 makestr(&rcvfilter,pv[SND_FLT].sval);
10150 #endif /* PIPESEND */
10153 if (pv[SND_MOV].ival > 0) {
10155 char * p = pv[SND_MOV].sval;
10158 printf("?Sorry, /MOVE-TO not available to guests\n");
10162 #endif /* CK_LOGIN */
10164 if (!isdir(p)) { /* Check directory */
10167 s = (char *)malloc(len + 4);
10169 strcpy(s,p); /* safe */
10171 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
10173 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
10174 #endif /* datageneral */
10180 printf("?Can't create \"%s\"\n",p);
10186 printf("?Directory \"%s\" not found\n",p);
10189 #endif /* CK_MKDIR */
10191 zfnqfp(p,LINBUFSIZ,line);
10192 makestr(&rcv_move,line);
10194 #endif /* CK_TMPDIR */
10196 if (pv[SND_REN].ival > 0) { /* /RENAME-TO:name */
10197 char * p = pv[SND_REN].sval;
10200 printf("?Sorry, /RENAME-TO not available to guests\n");
10204 #endif /* CK_LOGIN */
10207 printf("?New name required for /RENAME\n");
10212 makestr(&rcv_rename,p);
10213 debug(F110,"xget rcv_rename","",0);
10217 if (pv[SND_CAL].ival > 0)
10218 calibrate = (CK_OFF_T)1;
10219 #endif /* CALIBRATE */
10220 g_displa = fdispla;
10221 if (pv[SND_SHH].ival > 0)
10223 debug(F101,"xget display","",fdispla);
10225 if (pv[SND_NAM].ival > -1) { /* /FILENAMES */
10226 g_fncnv = fncnv; /* Save global value */
10227 fncnv = pv[SND_NAM].ival;
10228 debug(F101,"xsend fncnv","",fncnv);
10229 /* We should also handle O packet filename option here */
10230 /* but we don't really need to since WHATAMI already handles it */
10232 if (pv[SND_PTH].ival > -1) { /* PATHNAMES */
10233 g_rpath = fnrpath; /* Save global values */
10234 fnrpath = pv[SND_PTH].ival;
10235 debug(F101,"xsend fnrpath","",fnrpath);
10237 if (fnrpath != PATH_OFF) {
10240 debug(F101,"xsend fncnv","",fncnv);
10242 /* We should also handle O packet pathname option here */
10243 /* but we don't really need to since WHATAMI already handles it */
10244 #endif /* NZLTOR */
10247 /* Set protocol start state */
10249 if (opkt) { /* Extended GET Options*/
10250 sstate = (CHAR) 'o';
10252 if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
10253 if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
10254 if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
10256 sstate = (CHAR) 'v'; /* RECEIVE or CRECEIVE */
10257 else if (pv[SND_DEL].ival > 0)
10258 sstate = (CHAR) 'h'; /* GET /DELETE (= RETRIEVE) */
10259 else if (pv[SND_RES].ival > 0)
10260 sstate = (CHAR) 'j'; /* GET /RECOVER (= REGET) */
10262 sstate = (CHAR) 'r'; /* Regular GET */
10264 debug(F000,"xget sstate","",sstate);
10270 if (pv[SND_SHH].ival != 0)
10272 if (protocol == PROTO_K) /* fdc 20070108 */
10279 #endif /* PIPESEND */
10283 cmarg2 is also allowed to be a device or directory name;
10284 even the name of a directory that doesn't exist.
10286 y = strlen(cmarg2);
10287 debug(F111,"xget strlen(cmarg2)",cmarg2,y);
10290 ((isalpha(cmarg2[0]) &&
10291 cmarg2[1] == ':' &&
10292 cmarg2[2] == NUL) ||
10293 (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
10297 (cmarg2[y-1] == '/' || isdir(cmarg2))
10300 (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
10303 (cmarg2[y-1] == '>' || isdir(cmarg2))
10306 (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
10309 #endif /* datageneral */
10310 #endif /* STRATUS */
10312 #endif /* UNIXOROSK */
10315 debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
10320 ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
10321 f_tmpdir = 1; /* and that we did this */
10323 printf("?Can't get current directory\n");
10330 x = zchki(cmarg2); /* Does as-name exist? */
10331 if (x == -1) { /* Doesn't exist */
10332 char * p = NULL; /* Try to create it */
10333 x = strlen(cmarg2);
10334 if ((p = (char *)malloc(x+4))) {
10335 sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */
10339 printf("?Can't create %s\n",cmarg2);
10345 #endif /* CK_MKDIR */
10346 if (!zchdir(cmarg2)) { /* change to given disk/directory, */
10347 printf("?Can't access %s\n",cmarg2);
10354 #endif /* CK_TMPDIR */
10356 ckstrncpy(fspec,cmarg,CKMAXPATH); /* Note - this is a REMOTE filespec */
10357 debug(F111,"xget fspec",fspec,fspeclen);
10358 debug(F110,"xget cmarg2",cmarg2,0);
10361 for (i = 0; i < SND_MAX; i++)
10366 #endif /* NOXFER */
10371 D O G T A -- Do _GETARGS or _PUTARGS Command.
10373 Used by XIF, FOR, WHILE, and SWITCH, each of which are implemented as
10374 2-level macros; the first level defines the macro, the second runs it.
10375 This routine hides the fact that they are macros by importing the
10376 macro arguments (if any) from two levels up, to make them available
10377 in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
10378 loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
10379 _PUTARGS is in case we changed any of these variables or used SHIFT
10380 on them, so the new values won't be lost as we pop up the stack.
10383 dogta(cx) int cx; {
10385 char c, *p, mbuf[4];
10386 extern int topargc, cmdint;
10387 extern char ** topxarg;
10389 if ((y = cmcfm()) < 0)
10391 debug(F101,"dogta cx","",cx);
10392 debug(F101,"dogta maclvl","",maclvl);
10394 debug(F101,"dogta _GETARGS maclvl","",maclvl);
10395 } else if (cx == XXPTA) {
10396 debug(F101,"dogta _PUTARGS maclvl","",maclvl);
10401 return(success = 0);
10403 /* Make new copies of macro arguments /%0..9 */
10405 mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
10407 if (cx == XXPTA) { /* Go NOINT because _PUTARGS */
10408 if (cmdint) /* temporarily changes maclvl. */
10409 connoi(); /* Interrupts OFF. */
10411 for (i = 0; i < 10; i++) { /* For all args */
10412 c = (char) (i + '0'); /* Make name */
10413 mbuf[1] = (char) c; /* Insert digit */
10414 if (cx == XXGTA) { /* Get arg from level-minus-2 */
10415 if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
10416 else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
10420 makestr(&(m_line[maclvl]),m_line[maclvl-2]);
10421 #endif /* COMMENT */
10422 } else if (cx == XXPTA) { /* Put args level+2 */
10423 maclvl -= 2; /* This is gross, it's because we're */
10424 addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */
10425 maclvl += 2; /* and addmac() uses maclvl. */
10426 count[cmdlvl - 2] = count[cmdlvl];
10427 intime[cmdlvl - 2] = intime[cmdlvl];
10428 inpcas[cmdlvl - 2] = inpcas[cmdlvl];
10429 takerr[cmdlvl - 2] = takerr[cmdlvl];
10430 merror[cmdlvl - 2] = merror[cmdlvl];
10431 xquiet[cmdlvl - 2] = xquiet[cmdlvl];
10432 xvarev[cmdlvl - 2] = xvarev[cmdlvl];
10433 } else return(success = 0); /* Bad call to this routine */
10435 if (cx == XXPTA) { /* Restore interrupts if we */
10436 if (cmdint) /* turned them off above. */
10437 conint(trap,stptrap);
10439 /* Now take care of the argument vector array \&_[], \v(return), */
10440 /* and \v(argc) by just copying the pointers. */
10442 if (cx == XXGTA) { /* GETARGS from 2 levels up */
10444 a_ptr[0] = topxarg; /* \&_[] array */
10445 a_dim[0] = topargc - 1; /* Dimension doesn't include [0] */
10446 m_xarg[maclvl] = topxarg;
10447 n_xarg[maclvl] = topargc; /* But \v(argc) does include \%0 */
10448 macargc[maclvl] = topargc;
10449 makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
10451 a_ptr[0] = m_xarg[maclvl-2];
10452 a_dim[0] = n_xarg[maclvl-2];
10453 m_xarg[maclvl] = m_xarg[maclvl-2];
10454 n_xarg[maclvl] = n_xarg[maclvl-2];
10455 macargc[maclvl] = n_xarg[maclvl-2];
10456 makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
10459 } else { /* PUTARGS 2 levels up */
10461 a_ptr[0] = m_xarg[maclvl];
10462 m_xarg[maclvl-2] = m_xarg[maclvl];
10463 a_dim[0] = n_xarg[maclvl];
10464 n_xarg[maclvl-2] = n_xarg[maclvl];
10465 macargc[maclvl-2] = n_xarg[maclvl];
10468 return(1); /* Internal command - don't change success */
10474 Do the GOTO and [_]FORWARD commands.
10475 s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
10479 dogoto(s, cx) char *s; int cx; {
10480 int i, j, x, y, z, bc;
10481 int empty = 0, stopflg = 0;
10482 char * cmd; /* Name of this command */
10483 char tmplbl[LBLSIZ+1], *lp; /* Current label from command stream */
10484 char tmp2[LBLSIZ+1]; /* SWITCH label conversion buffer */
10485 char tmp3[LBLSIZ+1]; /* Target label */
10487 stopflg = (cx == XXXFWD); /* _FORWARD (used in SWITCH) */
10488 bc = 0; /* Brace counter */
10490 cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
10492 if (!*s) empty = 1;
10496 debug(F111,"GOTO command",cmd,cx);
10497 debug(F101,"GOTO cmdlvl","",cmdlvl);
10498 debug(F101,"GOTO maclvl","",maclvl);
10499 debug(F101,"GOTO tlevel","",tlevel);
10500 debug(F111,"GOTO target",s,empty);
10503 debug(F110,cmd,s,0);
10504 x = ckstrncpy(tmp3+1,s,LBLSIZ);
10505 debug(F101,"GOTO target len","",x);
10506 debug(F101,"GOTO target at x","",s[x]);
10508 debug(F100,"GOTO target overflow","",0);
10509 printf("?GOTO target or SWITCH case label too long\n");
10510 if (stopflg) dostop(); /* If in SWITCH return to prompt */
10511 return(success = 0);
10514 if (*s != ':') { /* Make copy of label */
10515 tmp3[0] = ':'; /* guaranteed to start with ":" */
10518 if (!stopflg && !empty) {
10519 if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
10520 printf("?Bad label syntax - '%s'\n",s);
10521 if (stopflg) dostop(); /* If in SWITCH return to prompt */
10522 return(success = 0);
10526 printf("?Sorry, %s only works in a command file or macro\n",cmd);
10527 return(success = 0);
10529 y = strlen(s); /* y = length of target label */
10530 debug(F111,cmd,s,y);
10532 while (cmdlvl > 0) { /* As long as not at top level... */
10533 if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
10537 /* GOTO: rewind the macro; FORWARD: start at current position */
10539 lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
10540 m = (int)strlen(lp);
10541 debug(F111,"GOTO in macro",lp,m);
10543 flag = 1; /* flag for valid label position */
10544 for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
10545 if (*lp == '{') /* But only at this level */
10546 bc++; /* Anything inside braces is off */
10547 else if (*lp == '}') /* limits. */
10549 if (stopflg && bc > 0) /* This is good for SWITCH */
10550 continue; /* but interferes with WHILE, etc. */
10555 if (flag) { /* If in valid label position */
10556 if (*lp == SP) /* eat leading spaces */
10558 if (*lp != ':') { /* Look for label introducer */
10559 flag = 0; /* this isn't it */
10560 continue; /* keep looking */
10563 if (!flag) /* We don't have a label */
10564 continue; /* so keep looking... */
10565 xp = lp; tp = tmplbl; /* Copy the label from the macro */
10566 j = 0; /* to make it null-terminated */
10567 while ((*tp = *xp)) {
10568 if (j++ > LBLSIZ-1) { /* j = length of word from macro */
10569 printf("?GOTO target or SWITCH case label too long\n");
10570 if (stopflg) dostop(); /* Return to prompt */
10571 return(success = 0);
10573 if (!*tp || *tp == ',') /* Look for end of word */
10575 else tp++, xp++; /* Next character */
10577 *tp = NUL; /* In case we stopped early */
10578 /* Now do caseless string comparison, using longest length */
10579 debug(F111,"macro GOTO label",s,y);
10580 debug(F111,"macro target label",tmplbl,j);
10581 if (stopflg) { /* Allow variables as SWITCH labels */
10582 int n = LBLSIZ - 1;
10584 zzstring(tmplbl,&p,&n);
10586 printf("?GOTO target or SWITCH case label too long\n");
10587 if (stopflg) dostop(); /* Return to prompt */
10590 ckstrncpy(tmplbl,tmp2,LBLSIZ);
10592 debug(F111,"GOTO s",s,y);
10593 debug(F111,"GOTO tmplbl",tmplbl,j);
10594 debug(F111,"GOTO empty",ckitoa(stopflg),empty);
10596 if (empty) { /* Empty target */
10597 z = (!strcmp(s,":") && /* String is empty */
10598 /* and Label is ":" or ":*"... */
10599 (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*")))
10601 debug(F111,"GOTO","A",z);
10602 } else if (stopflg) {
10603 z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
10604 debug(F111,"GOTO","B",z);
10606 z = (stopflg && inpcas[cmdlvl]) ?
10608 ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
10609 debug(F111,"GOTO","C",z);
10613 } else if (stopflg &&
10614 !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) {
10615 debug(F100,"GOTO DEFAULT","",0);
10621 debug(F111,"GOTO macro i",cmd,i);
10622 debug(F111,"GOTO macro m",cmd,m);
10623 if (i >= m) { /* Didn't find the label */
10624 debug(F101,"GOTO failed cmdlvl","",cmdlvl);
10626 /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */
10629 #endif /* COMMENT */
10630 if ((maclvl > 0) &&
10631 (m_arg[maclvl-1][0]) &&
10632 (cmdstk[cmdlvl].src == CMD_MD) &&
10633 (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
10634 !strncmp(m_arg[maclvl-1][0],"_for",4) ||
10635 !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
10636 !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
10637 dogta(XXPTA); /* Restore args */
10638 debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
10639 popclvl(); /* Pop an extra level */
10641 debug(F101,"GOTO popping","",cmdlvl);
10642 if (!popclvl()) { /* pop up to next higher level */
10643 printf("?Label '%s' not found\n",s); /* if none */
10644 return(0); /* Quit */
10645 } else if (stopflg) { /* SWITCH no case label match */
10646 return(0); /* and no DEFAULT lable. */
10648 continue; /* otherwise look again */
10651 debug(F110,"GOTO found macro label",tmplbl,0);
10652 macp[maclvl] = lp; /* set macro buffer pointer */
10654 } else if (cmdstk[cmdlvl].src == CMD_TF) {
10655 x = 0; /* GOTO issued in take file */
10656 debug(F111,"GOTO in TAKE file",cmd,cx);
10657 if (cx == XXGOTO) { /* If GOTO, but not FORWARD, */
10658 rewind(tfile[tlevel]); /* search file from beginning */
10659 tfline[tlevel] = 0;
10661 while (! feof(tfile[tlevel])) {
10663 /* This is wrong - it lets us jump to labels inside inferior blocks */
10665 if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
10667 if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0)
10668 #endif /* COMMENT */
10669 break; /* If no more, done, label not found */
10670 lp = line; /* Got line */
10671 while (*lp == SP || *lp == HT)
10672 lp++; /* Strip leading whitespace */
10673 if (*lp != ':') continue; /* Check for label introducer */
10674 while (*(lp+1) == SP) { /* Remove space between : and name */
10676 lp++; /* Strip leading whitespace */
10678 tp = lp; /* Get end of word */
10680 while (*tp) { /* And null-terminate it */
10686 if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
10687 x = 1; /* Got it */
10689 } else if (stopflg &&
10690 !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
10695 if (x == 0) { /* If not found, print message */
10696 debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
10699 if (!popclvl()) { /* pop up to next higher level */
10700 printf("?Label '%s' not found\n",s); /* if none */
10701 return(0); /* quit */
10702 } else continue; /* otherwise look again */
10704 return(x); /* Send back return code */
10707 printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
10712 /* Finish parsing and do the IF, XIF, and WHILE commands */
10716 /* C H K V A R -- Check (if it's a) Variable */
10721 Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
10722 have backslashes in them. How do we know if a backslash in a filename is a
10723 directory separator, or if it's a Kermit backslash? This routine does a
10724 rough syntax check of the next few characters and if it looks like it MIGHT
10725 be a variable, then it tries to evaluate it, and if the result is not empty,
10726 we say it's a variable, although sometimes it might not be -- some cases are
10727 truly ambiguous. For example there might a DOS directory called \%a, and
10728 we also have a variable with the same name. This is all for the sake of not
10729 having to tell PC users that they have to double all backslashes in file
10730 and directory names.
10734 Somewhat less crude & disgusting. The previous method was nondeterministic
10735 and (worse) it interfered with macro argument passing. So now we only
10736 check the syntax of backslash-items to see if they are variables, but we
10737 do NOT check their values.
10739 #endif /* OLDCHKVAR */
10741 Call with a string pointer pointing at the backslash of the purported
10742 variable. Returns 1 if it has the syntax of a variable, 0 if not.
10745 chkvar(s) char *s; {
10746 int z = 0; /* Return code - assume failure. */
10747 if (!s) s = ""; /* Watch our for null pointers. */
10748 if (!*s) return(0); /* Empty arg so not a variable. */
10749 if (*s == CMDQ) { /* Object begins with backslash. */
10751 c = s[1]; /* Character following backslash. */
10754 if (c == CMDQ) /* Quoted backslash */
10756 c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
10757 if (c == '%') { /* Simple variable */
10762 #endif /* OLDCHKVAR */
10763 } else if (c == '&') { /* Array */
10764 if (!s[2]) return(0);
10766 t = ckindex("]",s,4,0,1);
10768 return((t > 0) ? 1 : 0);
10769 #endif /* OLDCHKVAR */
10770 } else if (c == '$' || /* Environment variable */
10771 c == 'V' || /* Built-in variable */
10772 c == 'M') { /* Macro name */
10775 return((t > 0) ? 1 : 0);
10776 #endif /* OLDCHKVAR */
10777 } else if (c == 'F') { /* Function reference */
10778 /* Don't actually call it - it might have side effects */
10780 if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */
10781 if ((x = ckindex(")",s,x,0,1)))
10783 /* Insert a better syntax check here if necessary */
10787 t = 255; /* This lets us test \v(xxx) */
10788 lp = line; /* and even \f...(xxx) */
10789 zzstring(s,&lp,&t); /* Evaluate it, whatever it is. */
10790 t = strlen(line); /* Get its length. */
10791 debug(F111,"chkvar",line,t);
10792 z = t > 0; /* If length > 0, it's defined */
10794 #endif /* OLDCHKVAR */
10800 /* B O O L E X P -- Evaluate a Boolean expression */
10802 #define BOOLLEN 1024
10803 static char boolval[BOOLLEN];
10806 boolexp(cx) int cx; {
10807 int x, y, z; char *s, *p;
10808 int parens = 0, pcount = 0, ecount = 0;
10813 CKFLOAT f1 = 0.0, f2 = 0.0;
10814 int f1flag = 0, f2flag = 0;
10815 #endif /* FNFLOAT */
10820 not = 0; /* Flag for whether "NOT" was seen */
10821 z = 0; /* Initial IF condition */
10822 ifargs = 0; /* Count of IF condition words */
10823 bx = boolval; /* Initialize boolean value */
10827 cmfdbi(&kw, /* First FDB - command switches */
10828 _CMKEY, /* fcode */
10829 "Number, numeric-valued variable, Boolean expression, or keyword",
10831 "", /* addtl string data */
10832 nif, /* addtl numeric data 1: tbl size */
10833 0, /* addtl numeric data 2: 4 = silent */
10834 xxstring, /* Processing function */
10835 iftab, /* Keyword table */
10836 &nu /* Pointer to next FDB */
10838 cmfdbi(&nu, /* 2nd FDB - An integer */
10839 _CMNUM, /* fcode */
10842 "", /* addtl string data */
10851 #endif /* FNFLOAT */
10854 cmfdbi(&fl, /* A floating-point number */
10855 _CMFLD, /* fcode */
10858 "", /* addtl string data */
10859 0, /* addtl numeric data 1 */
10860 0, /* addtl numeric data 2 */
10865 #endif /* FNFLOAT */
10866 x = cmfdb(&kw); /* Parse a keyword or a number */
10867 debug(F111,"boolval cmfdb","",x);
10873 debug(F111,"boolval switch","",cmresult.fcode);
10874 switch (cmresult.fcode) { /* What did we get? */
10875 case _CMFLD: { /* A "field" */
10878 s = cmresult.sresult;
10880 C-Kermit 9.0: This allows a macro name to serve as an
10881 IF condition without having to enclose it in \m(...).
10885 !isfloat(cmresult.sresult,0) /* Not a number */
10887 !chknum(cmresult.sresult) /* Not a number */
10888 #endif /* FNFLOAT */
10890 i = mlook(mactab,cmresult.sresult,nmac); /* Look it up */
10891 if (i > -1) /* in the macro table */
10892 s = mactab[x].mval; /* and get its value */
10893 else /* Otherwise if no such macro */
10894 s = "0"; /* evaluate as FALSE. */
10897 if (isfloat(s,0)) { /* A floating-point number? */
10898 f1 = floatval; /* Yes, get its value */
10899 f1flag = 1; /* remember we did this */
10900 ifc = 9999; /* Set special "if-code" */
10904 cmresult.nresult = atoi(s);
10908 #endif /* FNFLOAT */
10912 case _CMNUM: /* A number... */
10913 ifc = 9999; /* Set special "if-code" */
10915 case _CMKEY: /* A keyword */
10916 ifc = cmresult.nresult; /* Get if-code */
10921 switch (ifc) { /* set z = 1 for true, 0 for false */
10922 case 9999: /* Number */
10925 z = (f1 == 0.0) ? 0 : 1;
10927 #endif /* FNFLOAT */
10928 z = (cmresult.nresult == 0) ? 0 : 1;
10930 case XXIFLP: /* Left paren */
10931 if (pcount == 0 && ifargs > 0)
10938 case XXIFRP: /* Right paren */
10949 case XXIFAN: /* AND (&&) */
10955 case XXIFOR: /* OR (||) */
10961 case XXIFNO: /* IF NOT [ NOT [ NOT ... ] ] */
10962 if (bx > boolval) { /* evala() doesn't like cascaded */
10963 if (*(bx-1) == '!') { /* unary operators... */
10964 *(bx-1) = NUL; /* So here, two wrongs make a right. */
10974 case XXIFTR: /* IF TRUE */
10976 debug(F101,"if true","",z);
10979 case XXIFNT: /* IF FALSE */
10981 debug(F101,"if true","",z);
10984 case XXIFSU: /* IF SUCCESS */
10985 z = ( success != 0 ) ? 1 : 0;
10986 debug(F101,"if success","",z);
10989 case XXIFFA: /* IF FAILURE */
10990 z = ( success == 0 ) ? 1 : 0;
10991 debug(F101,"if failure","",z);
10995 case XXIFDE: /* IF DEFINED */
10996 if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
10997 return((x == -3) ? -2 : x);
11003 if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */
11004 extern struct keytab fnctab[];
11006 ckstrncpy(line,s+2,256);
11008 lp = ckstrchr(line,'(');
11010 x = lookup(fnctab,line,nfuncs,&t);
11013 debug(F111,"if defined function",line,z);
11014 } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */
11015 extern struct keytab vartab[];
11018 if (*(s+2) == '(') {
11019 ckstrncpy(line,s+3,256);
11021 lp = ckstrchr(line,')');
11023 x = lookup(vartab,line,nvars,&t);
11025 if (z) { /* 8.0.203 */
11026 int t; /* It must have a value to succeed */
11027 t = 255; /* as in C-Kermit 6.0 and 7.0 */
11028 lp = line; /* (this was broken in 8.0.200-201) */
11029 zzstring(s,&lp,&t);
11031 z = line[0] ? 1 : 0;
11035 debug(F111,"if defined variable",line,z);
11037 z = chkvar(s); /* Starts with backslash */
11038 if (z > 0) { /* Yes... */
11039 t = 255; /* than buffer so if zzstring fails */
11040 lp = line; /* check for that -- overflow means */
11041 line[0] = NUL; /* the quantity is defined. */
11042 x = zzstring(s,&lp,&t);
11043 if ((x < 0 && t != 255) || !line[0])
11045 debug(F111,"if defined zzstring",line,z);
11046 debug(F101,"if defined zzstring t","",t);
11050 z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
11052 debug(F111,"if defined final",s,z);
11056 case XXIFDC: { /* IF DECLARED */
11060 if ((x = cmfld("Array name","",&s,NULL)) < 0)
11061 return((x == -3) ? -2 : x);
11063 if (*(s+1) != '&') {
11067 x = zzstring(s,&lp,&t);
11072 if ((x = arraybounds(s,&j,&k)) > -1) {
11076 else if (j <= a_dim[x])
11078 if (z == 1 && k > a_dim[x])
11084 case XXIFBG: /* IF BACKGROUND */
11085 case XXIFFG: /* IF FOREGROUND */
11086 bgchk(); /* Check background status */
11087 if (ifc == XXIFFG) /* Foreground */
11089 else z = pflag ? 0 : 1; /* Background */
11093 case XXIFCO: /* IF COUNT */
11094 z = ( --count[cmdlvl] > 0 );
11095 if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
11096 debug(F101,"if count","",z);
11100 case XXIFEX: /* IF EXIST */
11102 case XXIFDI: /* IF DIRECTORY */
11103 #endif /* CK_TMPDIR */
11104 case XXIFAB: /* IF ABSOLUTE */
11105 case XXIFLN: /* IF LINK */
11107 ((ifc == XXIFDI) ? "Directory name" : "File"),
11110 NULL /* This allows \'s in filenames */
11118 printf("?File or directory name required\n");
11125 if (ifc == XXIFLN) {
11129 if (ifc == XXIFAB) {
11131 } else if (ifc == XXIFEX) {
11132 z = (zgetfs(s) > -1L);
11133 debug(F101,"if exist 1","",z);
11135 if (!z) { /* File not found. */
11136 int t; /* Try expanding variables */
11137 t = LINBUFSIZ-1; /* and looking again. */
11139 zzstring(s,&lp,&t);
11141 z = ( zchki(s) > -1L );
11142 debug(F101,"if exist 2","",z);
11148 z = (zchki(s) == -2)
11150 /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
11153 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
11157 debug(F101,"if directory 1","",z);
11159 if (!z) { /* File not found. */
11160 int t; /* Try expanding variables */
11161 t = LINBUFSIZ-1; /* and looking again. */
11163 zzstring(s,&lp,&t);
11167 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
11170 debug(F101,"if directory 2","",z);
11172 #endif /* CK_TMPDIR */
11177 case XXIFEQ: /* IF EQUAL (string comparison) */
11178 case XXIFLL: /* IF Lexically Less Than */
11179 case XXIFLG: /* If Lexically Greater Than */
11180 if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
11182 printf("?Text required\n");
11186 s = brstrip(s); /* Strip braces */
11187 x = (int)strlen(s);
11188 if (x > LINBUFSIZ-1) {
11189 printf("?IF: strings too long\n");
11192 lp = line; /* lp points to first string */
11193 ckstrncpy(line,s,LINBUFSIZ);
11194 if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
11196 printf("?Text required\n");
11201 y = (int)strlen(s);
11202 if (x + y + 2 > LINBUFSIZ) {
11203 printf("?IF: strings too long\n");
11206 tp = lp + x + 2; /* tp points to second string */
11207 strcpy(tp,s); /* safe (checked) */
11208 x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
11210 case XXIFEQ: /* IF EQUAL (string comparison) */
11213 case XXIFLL: /* IF Lexically Less Than */
11216 case XXIFLG: /* If Lexically Greater Than */
11220 debug(F101,"IF EQ result","",z);
11224 case XXIFVE: /* IF VERSION */
11225 case XXIFAE: /* IF (arithmetically) = */
11226 case XXIFNQ: /* IF != (not arithmetically equal) */
11227 case XXIFLT: /* IF < */
11228 case XXIFLE: /* IF <= */
11229 case XXIFGE: /* IF >= */
11230 case XXIFGT: { /* IF > */
11232 /* July 2006 - converted to use CK_OFF_T rather than int to */
11233 /* allow long integers on platforms that have ck_off_t > 32 bits */
11235 CK_OFF_T n1 = (CK_OFF_T)0, n2 = (CK_OFF_T)0;
11236 if (ifc == XXIFVE) {
11237 n1 = (CK_OFF_T) vernum;
11239 x = cmfld("first number or variable name","",&s,xxstring);
11241 printf("?Quantity required\n");
11244 if (x < 0) return(x);
11245 debug(F101,"xxifgt cmfld","",x);
11246 ckstrncpy(line,s,LINBUFSIZ);
11247 lp = brstrip(line);
11248 debug(F110,"xxifgt exp1",lp,0);
11250 /* The following bit is for compatibility with old versions of MS-DOS Kermit */
11252 if (!ckstrcmp(lp,"count",5,0)) {
11253 n1 = (CK_OFF_T)count[cmdlvl];
11254 } else if (!ckstrcmp(lp,"version",7,0)) {
11255 n1 = (CK_OFF_T) vernum;
11256 } else if (!ckstrcmp(lp,"argc",4,0)) {
11257 n1 = (CK_OFF_T) macargc[maclvl];
11260 /* End of compatibility bit */
11263 if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */
11267 #endif /* FNFLOAT */
11270 } else { /* Check for arithmetic expression */
11271 q = evala(lp); /* cmnum() does this but ... */
11272 if (chknum(q)) { /* we're not using cmnum(). */
11275 printf("?Value not numeric - %s", lp);
11281 y = cmfld("number or variable name","",&s,xxstring);
11283 printf("?Quantity required\n");
11286 if (y < 0) return(y);
11288 if (!*s) return(-2);
11289 if (ifc == XXIFVE) {
11292 x = (int)strlen(lp);
11295 ckstrncpy(tp,s,LINBUFSIZ-x-2);
11296 debug(F110,"xxifgt exp2",tp,0);
11297 if (!ckstrcmp(tp,"count",5,0)) {
11298 n2 = (CK_OFF_T) count[cmdlvl];
11299 } else if (!ckstrcmp(tp,"version",7,0)) {
11300 n2 = (CK_OFF_T) vernum;
11301 } else if (!ckstrcmp(tp,"argc",4,0)) {
11302 n2 = (CK_OFF_T) macargc[maclvl];
11305 if (isfloat(tp,0) > 1) {
11309 #endif /* FNFLOAT */
11314 if (chknum(q)) { /* we're not using cmnum(). */
11317 printf("?Value not numeric - %s", tp);
11322 xx = (ifc == XXIFVE) ? XXIFGE : ifc;
11325 if (f1flag && !f2flag) {
11329 if (f2flag && !f1flag)
11332 z = ((f1 < f2 && xx == XXIFLT)
11333 || (f1 != f2 && xx == XXIFNQ)
11334 || (f1 <= f2 && xx == XXIFLE)
11335 || (f1 == f2 && xx == XXIFAE)
11336 || (f1 >= f2 && xx == XXIFGE)
11337 || (f1 > f2 && xx == XXIFGT));
11339 #endif /* FNFLOAT */
11340 z = ((n1 < n2 && xx == XXIFLT)
11341 || (n1 != n2 && xx == XXIFNQ)
11342 || (n1 <= n2 && xx == XXIFLE)
11343 || (n1 == n2 && xx == XXIFAE)
11344 || (n1 >= n2 && xx == XXIFGE)
11345 || (n1 > n2 && xx == XXIFGT));
11346 debug(F101,"xxifge z","",z);
11354 case XXIFNU: /* IF NUMERIC */
11355 x = cmfld("variable name or constant","",&s,NULL);
11359 printf("?Quantity required\n");
11366 zzstring(s,&lp,&x);
11368 debug(F110,"xxifnu quantity",lp,0);
11372 This works, but it's not wise -- IF NUMERIC is mostly used to see if a
11373 string really does contain only numeric characters. If they want to force
11374 evaluation, they can use \feval() on the argument string.
11376 if (!z) { /* Not a number */
11377 x_ifnum = 1; /* Avoid "eval" error messages */
11378 q = evala(lp); /* Maybe it's an expression */
11379 z = chknum(q); /* that evaluates to a number */
11380 x_ifnum = 0; /* Put eval messages back to normal */
11381 if (z) debug(F110,"xxifnu exp",lp,0);
11383 #endif /* COMMENT */
11384 debug(F101,"xxifnu chknum","",z);
11389 case XXIFNE: { /* IF NEWER */
11390 char d1[20], * d2; /* Buffers for 2 dates */
11391 if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
11393 ckstrncpy(d1,zfcdat(s),20);
11394 if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
11397 if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
11398 printf("?Failure to get file date\n");
11401 debug(F110,"xxifnewer d1",d1,0);
11402 debug(F110,"xxifnewer d2",d2,0);
11403 z = (strcmp(d1,d2) > 0) ? 1 : 0;
11404 debug(F101,"xxifnewer","",z);
11408 #endif /* ZFCDAT */
11411 case XXIFRO: /* REMOTE-ONLY advisory */
11417 #endif /* NOLOCAL */
11419 #endif /* CK_IFRO */
11421 case XXIFAL: /* ALARM */
11423 debug(F101,"IF ALARM ck_alarm","",ck_alarm);
11424 debug(F110,"IF ALARM alrm_date",alrm_date,0);
11425 debug(F110,"IF ALARM alrm_time",alrm_time,0);
11427 if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
11428 z = 0; /* ALARM not SET */
11429 break; /* so IF ALARM fails */
11431 /* Get current date and time */
11432 ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ);
11435 z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
11436 debug(F101,"IF ALARM date z","",z);
11437 if (z == 0) { /* Dates are the same */
11438 /* Compare times */
11439 z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
11440 debug(F101,"IF ALARM time z","",z);
11442 tmpbuf[0] = NUL; /* z >= 0 if alarm is passed */
11443 z = ((z >= 0) ? 1 : 0); /* z < 0 otherwise */
11444 debug(F101,"IF ALARM final z","",z);
11447 case XXIFOP: /* IF OPEN */
11448 if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
11450 if (x == 9999 || x == ZSTDIO) {
11451 bgchk(); /* Check background status */
11453 } else if (x == 8888) {
11454 z = local ? ttchk() > -1 : 0;
11456 } else if (x == 7777) {
11458 z = dialog ? 1 : 0;
11459 #endif /* CKLOGDIAL */
11461 z = (chkfn(x) > 0) ? 1 : 0;
11465 case XXIFSD: /* Started-From-Dialer */
11467 z = StartedFromDialer;
11473 case XXIFTM: /* Terminal-Macro */
11475 z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
11481 case XXIFEM: /* Emulation is active */
11489 case XXIFIK: /* Running as IKSD? */
11493 case XXIFTA: /* Connection is TAPI */
11497 if (local && !network && tttapi)
11499 #endif /* CK_TAPI */
11500 #endif /* NODIAL */
11503 case XXIFMA: /* IF MATCH */
11504 x = cmfld("String or variable","",&s,xxstring);
11508 printf("?String required\n");
11513 ckstrncpy(line,s,LINBUFSIZ);
11515 debug(F110,"xxifma string",line,0);
11516 x = cmfld("Pattern","",&p,xxstring);
11520 printf("?Pattern required\n");
11525 ckstrncpy(tmpbuf,p,TMPBUFSIZ);
11526 p = brstrip(tmpbuf);
11527 debug(F110,"xxifma pattern",tmpbuf,0);
11528 z = ckmatch(p,s,inpcas[cmdlvl],1);
11531 case XXIFFL: { /* IF FLAG */
11536 case XXIFAV: { /* IF AVAILABLE */
11537 if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
11541 z = ck_krb4_is_installed();
11544 z = ck_krb5_is_installed();
11547 z = ck_srp_is_installed();
11550 z = ck_ssleay_is_installed();
11553 z = ck_ntlm_is_installed();
11556 z = ck_crypt_is_installed();
11559 z = ck_ssh_is_installed();
11566 case XXIFAT: /* IF ASKTIMEOUT */
11570 case XXIFRD: /* IF READABLE */
11571 case XXIFWR: /* IF WRITEABLE */
11572 if ((x = cmfld("File or directory name",
11576 NULL /* This allows \'s in filenames */
11584 printf("?File or directory name required\n");
11591 zchk[io]() do not do what we want here for directories, so we set
11592 a global flag telling it to behave specially in this case. Othewise
11593 we'd have to change the API and change all ck?fio.c modules accordingly.
11595 y = 0; /* Try-again control */
11599 if (ifc == XXIFRD) { /* IF READABLE */
11603 } else if (ifc == XXIFWR) { /* IF WRITEABLE */
11609 if (!z && !y) { /* File not found. */
11610 int t; /* Try expanding variables */
11611 t = LINBUFSIZ-1; /* and looking again. */
11613 zzstring(s,&lp,&t);
11622 case XXIFQU: /* IF QUIET */
11624 debug(F101,"if quiet","",z);
11628 case XXIFWI: /* WILD */
11629 if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
11633 case XXIFCK: /* C-KERMIT */
11641 case XXIFK9: /* K-95 */
11649 case XXIFGU: /* GUI */
11657 case XXIFMS: /* MS-KERMIT */
11661 case XXIFLO: /* IF LOCAL */
11665 case XXIFCM: { /* IF COMMAND */
11666 extern struct keytab cmdtab[];
11668 if ((x = cmfld("Word","",&s,xxstring)) < 0)
11670 z = lookup(cmdtab,s,ncmd,&y);
11671 z = (z == -2 || z > -1) ? 1 : 0;
11675 case XXIFFP: /* IF FLOAT */
11676 if ((x = cmfld("Number","",&s,xxstring)) < 0)
11677 if (x != -3) /* e.g. empty variable */
11681 #endif /* CKFLOAT */
11683 case XXIFKB: /* KBHIT */
11689 case XXIFKG: { /* KERBANG */
11692 z = (xcmdsrc == 0) ? 0 : (cfilef && cmdlvl == 1);
11694 z = (xcmdsrc == 0) ? 0 : (cfilef && tlevel == 0);
11695 #endif /* COMMENT */
11699 case XXIFDB: { /* IF DEBUG - 2010/03/16 */
11705 default: /* Shouldn't happen */
11707 } /* end of switch */
11714 if (bx > boolval + BOOLLEN - 2) {
11715 printf("?Boolean expression too long");
11718 ecount++; /* Expression counter */
11719 debug(F101,"boolexp parens","",parens);
11720 debug(F101,"boolexp pcount","",pcount);
11721 if (parens && pcount > 0)
11724 ifend: /* No more - done */
11726 z = atoi(evalx(boolval));
11727 debug(F111,"boolexp boolval",boolval,z);
11731 /* D O I F -- Do the IF command */
11735 int x, y, z; char *s, *p;
11741 debug(F101,"doif cx","",cx);
11743 z = boolexp(cx); /* Evaluate the condition(s) */
11744 debug(F010,"doif cmdbuf",cmdbuf,0);
11745 debug(F101,"doif boolexp","",z);
11749 if (cx == XXIF) { /* Allow IF to have XIF semantics. */
11754 if (*p == SP || *p == HT)
11762 switch (cx) { /* Separate handling for IF and XIF */
11764 case XXASSER: /* And ASSERT */
11765 if ((x = cmcfm()) < 0)
11767 return(success = z);
11769 case XXIF: /* This is IF... */
11770 ifcmd[cmdlvl] = 1; /* We just completed an IF command */
11771 debug(F101,"doif condition","",z);
11772 if (z) { /* Condition is true */
11773 iftest[cmdlvl] = 1; /* Remember that IF succeeded */
11774 if (maclvl > -1) { /* In macro, */
11775 pushcmd(NULL); /* save rest of command. */
11776 } else if (tlevel > -1) { /* In take file, */
11777 debug(F100, "doif: pushing command", "", 0);
11778 pushcmd(NULL); /* save rest of command. */
11779 } else { /* If interactive, */
11780 cmini(ckxech); /* just start a new command */
11781 printf("\n"); /* (like in MS-DOS Kermit) */
11782 if (pflag) prompt(xxstring);
11784 } else { /* Condition is false */
11785 iftest[cmdlvl] = 0; /* Remember command failed. */
11786 if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
11787 return(y); /* Gobble up rest of line */
11791 case XXIFX: { /* This is XIF (Extended IF) */
11795 if ((y = cmtxt("Object command","",&s,NULL)) < 0)
11796 return(y); /* Get object command. */
11799 debug(F110,"doif THEN part",s,-54);
11800 if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
11803 debug(F111,"doif THEN part 2",line,z);
11805 while (*p == SP) p++; /* Strip trailing spaces */
11806 ifcmd[cmdlvl] = 0; /* Assume ELSE part in same line */
11807 iftest[cmdlvl] = z ? 1 : 0;
11808 if (*p) { /* At end? */
11809 if (!z) { /* No, use ELSE-part, if any */
11810 for (i = 0; i < 4; i++) e[i] = *p++;
11811 if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
11812 return(-2); /* Something else - error. */
11813 debug(F010,"doif ELSE line 1",p,0);
11814 while (*p == SP) p++; /* Skip spaces */
11815 if (*p != '{') { /* Brace ELSE part if necessary */
11816 ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL);
11818 debug(F010,"doif ELSE line 2",p,0);
11820 lp = line; /* Write over THEN part... */
11821 *lp = NUL; /* with ELSE part. */
11822 if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
11825 while (*p == SP) p++; /* Strip trailing spaces */
11826 if (*p) return(-2); /* Should be nothing here. */
11827 debug(F010,"doif ELSE line 3",line,0);
11829 } else { /* At end, treat like an IF command */
11830 if (!z) line[0] = NUL; /* Condition not true and no ELSE */
11831 ifcmd[cmdlvl] = 1; /* Allow ELSE on next line */
11832 debug(F101,"IF condition","",z);
11835 x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
11836 if (x < 0) { /* Not there? */
11837 addmmac("_xif",xif_def); /* Put it back. */
11838 if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
11839 printf("?XIF macro gone!\n");
11840 return(success = 0);
11843 dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
11847 case XXWHI: { /* WHILE Command */
11848 p = cmdbuf; /* Capture IF condition */
11849 ifcond[0] = NUL; /* from command buffer */
11850 while (*p == SP) p++;
11851 while (*p != SP) p++;
11853 ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN);
11856 This doesn't work because it breaks on the first left brace, which does
11857 not necessarily start the command list, e.g. "while equal \%a {\35}".
11859 while (*p != '{' && *p != NUL) *ifcp++ = *p++;
11860 p = " ) goto _..bot) } ";
11861 while (*ifcp++ = *p++) ;
11864 The command parser sets cmbptr to the spot where it left off parsing in
11865 the command buffer.
11868 extern char * cmbptr;
11870 while (p < cmbptr && *p != NUL)
11872 p = " ) goto _..bot) } ";
11873 while ((*ifcp++ = *p++)) ;
11875 printf("?Internal error parsing WHILE condition\n");
11879 #endif /* COMMENT */
11881 debug(F110,"WHILE cmd",ifcond,0);
11883 if ((y = cmtxt("Object command","",&s,NULL)) < 0)
11884 return(y); /* Get object command. */
11887 if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
11890 debug(F101,"WHILE body",line,-54);
11893 x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
11894 if (x < 0) { /* Not there? */
11895 addmmac("_while",whil_def); /* Put it back. */
11896 if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
11897 printf("?WHILE macro definition gone!\n");
11898 return(success = 0);
11901 p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
11903 strcpy(p,ifcond); /* safe (prechecked) */
11904 strcat(p,line); /* safe (prechecked) */
11905 debug(F010,"WHILE dodo",p,0);
11906 dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
11910 printf("?Can't allocate storage for WHILE command");
11911 return(success = 0);
11922 /* Set up a TAKE command file */
11925 dotake(s) char *s; {
11927 extern int tra_cmd;
11931 extern int term_io;
11932 int term_io_sav = term_io;
11934 #endif /* NOLOCAL */
11937 debug(F110,"dotake",s,0);
11939 if (!*s) return(success = 0);
11941 debug(F101,"dotake len","",slen);
11943 if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
11945 debug(F110,"dotake fail",s,0);
11947 return(success = 0);
11949 tfline[tlevel] = 0; /* Line counter */
11951 conres(); /* So Ctrl-C will work */
11955 term_io = 0; /* Disable Terminal Emulator I/O */
11957 #endif /* NOLOCAL */
11959 cmdlvl++; /* Entering a new command level */
11960 debug(F111,"CMD +F",s,cmdlvl);
11961 debug(F101,"dotake cmdlvl","",cmdlvl);
11962 debug(F101,"dotake tlevel","",tlevel);
11963 if (cmdlvl > CMDSTKL) {
11964 debug(F100,"dotake stack overflow","",0);
11966 debug(F111,"CMD*-F",s,cmdlvl);
11967 fclose(tfile[tlevel--]);
11968 printf("?TAKE files and/or DO commands nested too deeply\n");
11969 return(success = 0);
11971 if (tfnam[tlevel]) { /* Copy the filename */
11972 free(tfnam[tlevel]);
11973 tfnam[tlevel] = NULL;
11975 if ((tfnam[tlevel] = malloc(strlen(s) + 1))) {
11976 strcpy(tfnam[tlevel],s); /* safe */
11978 printf("?Memory allocation failure\n");
11979 return(success = 0);
11981 ifcmd[cmdlvl] = 0; /* Set variables for this cmd file */
11982 iftest[cmdlvl] = 0;
11983 count[cmdlvl] = count[cmdlvl-1]; /* Inherit this */
11984 intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
11985 inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
11986 takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
11987 merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
11988 xquiet[cmdlvl] = quiet;
11989 xvarev[cmdlvl] = vareval;
11991 cmdstk[cmdlvl].src = CMD_TF; /* Say we're in a TAKE file */
11992 cmdstk[cmdlvl].lvl = tlevel; /* nested at this level */
11993 cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
11995 takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
12000 printf("[%d] +F: \"%s\"\n",cmdlvl,s);
12004 term_io = term_io_sav;
12006 #endif /* NOLOCAL */