1 #include "ckcsym.h"
2 #ifndef NOICP
3
4 /*
5 Authors:
6 Frank da Cruz <fdc@columbia.edu>,
7 The Kermit Project, New York City
8 Jeffrey E Altman <jaltman@secure-endpoints.com>
9 Secure Endpoints Inc., New York City
10
11 Copyright (C) 1985, 2020,
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.
15
16 Last update:
17 Fri Sep 18 14:55:27 2020
18 */
19
20 /* Includes */
21
22 #include "ckcdeb.h"
23 #include "ckcasc.h"
24 #include "ckcker.h"
25 #include "ckuusr.h"
26 #include "ckcxla.h"
27 #include "ckcnet.h" /* Network symbols */
28 #include <signal.h>
29
30 #ifndef NOSTAT
31 #ifdef VMS
32 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
33 #include <stat.h>
34 #else /* def VMS */
35 #include <sys/stat.h>
36 #endif /* def VMS [else] */
37 #endif /* NOSTAT */
38
39 #ifdef VMS
40 #ifndef TCPSOCKET
41 #include <errno.h>
42 #endif /* TCPSOCKET */
43 #endif /* VMS */
44
45 #ifdef datageneral
46 #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
47 #endif /* datageneral */
48
49 #ifdef QNX6
50 #define readblock kreadblock
51 #endif /* QNX6 */
52
53 /* External Kermit Variables, see ckmain.c for description. */
54
55 extern xx_strp xxstring;
56
57 extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
58 turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
59 zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive;
60
61 extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive,
62 xcmdsrc, nscanfile, reliable, nolinks, cmflgs;
63
64 #ifdef VMSORUNIX
65 extern int zgfs_dir, zgfs_link;
66 #endif /* VMSORUNIX */
67
68 #ifdef CK_IFRO
69 extern int remonly;
70 #endif /* CK_IFRO */
71
72 #ifdef OS2
73 extern int StartedFromDialer ;
74 extern BYTE vmode;
75 extern int k95stdout;
76 #ifndef NT
77 #define INCL_NOPM
78 #define INCL_VIO /* Needed for ckocon.h */
79 #include <os2.h>
80 #undef COMMENT
81 #else
82 #define APIRET ULONG
83 #include <windows.h>
84 #include <tapi.h>
85 #include "ckntap.h"
86 #endif /* NT */
87 #include "ckocon.h"
88 #include "ckodir.h" /* [jt] 2013/11/21 - for MAXPATHLEN */
89 #endif /* OS2 */
90
91 extern long vernum, speed;
92 extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
93 extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
94 extern char *foz_def[];
95 extern char *ckxsys, *ckzsys;
96 #ifndef OS2
97 extern char *DIRCMD;
98 #ifndef UNIX
99 extern char *DELCMD;
100 #endif /* UNIX */
101 #endif /* OS2 */
102 extern char ttname[], filnam[];
103 extern CHAR sstate, feol;
104 extern char *zinptr;
105
106 #ifdef UNIX
107 extern char ** mtchs; /* zxpand() file list */
108 #endif /* UNIX */
109
110 #ifndef NOXFER
111 extern int oopts, omode, oname, opath; /* O-Packet options */
112
113 extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
114 stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
115 atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
116 fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
117 g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
118 g_fnspath, g_fnrpath, xfrxla, g_xfrxla;
119
120 extern char *cmarg, *cmarg2;
121
122 #ifndef NOMSEND /* Multiple SEND */
123 extern char *msfiles[];
124 #endif /* NOMSEND */
125 extern char fspec[]; /* Most recent filespec */
126 extern int fspeclen;
127
128 #ifdef CK_TMPDIR
129 extern int f_tmpdir; /* Directory changed temporarily */
130 extern char savdir[]; /* For saving current directory */
131 #endif /* CK_TMPDIR */
132
133 extern struct keytab protos[]; /* File transfer protocols */
134 extern struct ck_p ptab[NPROTOS];
135 #endif /* NOXFER */
136
137 #ifdef DCMDBUF /* Declarations from cmd package */
138 extern char *cmdbuf, *atmbuf; /* Command buffers */
139 #else
140 extern char cmdbuf[], atmbuf[]; /* Command buffers */
141 #endif /* DCMDBUF */
142
143 extern int nopush;
144
145 #ifndef NOSPL
146 int askflag = 0; /* ASK-class command active */
147 int echostars = 0; /* ASKQ should echo asterisks */
148 extern char **a_ptr[];
149 extern int a_dim[];
150 extern char **m_xarg[];
151 extern int n_xarg[];
152 extern struct mtab *mactab;
153 extern int nmac;
154 extern long ck_alarm;
155 extern char alrm_date[], alrm_time[];
156 extern int x_ifnum;
157 #endif /* NOSPL */
158
159 extern int inserver; /* I am IKSD */
160 extern int backgrd; /* Kermit executing in background */
161 extern char psave[]; /* For saving & restoring prompt */
162 extern char *tp; /* Temporary buffer */
163
164 int readblock = 4096; /* READ buffer size */
165 CHAR * readbuf = NULL; /* Pointer to read buffer */
166 int readsize = 0; /* Number of chars actually read */
167 int getcmd = 0; /* GET-class command was given */
168
169 char chgsourcedir[MAXPATHLEN+1] = { 0,0 }; /* Source directory for CHANGE */
170 char chgdestdir[MAXPATHLEN+1] = { 0,0 }; /* Destination directory for CHANGE */
171 char chgbackupdir[MAXPATHLEN+1] = { 0,0 }; /* Backup directory for CHANGE */
172
173 extern int zchkod, zchkid;
174
175 /* C K U U S 6 -- "User Interface" for Unix Kermit (Part 6) */
176
177 struct keytab deltab[] = { /* DELETE Command Options */
178 { "/all", DEL_ALL, CM_INV },
179 { "/after", DEL_AFT, CM_ARG },
180 { "/ask", DEL_ASK, 0 },
181 { "/before", DEL_BEF, CM_ARG },
182 { "/directories", DEL_DIR, 0 },
183 { "/dotfiles", DEL_DOT, 0 },
184 { "/except", DEL_EXC, CM_ARG },
185 { "/heading", DEL_HDG, 0 },
186 { "/l", DEL_LIS, CM_INV|CM_ABR },
187 { "/larger-than", DEL_LAR, CM_ARG },
188 { "/list", DEL_LIS, 0 },
189 { "/log", DEL_LIS, CM_INV },
190 { "/noask", DEL_NAS, 0 },
191 { "/nodotfiles", DEL_NOD, 0 },
192 { "/noheading", DEL_NOH, 0 },
193 { "/nol", DEL_NOL, CM_INV|CM_ABR },
194 { "/nolist", DEL_NOL, 0 },
195 { "/nolog", DEL_NOL, CM_INV },
196 { "/nopage", DEL_NOP, 0 },
197 { "/not-after", DEL_NAF, CM_ARG },
198 { "/not-before", DEL_NBF, CM_ARG },
199 { "/not-since", DEL_NAF, CM_INV|CM_ARG },
200 { "/page", DEL_PAG, 0 },
201 { "/quiet", DEL_QUI, CM_INV },
202 { "/recursive", DEL_REC, 0 },
203 { "/simulate", DEL_SIM, 0 },
204 { "/since", DEL_AFT, CM_ARG|CM_INV },
205 { "/smaller-than", DEL_SMA, CM_ARG },
206 { "/summary", DEL_SUM, 0 },
207 { "/tree", DEL_ALL, 0 },
208 { "/type", DEL_TYP, CM_ARG },
209 { "/verbose", DEL_VRB, CM_INV }
210 };
211 int ndeltab = sizeof(deltab)/sizeof(struct keytab);
212
213 /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
214
215 struct keytab qvswtab[] = {
216 { "/l", DEL_LIS, CM_INV|CM_ABR },
217 { "/list", DEL_LIS, 0 },
218 { "/log", DEL_LIS, CM_INV },
219 { "/nol", DEL_NOL, CM_INV|CM_ABR },
220 { "/nolist", DEL_NOL, 0 },
221 { "/nolog", DEL_NOL, CM_INV },
222 { "/quiet", DEL_QUI, CM_INV },
223 { "/verbose", DEL_VRB, CM_INV }
224 };
225 int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
226
227 static struct keytab renamsw[] = {
228 { "/collision", REN_OVW, CM_ARG },
229 #ifndef NOUNICODE
230 { "/convert", REN_XLA, CM_ARG },
231 #endif /* NOUNICODE */
232 { "/fixspaces", REN_SPA, CM_ARG },
233 { "/l", DEL_LIS, CM_INV|CM_ABR },
234 { "/list", DEL_LIS, 0 },
235 { "/log", DEL_LIS, CM_INV },
236 { "/lower", REN_LOW, CM_ARG },
237 { "/nol", DEL_NOL, CM_INV|CM_ABR },
238 { "/nolist", DEL_NOL, 0 },
239 { "/nolog", DEL_NOL, CM_INV },
240 { "/quiet", DEL_QUI, CM_INV },
241 { "/replace", REN_RPL, CM_ARG },
242 { "/simulate", DEL_SIM, 0 },
243 { "/upper", REN_UPP, CM_ARG },
244 { "/verbose", DEL_VRB, CM_INV }
245 };
246 static int nrenamsw = sizeof(renamsw)/sizeof(struct keytab);
247
248 static struct keytab renamset[] = {
249 { "collision", REN_OVW, 0 },
250 { "list", DEL_LIS, 0 }
251 };
252 static int nrenamset = sizeof(renamset)/sizeof(struct keytab);
253
254 /* Args for RENAME /LOWER: and /UPPER: */
255
256 static struct keytab r_upper[] = {
257 { "all", 1, 0 },
258 { "lower", 0, 0 }
259 };
260
261 static struct keytab r_lower[] = {
262 { "all", 1, 0 },
263 { "upper", 0, 0 }
264 };
265
266 /* Args for RENAME /COLLISION... */
267
268 #define RENX_FAIL 0
269 #define RENX_OVWR 1
270 #define RENX_SKIP 2
271
272 static struct keytab r_collision[] = {
273 { "fail", RENX_FAIL, 0 },
274 { "overwrite", RENX_OVWR, 0 },
275 { "proceed", RENX_SKIP, CM_INV },
276 { "skip", RENX_SKIP, 0 }
277 };
278 static int nr_collision = sizeof(r_collision)/sizeof(struct keytab);
279
280 struct keytab copytab[] = {
281 { "/append", 998, 0 },
282 #ifndef NOSPL
283 { "/fromb64", 997, 0 },
284 #endif /* NOSPL */
285 { "/l", DEL_LIS, CM_INV|CM_ABR },
286 { "/list", DEL_LIS, 0 },
287 { "/log", DEL_LIS, CM_INV },
288 { "/nol", DEL_NOL, CM_INV|CM_ABR },
289 { "/nolist", DEL_NOL, 0 },
290 { "/nolog", DEL_NOL, CM_INV },
291 { "/overwrite", 994, CM_ARG },
292 #ifndef NOXFER
293 { "/preserve", 995, 0 },
294 #endif /* NOXFER */
295 { "/quiet", DEL_QUI, CM_INV },
296 { "/swap-bytes", 999, 0 },
297 #ifndef NOSPL
298 { "/tob64", 996, 0 },
299 #endif /* NOSPL */
300 { "/verbose", DEL_VRB, CM_INV }
301 };
302 int ncopytab = sizeof(copytab)/sizeof(struct keytab);
303
304 #define OVW_ALWAYS 0
305 #define OVW_NEVER 1
306 #define OVW_OLDER 2
307 #define OVW_NEWER 3
308
309 static struct keytab ovwtab[] = {
310 { "always", OVW_ALWAYS, 0 },
311 { "never", OVW_NEVER, 0 },
312 { "newer", OVW_NEWER, 0 },
313 { "older", OVW_OLDER, 0 }
314 };
315 static int novwtab = 4;
316
317 #ifndef NOXFER
318 static struct keytab gettab[] = { /* GET options */
319 { "/as-name", SND_ASN, CM_ARG },
320 { "/binary", SND_BIN, 0 },
321 #ifdef CALIBRATE
322 { "/calibrate", SND_CAL, CM_INV },
323 #endif /* CALIBRATE */
324 #ifdef PIPESEND
325 { "/command", SND_CMD, CM_PSH },
326 #endif /* PIPESEND */
327 { "/delete", SND_DEL, 0 },
328 { "/except", SND_EXC, CM_ARG },
329 { "/filenames", SND_NAM, CM_ARG },
330 #ifdef PIPESEND
331 { "/filter", SND_FLT, CM_ARG|CM_PSH },
332 #endif /* PIPESEND */
333 #ifdef VMS
334 { "/image", SND_IMG, 0 },
335 { "/labeled", SND_LBL, 0 },
336 #else
337 { "/image", SND_BIN, CM_INV },
338 #endif /* VMS */
339 #ifdef CK_TMPDIR
340 { "/move-to", SND_MOV, CM_ARG },
341 #endif /* CK_TMPDIR */
342 { "/pathnames", SND_PTH, CM_ARG },
343 { "/pipes", SND_PIP, CM_ARG|CM_PSH },
344 { "/quiet", SND_SHH, 0 },
345 #ifdef CK_RESEND
346 { "/recover", SND_RES, 0 },
347 #endif /* CK_RESEND */
348 { "/recursive", SND_REC, 0 },
349 { "/rename-to", SND_REN, CM_ARG },
350 #ifdef COMMENT
351 { "/smaller-than", SND_SMA, CM_ARG },
352 #endif /* COMMENT */
353 { "/subdirectories", SND_REC, CM_INV },
354 { "/text", SND_TXT, 0 },
355 { "/transparent", SND_XPA, 0 }
356 };
357 #define NGETTAB sizeof(gettab)/sizeof(struct keytab)
358 static int ngettab = NGETTAB;
359
360 static struct keytab rcvtab[] = { /* RECEIVE options */
361 { "/as-name", SND_ASN, CM_ARG },
362 { "/binary", SND_BIN, 0 },
363 #ifdef CALIBRATE
364 { "/calibrate", SND_CAL, CM_INV },
365 #endif /* CALIBRATE */
366 #ifdef PIPESEND
367 { "/command", SND_CMD, CM_PSH },
368 #endif /* PIPESEND */
369 { "/except", SND_EXC, CM_ARG },
370 { "/filenames", SND_NAM, CM_ARG },
371 #ifdef PIPESEND
372 { "/filter", SND_FLT, CM_ARG|CM_PSH },
373 #endif /* PIPESEND */
374 #ifdef VMS
375 { "/image", SND_IMG, 0 },
376 { "/labeled", SND_LBL, 0 },
377 #else
378 { "/image", SND_BIN, CM_INV },
379 #endif /* VMS */
380 #ifdef CK_TMPDIR
381 { "/move-to", SND_MOV, CM_ARG },
382 #endif /* CK_TMPDIR */
383 { "/pathnames", SND_PTH, CM_ARG },
384 { "/pipes", SND_PIP, CM_ARG|CM_PSH },
385 #ifdef CK_XYZ
386 { "/protocol", SND_PRO, CM_ARG },
387 #else
388 { "/protocol", SND_PRO, CM_ARG|CM_INV },
389 #endif /* CK_XYZ */
390 { "/quiet", SND_SHH, 0 },
391 { "/recursive", SND_REC, 0 },
392 { "/rename-to", SND_REN, CM_ARG },
393 { "/text", SND_TXT, 0 },
394 { "/transparent", SND_XPA, 0 }
395 };
396 #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
397 static int nrcvtab = NRCVTAB;
398 #endif /* NOXFER */
399
400 /* WAIT table */
401
402 #define WAIT_FIL 997
403 #define WAIT_MDM 998
404
405 struct keytab waittab[] = {
406 { "cd", BM_DCD, CM_INV }, /* (Carrier Detect) */
407 { "cts", BM_CTS, CM_INV }, /* (Clear To Send) */
408 { "dsr", BM_DSR, CM_INV }, /* (Data Set Ready) */
409 { "file", WAIT_FIL, 0 }, /* New category selector keywords */
410 { "modem-signals", WAIT_MDM, 0 }, /* ... */
411 { "ri", BM_RNG, CM_INV } /* (Ring Indicator) */
412 };
413 int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
414
415 /* Modem signal table */
416
417 struct keytab mstab[] = {
418 { "cd", BM_DCD, 0 }, /* Carrier Detect */
419 { "cts", BM_CTS, 0 }, /* Clear To Send */
420 { "dsr", BM_DSR, 0 }, /* Data Set Ready */
421 { "ri", BM_RNG, 0 } /* Ring Indicator */
422 };
423 int nms = (sizeof(mstab) / sizeof(struct keytab));
424
425 #define WF_MOD 1
426 #define WF_DEL 2
427 #define WF_CRE 3
428
429 struct keytab wfswi[] = { /* WAIT FILE switches */
430 { "creation", WF_CRE, 0 }, /* Wait for file to be created */
431 { "deletion", WF_DEL, 0 }, /* Wait for file to be deleted */
432 { "modification", WF_MOD, 0 } /* Wait for file to be modified */
433 };
434 int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
435
436 #ifndef NOSPL
437 struct keytab asgtab[] = { /* Assignment operators for "." */
438 { "::=", 2, 0 }, /* ASSIGN and EVALUATE */
439 { ":=", 1, 0 }, /* ASSIGN */
440 { "=", 0, 0 } /* DEFINE */
441 };
442 int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
443
444 struct keytab opntab[] = {
445 #ifndef NOPUSH
446 { "!read", OPN_PI_R, CM_INV },
447 { "!write", OPN_PI_W, CM_INV },
448 #endif /* NOPUSH */
449 { "append", OPN_FI_A, 0 },
450 { "host", OPN_NET, 0 },
451 #ifdef OS2
452 { "line", OPN_SER, CM_INV },
453 { "port", OPN_SER, 0 },
454 #else
455 { "line", OPN_SER, 0 },
456 { "port", OPN_SER, CM_INV },
457 #endif /* OS2 */
458 { "read", OPN_FI_R, 0 },
459 { "write", OPN_FI_W, 0 }
460 };
461 int nopn = (sizeof(opntab) / sizeof(struct keytab));
462
463 /* IF conditions */
464
465 #define XXIFCO 0 /* IF COUNT */
466 #define XXIFER 1 /* IF ERRORLEVEL */
467 #define XXIFEX 2 /* IF EXIST */
468 #define XXIFFA 3 /* IF FAILURE */
469 #define XXIFSU 4 /* IF SUCCESS */
470 #define XXIFNO 5 /* IF NOT */
471 #define XXIFDE 6 /* IF DEFINED */
472 #define XXIFEQ 7 /* IF EQUAL (strings) */
473 #define XXIFAE 8 /* IF = (numbers) */
474 #define XXIFLT 9 /* IF < (numbers) */
475 #define XXIFGT 10 /* IF > (numbers) */
476 #define XXIFLL 11 /* IF Lexically Less Than (strings) */
477 #define XXIFLG 12 /* IF Lexically Greater Than (strings) */
478 #define XXIFEO 13 /* IF EOF (READ file) */
479 #define XXIFBG 14 /* IF BACKGROUND */
480 #define XXIFNU 15 /* IF NUMERIC */
481 #define XXIFFG 16 /* IF FOREGROUND */
482 #define XXIFDI 17 /* IF DIRECTORY */
483 #define XXIFNE 18 /* IF NEWER */
484 #define XXIFRO 19 /* IF REMOTE-ONLY */
485 #define XXIFAL 20 /* IF ALARM */
486 #define XXIFSD 21 /* IF STARTED-FROM-DIALER */
487 #define XXIFTR 22 /* IF TRUE */
488 #define XXIFNT 23 /* IF FALSE */
489 #define XXIFTM 24 /* IF TERMINAL-MACRO */
490 #define XXIFEM 25 /* IF EMULATION */
491 #define XXIFOP 26 /* IF OPEN */
492 #define XXIFLE 27 /* IF <= */
493 #define XXIFGE 28 /* IF >= */
494 #define XXIFIP 29 /* IF INPATH */
495 #define XXIFTA 30 /* IF TAPI */
496 #define XXIFMA 31 /* IF MATCH */
497 #define XXIFFL 32 /* IF FLAG */
498 #define XXIFAB 33 /* IF ABSOLUTE */
499 #define XXIFAV 34 /* IF AVAILABLE */
500 #define XXIFAT 35 /* IF ASKTIMEOUT */
501 #define XXIFRD 36 /* IF READABLE */
502 #define XXIFWR 37 /* IF WRITEABLE */
503 #define XXIFAN 38 /* IF ... AND ... */
504 #define XXIFOR 39 /* IF ... OR ... */
505 #define XXIFLP 40 /* IF left parenthesis */
506 #define XXIFRP 41 /* IF right parenthesis */
507 #define XXIFNQ 42 /* IF != (== "NOT =") */
508 #define XXIFQU 43 /* IF QUIET */
509 #define XXIFCK 44 /* IF C-KERMIT */
510 #define XXIFK9 45 /* IF K-95 */
511 #define XXIFMS 46 /* IF MS-KERMIT */
512 #define XXIFWI 47 /* IF WILD */
513 #define XXIFLO 48 /* IF LOCAL */
514 #define XXIFCM 49 /* IF COMMAND */
515 #define XXIFFP 50 /* IF FLOAT */
516 #define XXIFIK 51 /* IF IKS */
517 #define XXIFKB 52 /* IF KBHIT */
518 #define XXIFKG 53 /* IF KERBANG */
519 #define XXIFVE 54 /* IF VERSION */
520 #define XXIFDC 55 /* IF DECLARED */
521 #define XXIFGU 56 /* IF GUI */
522 #define XXIFLN 57 /* IF LINK */
523 #define XXIFDB 58 /* IF DEBUG */
524 #define XXIFFU 59 /* IF FUNCTION */
525 #define XXIFNN 60 /* IF NEQ (lexically not equal) */
526 #define XXIFLLE 61 /* IF LLE (lexically less than or equal) */
527 #define XXIFLGE 62 /* IF LLE (lexically less than or equal) */
528 #define XXIFTXT 63 /* IF TEXT (file) */
529 #define XXIFBIN 64 /* IF BINARY (file) */
530
531 struct keytab iftab[] = { /* IF commands */
532 { "!", XXIFNO, 0 },
533 { "!=", XXIFNQ, 0 },
534 { "&&", XXIFAN, 0 },
535 { "(", XXIFLP, 0 },
536 { ")", XXIFRP, 0 },
537 { "<", XXIFLT, 0 },
538 { "<=", XXIFLE, 0 },
539 { "=", XXIFAE, 0 },
540 { "==", XXIFAE, CM_INV },
541 { ">", XXIFGT, 0 },
542 { ">=", XXIFGE, 0 },
543 { "absolute", XXIFAB, 0 },
544 { "alarm", XXIFAL, 0 },
545 { "and", XXIFAN, 0 },
546 { "asktimeout", XXIFAT, 0 },
547 { "available", XXIFAV, 0 },
548 { "background", XXIFBG, 0 },
549 { "binary", XXIFBIN,0 },
550 { "c-kermit", XXIFCK, 0 },
551 { "command", XXIFCM, 0 },
552 { "count", XXIFCO, 0 },
553 { "dcl", XXIFDC, CM_INV },
554 { "debug", XXIFDB, 0 },
555 { "declared", XXIFDC, 0 },
556 { "defined", XXIFDE, 0 },
557 #ifdef CK_TMPDIR
558 { "directory", XXIFDI, 0 },
559 #endif /* CK_TMPDIR */
560 { "emulation", XXIFEM, 0 },
561 #ifdef COMMENT
562 { "eof", XXIFEO, 0 },
563 #endif /* COMMENT */
564 { "equal", XXIFEQ, 0 },
565 { "error", XXIFFA, CM_INV },
566 { "exist", XXIFEX, 0 },
567 { "failure", XXIFFA, 0 },
568 { "false", XXIFNT, 0 },
569 { "flag", XXIFFL, 0 },
570 #ifdef CKFLOAT
571 { "float", XXIFFP, 0 },
572 #endif /* CKFLOAT */
573 { "foreground", XXIFFG, 0 },
574 { "function", XXIFFU, 0 },
575 #ifdef OS2
576 { "gui", XXIFGU, 0 },
577 #else
578 { "gui", XXIFGU, CM_INV },
579 #endif /* OS2 */
580 #ifdef IKSD
581 { "iksd", XXIFIK, 0 },
582 #else
583 { "iksd", XXIFIK, CM_INV },
584 #endif /* IKSD */
585 { "integer", XXIFNU, CM_INV },
586 { "k-95", XXIFK9, CM_INV },
587 { "kbhit", XXIFKB, 0 },
588 #ifdef UNIX
589 { "kerbang", XXIFKG, 0 },
590 #else
591 { "kerbang", XXIFKG, CM_INV },
592 #endif /* UNIX */
593 { "lge", XXIFLGE,0 },
594 { "lgt", XXIFLG, 0 },
595 #ifdef UNIX
596 { "link", XXIFLN, 0 },
597 #endif /* UNIX */
598 { "lle", XXIFLLE,0 },
599 { "llt", XXIFLL, 0 },
600 { "local", XXIFLO, 0 },
601 { "match", XXIFMA, 0 },
602 { "ms-kermit", XXIFMS, CM_INV },
603 { "neq", XXIFNN, 0 },
604 #ifdef ZFCDAT
605 { "newer", XXIFNE, 0 },
606 #endif /* ZFCDAT */
607 { "not", XXIFNO, 0 },
608 { "numeric", XXIFNU, 0 },
609 /* { "ok", XXIFSU, CM_INV }, */
610 { "open", XXIFOP, 0 },
611 { "or", XXIFOR, 0 },
612 { "quiet", XXIFQU, 0 },
613 { "readable", XXIFRD, 0 },
614 { "remote-only",XXIFRO, 0 },
615 { "started-from-dialer",XXIFSD, CM_INV },
616 { "success", XXIFSU, 0 },
617 { "tapi", XXIFTA, 0 },
618 #ifdef OS2
619 { "terminal-macro", XXIFTM, 0 },
620 #else
621 { "terminal-macro", XXIFTM, CM_INV },
622 #endif /* OS2 */
623 { "text", XXIFTXT,0 },
624 { "true", XXIFTR, 0 },
625 { "version", XXIFVE, 0 },
626 { "wild", XXIFWI, 0 },
627 { "windows", XXIFK9, 0 },
628 { "writeable", XXIFWR, 0 },
629 { "||", XXIFOR, 0 },
630 { "", 0, 0 }
631 };
632 int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
633
634 struct keytab iotab[] = { /* Keywords for IF OPEN */
635 { "!read-file", ZRFILE, CM_INV },
636 { "!write-file", ZWFILE, CM_INV },
637 { "append-file", ZWFILE, CM_INV },
638 { "connection", 8888, 0 },
639 #ifdef CKLOGDIAL
640 { "cx-log", 7777, 0 },
641 #endif /* CKLOGDIAL */
642 { "debug-log", ZDFILE, 0 },
643 { "error", 9999, 0 },
644 { "packet-log", ZPFILE, 0 },
645 { "read-file", ZRFILE, 0 },
646 { "screen", ZSTDIO, 0 },
647 { "session-log", ZSFILE, 0 },
648 { "transaction-log", ZTFILE, 0 },
649 { "write-file", ZWFILE, 0 }
650 };
651 int niot = (sizeof(iotab) / sizeof(struct keytab));
652 #endif /* NOSPL */
653
654 /* Variables and prototypes */
655
656 _PROTOTYP(static int doymdir,(int));
657 _PROTOTYP(static int renameone,(char *,char *,
658 int,int,int,int,int,int,int,int,int,int,int));
659
660 #ifdef NETCONN
661 extern int nnetdir; /* How many network directories */
662 #endif /* NETCONN */
663 #ifdef CK_SECURITY
664 _PROTOTYP(int ck_krb4_is_installed,(void));
665 _PROTOTYP(int ck_krb5_is_installed,(void));
666 _PROTOTYP(int ck_ntlm_is_installed,(void));
667 _PROTOTYP(int ck_srp_is_installed,(void));
668 _PROTOTYP(int ck_ssleay_is_installed,(void));
669 _PROTOTYP(int ck_ssh_is_installed,(void));
670 _PROTOTYP(int ck_crypt_is_installed,(void));
671 #else
672 #define ck_krb4_is_installed() (0)
673 #define ck_krb5_is_installed() (0)
674 #define ck_ntlm_is_installed() (0)
675 #define ck_srp_is_installed() (0)
676 #define ck_ssleay_is_installed() (0)
677 #define ck_ssh_is_installed() (0)
678 #define ck_crypt_is_installed() (0)
679 #endif /* CK_SECURITY */
680
681 #define AV_KRB4 1
682 #define AV_KRB5 2
683 #define AV_NTLM 3
684 #define AV_SRP 4
685 #define AV_SSL 5
686 #define AV_CRYPTO 6
687 #define AV_SSH 7
688
689 struct keytab availtab[] = { /* Available authentication types */
690 { "crypto", AV_CRYPTO, CM_INV }, /* and encryption */
691 { "encryption", AV_CRYPTO, 0 },
692 { "k4", AV_KRB4, CM_INV },
693 { "k5", AV_KRB5, CM_INV },
694 { "kerberos4", AV_KRB4, 0 },
695 { "kerberos5", AV_KRB5, 0 },
696 { "krb4", AV_KRB4, CM_INV },
697 { "krb5", AV_KRB5, CM_INV },
698 { "ntlm", AV_NTLM, 0 },
699 { "srp", AV_SRP, 0 },
700 { "ssh", AV_SSH, 0 },
701 { "ssl", AV_SSL, 0 },
702 { "tls", AV_SSL, 0 },
703 { "", 0, 0 }
704 };
705 int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
706
707 #ifndef NODIAL
708 _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
709 _PROTOTYP(static int dncvt, (int, int, int, int) );
710 _PROTOTYP(char * getdname, (void) );
711
712 static int partial = 0; /* For partial dial */
713 static char *dscopy = NULL;
714 int dialtype = -1;
715
716 char *dialnum = (char *)0; /* Remember DIAL number for REDIAL */
717 int dirline = 0; /* Dial directory line number */
718 extern char * dialdir[]; /* Dial directory file names */
719 extern int dialdpy; /* DIAL DISPLAY on/off */
720 extern int ndialdir; /* How many dial directories */
721 extern int ntollfree; /* Toll-free call info */
722 extern int ndialpxx; /* List of PBX exchanges */
723 extern char *dialtfc[];
724 char * matchpxx = NULL; /* PBX exchange that matched */
725 extern int nlocalac; /* Local area-code list */
726 extern char * diallcac[];
727 extern int tttapi;
728 #ifdef CK_TAPI
729 extern int tapiconv; /* TAPI Conversions */
730 extern int tapipass; /* TAPI Passthrough */
731 #endif /* CK_TAPI */
732 extern int dialatmo;
733 extern char * dialnpr, * dialsfx;
734 extern char * dialixp, * dialixs, * dialmac;
735 extern char * dialldp, * diallds, * dialtfp;
736 extern char * dialpxi, * dialpxo, * diallac;
737 extern char * diallcp, * diallcs, * diallcc;
738 extern char * dialpxx[];
739
740 extern int dialcnf; /* DIAL CONFIRMATION */
741 int dialfld = 0; /* DIAL FORCE-LONG-DISTANCE */
742 int dialsrt = 1; /* DIAL SORT ON */
743 int dialrstr = 6; /* DIAL RESTRICTION */
744 int dialtest = 0; /* DIAL TEST */
745 int dialcount = 0; /* \v(dialcount) */
746
747 extern int dialsta; /* Dial status */
748 int dialrtr = -1, /* Dial retries */
749 dialint = 10; /* Dial retry interval */
750 extern long dialcapas; /* Modem capabilities */
751 extern int dialcvt; /* DIAL CONVERT-DIRECTORY */
752 #endif /* NODIAL */
753
754 #ifndef NOSPL
755 #define IFCONDLEN 256
756 int ifc, /* IF case */
757 not = 0, /* Flag for IF NOT */
758 ifargs = 0; /* Count of IF condition words */
759 char ifcond[IFCONDLEN]; /* IF condition text */
760 char *ifcp; /* Pointer to IF condition text */
761 extern int vareval;
762 #ifdef DCMDBUF
763 extern int
764 *ifcmd, *count, *iftest, *intime,
765 *inpcas, *takerr, *merror, *xquiet, *xvarev;
766 #else
767 extern int ifcmd[]; /* Last command was IF */
768 extern int iftest[]; /* Last IF was true */
769 extern int count[]; /* For IF COUNT, one for each cmdlvl */
770 extern int intime[]; /* Ditto for other stackables... */
771 extern int inpcas[];
772 extern int takerr[];
773 extern int merror[];
774 extern int xquiet[];
775 extern int xvarev[];
776 #endif /* DCMDBUF */
777 #else
778 extern int takerr[];
779 #endif /* NOSPL */
780
781 #ifdef DCMDBUF
782 extern char *line; /* Character buffer for anything */
783 extern char *tmpbuf;
784 #else
785 extern char line[], tmpbuf[];
786 #endif /* DCMDBUF */
787 extern char *lp; /* Pointer to line buffer */
788
789 int cwdf = 0; /* CWD has been done */
790
791 /* Flags for ENABLE/DISABLE */
792 extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
793 en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
794 en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
795
796 extern FILE *tfile[]; /* File pointers for TAKE command */
797 extern char *tfnam[]; /* Names of TAKE files */
798 extern int tfline[]; /* TAKE-file line number */
799
800 extern int success; /* Command success/failure flag */
801 extern int cmdlvl; /* Current position in command stack */
802
803 #ifndef NOSPL
804 extern int maclvl; /* Macro to execute */
805 extern char *macx[]; /* Index of current macro */
806 extern char *mrval[]; /* Macro return value */
807 extern char *macp[]; /* Pointer to macro */
808 extern int macargc[]; /* ARGC from macro invocation */
809
810 #ifdef COMMENT
811 extern char *m_line[];
812 #endif /* COMMENT */
813
814 extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */
815 extern char *g_var[]; /* Global variables %a, %b, etc */
816
817 #ifdef DCMDBUF
818 extern struct cmdptr *cmdstk; /* The command stack itself */
819 #else
820 extern struct cmdptr cmdstk[]; /* The command stack itself */
821 #endif /* DCMDBUF */
822 #endif /* NOSPL */
823
824 #define xsystem(s) zsyscmd(s)
825
826 static int x, y, z = 0;
827 static char *s, *p;
828
829 #ifdef OS2
830 _PROTOTYP( int os2settitle, (char *, int) );
831 #endif /* OS2 */
832
833 extern struct keytab yesno[], onoff[], fntab[];
834 extern int nyesno, nfntab;
835
836 #ifndef NOSPL
837
838 /* Do the ASK, ASKQ, GETOK, and READ commands */
839
840 int asktimedout = 0;
841
842 #define ASK_PUP 1
843 #define ASK_TMO 2
844 #define ASK_GUI 3
845 #define ASK_QUI 4
846 #define ASK_DEF 5
847 #define ASK_ECH 6
848
849 #define GETC_CHK 1
850 #define GETC_TMO 2
851 #define GETC_QUI 3
852
853 static struct keytab asktab[] = {
854 { "/default", ASK_DEF, CM_ARG },
855 { "/gui", ASK_GUI,
856 #ifdef KUI
857 0
858 #else /* KUI */
859 CM_INV
860 #endif /* KUI */
861 },
862 { "/popup", ASK_PUP,
863 #ifdef OS2
864 0
865 #else /* OS2 */
866 CM_INV
867 #endif /* OS2 */
868 },
869 { "/quiet", ASK_QUI, 0 },
870 { "/timeout", ASK_TMO, CM_ARG },
871 { "", 0, 0 }
872 };
873 static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1;
874
875 static struct keytab askqtab[] = {
876 { "/default", ASK_DEF, CM_ARG },
877 { "/echo", ASK_ECH, CM_ARG },
878 { "/gui", ASK_GUI,
879 #ifdef KUI
880 0
881 #else /* KUI */
882 CM_INV
883 #endif /* KUI */
884 },
885 { "/noecho", ASK_QUI, CM_INV },
886 { "/popup", ASK_PUP,
887 #ifdef OS2
888 0
889 #else /* OS2 */
890 CM_INV
891 #endif /* OS2 */
892 },
893 { "/quiet", ASK_QUI, 0 },
894 { "/timeout", ASK_TMO, CM_ARG },
895 { "", 0, 0 }
896 };
897 static int naskqtab = sizeof(askqtab)/sizeof(struct keytab)-1;
898
899 static struct keytab getctab[] = {
900 { "/check", GETC_CHK, 0 },
901 { "/quiet", GETC_QUI, 0 },
902 { "/timeout", GETC_TMO, CM_ARG },
903 { "", 0, 0 }
904 };
905 static int ngetctab = sizeof(getctab)/sizeof(struct keytab)-1;
906
907 int
doask(cx)908 doask(cx) int cx; {
909 extern int asktimer, timelimit;
910 #ifdef CK_RECALL
911 extern int on_recall;
912 #endif /* CK_RECALL */
913 int echochar = 0;
914 int popupflg = 0;
915 int guiflg = 0;
916 int nomsg = 0;
917 int mytimer = 0;
918 int peek = 0;
919 #ifdef CK_APC
920 extern int apcactive, apcstatus;
921 #endif /* CK_APC */
922
923 char dfbuf[1024]; /* Buffer for default answer */
924 char * dfanswer = NULL; /* Pointer to it */
925
926 char vnambuf[VNAML+1]; /* Buffer for variable names */
927 char *vnp = NULL; /* Pointer to same */
928
929 dfbuf[0] = NUL;
930 vnambuf[0] = NUL;
931
932 #ifdef CK_APC
933 if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
934 return(success = 0);
935 }
936 #endif /* CK_APC */
937
938 mytimer = asktimer; /* Inherit global ASK timer */
939 echostars = 0; /* For ASKQ */
940
941 if (cx == XXASK || cx == XXASKQ) {
942 struct FDB sw, fl;
943 int getval;
944 char c;
945 if (cx == XXASKQ) /* Don't log ASKQ response */
946 debok = 0;
947 cmfdbi(&sw, /* First FDB - command switches */
948 _CMKEY, /* fcode */
949 "Variable name or switch",
950 "", /* default */
951 "", /* addtl string data */
952 ((cx == XXASK) ? nasktab : naskqtab), /* Table size */
953 4, /* addtl numeric data 2: 4 = cmswi */
954 xxstring, /* Processing function */
955 ((cx == XXASK) ? asktab : askqtab), /* Keyword table */
956 &fl /* Pointer to next FDB */
957 );
958 cmfdbi(&fl, /* Anything that doesn't match */
959 _CMFLD, /* fcode */
960 "", /* hlpmsg */
961 "", /* default */
962 "", /* addtl string data */
963 0, /* addtl numeric data 1 */
964 0, /* addtl numeric data 2 */
965 NULL,
966 NULL,
967 NULL
968 );
969 while (1) { /* Parse 0 or more switches */
970 x = cmfdb(&sw); /* Parse something */
971 if (x < 0)
972 return(x);
973 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
974 break;
975 c = cmgbrk();
976 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
977 printf("?This switch does not take an argument\n");
978 return(-9);
979 }
980 if (!getval && (cmgkwflgs() & CM_ARG)) {
981 printf("?This switch requires an argument\n");
982 return(-9);
983 }
984 switch (cmresult.nresult) {
985 case ASK_QUI:
986 nomsg = 1;
987 if (cx == XXASKQ)
988 echostars = 0;
989 break;
990 case ASK_PUP:
991 popupflg = 1;
992 break;
993 case ASK_GUI:
994 guiflg = 1;
995 break;
996 case ASK_TMO: {
997 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
998 return(y);
999 if (x < 0)
1000 x = 0;
1001 mytimer = x;
1002 break;
1003 }
1004 case ASK_ECH: {
1005 if ((y = cmfld("Character to echo","*",&s,xxstring)) < 0)
1006 return(y);
1007 echochar = *s;
1008 break;
1009 }
1010 case ASK_DEF: {
1011 if ((y = cmfld("Text to supply if reply is empty",
1012 "",&s,xxstring)) < 0)
1013 return(y);
1014 ckstrncpy(dfbuf,s,1024);
1015 dfanswer = dfbuf;
1016 break;
1017 }
1018 default: return(-2);
1019 }
1020 }
1021 /* Have variable name, make copy. */
1022 ckstrncpy(vnambuf,cmresult.sresult,VNAML);
1023 vnp = vnambuf;
1024 if (vnambuf[0] == CMDQ &&
1025 (vnambuf[1] == '%' || vnambuf[1] == '&'))
1026 vnp++;
1027 y = 0;
1028 if (*vnp == '%' || *vnp == '&') {
1029 if ((y = parsevar(vnp,&x,&z)) < 0)
1030 return(y);
1031 }
1032 } else if (cx == XXGETC) { /* GETC */
1033 struct FDB sw, fl;
1034 int getval;
1035 char c;
1036 cmfdbi(&sw, /* First FDB - command switches */
1037 _CMKEY, /* fcode */
1038 "Variable name or switch",
1039 "", /* default */
1040 "", /* addtl string data */
1041 ngetctab, /* Table size */
1042 4, /* addtl numeric data 2: 4 = cmswi */
1043 xxstring, /* Processing function */
1044 getctab, /* Keyword table */
1045 &fl /* Pointer to next FDB */
1046 );
1047 cmfdbi(&fl, /* Anything that doesn't match */
1048 _CMFLD, /* fcode */
1049 "", /* hlpmsg */
1050 "", /* default */
1051 "", /* addtl string data */
1052 0, /* addtl numeric data 1 */
1053 0, /* addtl numeric data 2 */
1054 NULL,
1055 NULL,
1056 NULL
1057 );
1058 while (1 && !peek) { /* Parse 0 or more switches */
1059 x = cmfdb(&sw); /* Parse something */
1060 if (x < 0)
1061 return(x);
1062 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
1063 break;
1064 c = cmgbrk();
1065 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1066 printf("?This switch does not take an argument\n");
1067 return(-9);
1068 }
1069 if (!getval && (cmgkwflgs() & CM_ARG)) {
1070 printf("?This switch requires an argument\n");
1071 return(-9);
1072 }
1073 switch (cmresult.nresult) {
1074 case GETC_CHK: /* GETC /CHECK */
1075 peek = 1;
1076 break;
1077 case GETC_QUI: /* GETC /QUIET */
1078 nomsg = 1;
1079 break;
1080 case GETC_TMO: { /* GETC /TIMEOUT:sec */
1081 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
1082 return(y);
1083 if (x < 0)
1084 x = 0;
1085 mytimer = x;
1086 break;
1087 }
1088 default: return(-2);
1089 }
1090 }
1091 if (peek) { /* GETC /CHECK */
1092 /*
1093 This was intended to mean "check how many characters are waiting to be
1094 read from standard input". Conchk() was supposed to do that but it
1095 doesn't when stdin is redirected. The best I can do is ask isatty(0)
1096 whether stdin is a terminal. If not we'll assume it's redirected stdin.
1097 Btw, even if stdin really is a terminal conchk() returns 0, even if
1098 there is typeahead. - fdc, 21 Apr 2017.
1099 */
1100 int itsatty = -1;
1101 if ((y = cmcfm()) < 0) /* Get confirmation */
1102 return(y);
1103 itsatty = isatty(0); /* Is stdin a tty? */
1104 debug(F101,"GETC peek","",peek);
1105 debug(F101,"GETC itsatty","",itsatty);
1106 return(success = (itsatty > 0) ? 0 : 1);
1107 }
1108
1109 /* Regular GETC... Have variable name, make copy. */
1110 ckstrncpy(vnambuf,cmresult.sresult,VNAML);
1111 vnp = vnambuf;
1112 if (vnambuf[0] == CMDQ &&
1113 (vnambuf[1] == '%' || vnambuf[1] == '&'))
1114 vnp++;
1115 y = 0;
1116 if (*vnp == '%' || *vnp == '&') {
1117 if ((y = parsevar(vnp,&x,&z)) < 0)
1118 return(y);
1119 }
1120 } else if (cx != XXGOK && cx != XXRDBL && !peek) { /* Get variable name */
1121 if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
1122 if (y == -3) {
1123 printf("?Variable name required\n");
1124 return(-9);
1125 } else return(y);
1126 }
1127 ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */
1128 vnp = vnambuf;
1129 if (vnambuf[0] == CMDQ &&
1130 (vnambuf[1] == '%' || vnambuf[1] == '&'))
1131 vnp++;
1132 y = 0;
1133 if (*vnp == '%' || *vnp == '&') {
1134 if ((y = parsevar(vnp,&x,&z)) < 0)
1135 return(y);
1136 }
1137 }
1138 if (cx == XXREA || cx == XXRDBL) { /* READ or READBLOCK command */
1139 if ((y = cmcfm()) < 0) /* Get confirmation */
1140 return(y);
1141 if (chkfn(ZRFILE) < 1) { /* File open? */
1142 printf("?Read file not open\n");
1143 return(success = 0);
1144 }
1145 if (!(s = (char *)readbuf)) { /* Where to read into. */
1146 printf("?Oops, no READ buffer!\n");
1147 return(success = 0);
1148 }
1149 y = zsinl(ZRFILE, s, readblock); /* Read a line. */
1150 debug(F111,"read zsinl",s,y);
1151 if (y < 0) { /* On EOF or other error, */
1152 zclose(ZRFILE); /* close the file, */
1153 delmac(vnp,0); /* delete the variable, */
1154 return(success = 0); /* and return failure. */
1155 } else { /* Read was OK. */
1156 readsize = (int) strlen(s);
1157 success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
1158 debug(F111,"read addmac",vnp,success);
1159 return(success); /* Return success. */
1160 }
1161 }
1162
1163 /* ASK, ASKQ, GETOK */
1164
1165 if (cx == XXGOK) { /* GETOK can take switches */
1166 struct FDB sw, fl;
1167 int getval;
1168 char c;
1169 cmfdbi(&sw, /* First FDB - command switches */
1170 _CMKEY, /* fcode */
1171 "Variable name or question prompt",
1172 "", /* default */
1173 "", /* addtl string data */
1174 nasktab, /* addtl numeric data 1: tbl size */
1175 4, /* addtl numeric data 2: 4 = cmswi */
1176 xxstring, /* Processing function */
1177 asktab, /* Keyword table */
1178 &fl /* Pointer to next FDB */
1179 );
1180 cmfdbi(&fl, /* Anything that doesn't match */
1181 _CMTXT, /* fcode */
1182 "", /* hlpmsg */
1183 "", /* default */
1184 "", /* addtl string data */
1185 0, /* addtl numeric data 1 */
1186 0, /* addtl numeric data 2 */
1187 NULL,
1188 NULL,
1189 NULL
1190 );
1191 while (1) { /* Parse 0 or more switches */
1192 x = cmfdb(&sw); /* Parse something */
1193 if (x < 0)
1194 return(x);
1195 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
1196 break;
1197 c = cmgbrk();
1198 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1199 printf("?This switch does not take an argument\n");
1200 return(-9);
1201 }
1202 if (!getval && (cmgkwflgs() & CM_ARG)) {
1203 printf("?This switch requires an argument\n");
1204 return(-9);
1205 }
1206 switch (cmresult.nresult) {
1207 case ASK_PUP:
1208 popupflg = 1;
1209 break;
1210 case ASK_GUI:
1211 guiflg = 1;
1212 break;
1213 case ASK_TMO: {
1214 if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
1215 return(y);
1216 if (x < 0)
1217 x = 0;
1218 mytimer = x;
1219 break;
1220 }
1221 case ASK_DEF: {
1222 if ((y = cmfld("Text to supply if reply is empty",
1223 "",&s,xxstring)) < 0)
1224 return(y);
1225 ckstrncpy(dfbuf,s,1024);
1226 dfanswer = dfbuf;
1227 break;
1228 }
1229 case ASK_QUI:
1230 nomsg = 1;
1231 break;
1232 default: return(-2);
1233 }
1234 }
1235 p = cmresult.sresult;
1236 } else
1237 if ((y = cmtxt(
1238 "Prompt,\n\
1239 enclose in { braces } or \" quotes \" to preserve leading and trailing\n\
1240 spaces, precede question mark with backslash (\\).",
1241 "",&p,xxstring)) < 0)
1242 return(y);
1243
1244 if (!p) p = "";
1245 #ifndef NOLOCAL
1246 #ifdef OS2
1247 if (popupflg) { /* Popup requested */
1248 int len = -1;
1249 ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
1250 p = tmpbuf;
1251 if (cx == XXASK || cx == XXASKQ) {
1252 if (cx == XXASK)
1253 len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1254 else
1255 len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1256 asktimedout = ( len < 0 && mytimer );
1257 } else if (cx == XXGOK) {
1258 printf("?Sorry, GETOK /POPUP not implemented yet\n");
1259 timelimit = 0;
1260 return(-9);
1261 }
1262 if (len >= 0) {
1263 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1264 } else if ( asktimedout && dfanswer ) {
1265 y = addmac(vnp,dfanswer); /* Add it to the macro table. */
1266 asktimedout = 0;
1267 len = 0;
1268 }
1269 timelimit = 0;
1270 return(success = ((len >= 0) && (y >= 0)) && !asktimedout);
1271 }
1272 #ifdef KUI
1273 if (guiflg) { /* GUI requested */
1274 int rc, n;
1275 char * s1;
1276 s1 = tmpbuf;
1277 n = TMPBUFSIZ-1;
1278 zzstring(brstrip(p),&s1,&n);
1279 p = tmpbuf;
1280 if (cx == XXASK || cx == XXASKQ) {
1281 rc = gui_txt_dialog(NULL,p,(cx == XXASK),
1282 line,LINBUFSIZ,dfanswer,mytimer);
1283 asktimedout = (rc == -1 && mytimer);
1284 if (rc == 1) {
1285 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1286 } else if ( asktimedout && dfanswer ) {
1287 y = addmac(vnp,dfanswer); /* Add default to macro table. */
1288 asktimedout = 0;
1289 rc = 1;
1290 }
1291 timelimit = 0;
1292 return(success = (rc == 1 && (y >= 0)) && !asktimedout);
1293 } else if (cx == XXGOK) {
1294 int x;
1295 x = lookup(yesno,dfanswer,nyesno,NULL);
1296 if (x != 1) x = 2;
1297 rc = uq_ok(NULL, p, 3, NULL, x);
1298 return(success = (rc == 1));
1299 }
1300 }
1301 #endif /* KUI */
1302 #endif /* OS2 */
1303 #endif /* NOLOCAL */
1304
1305 concb((char)escape); /* Enter CBREAK mode */
1306 cmsavp(psave,PROMPTL); /* Save old prompt */
1307 cmsetp(brstrip(p)); /* Make new prompt */
1308
1309 reprompt:
1310 if (cx == XXASKQ) { /* For ASKQ, */
1311 cmini(0); /* no-echo mode. */
1312 if (echochar)
1313 echostars = echochar;
1314 } else { /* For others, regular echoing. */
1315 cmini(ckxech);
1316 echostars = 0;
1317 }
1318 askflag = 1;
1319 x = -1; /* This means to reparse. */
1320 cmflgs = 0;
1321 if (pflag)
1322 prompt(xxstring); /* Issue prompt. */
1323
1324 asktimedout = 0; /* Handle timed responses. */
1325 timelimit = mytimer;
1326 reparse:
1327 cmres();
1328 if (cx == XXGOK) { /* GETOK */
1329 #ifdef CK_RECALL
1330 on_recall = 0;
1331 #endif /* CK_RECALL */
1332 askflag = 0;
1333 /* GETOK uses keyword table */
1334 x = cmkey(yesno,nyesno,"",dfanswer,xxstring);
1335 if (x < 0) { /* Parse error */
1336 if (x == -10) {
1337 char * ds;
1338 ds = dfanswer ? dfanswer : "No";
1339 if (!nomsg)
1340 printf("?Timed out, assuming \"%s\"",ds);
1341 printf("\n");
1342 asktimedout = 1;
1343 x = lookup(yesno,ds,nyesno,NULL);
1344 if (x != 1) x = 0;
1345 goto gokdone;
1346 } else if (x == -3) { /* No answer? */
1347 printf("Please respond Yes or No\n"); /* Make them answer */
1348 cmini(ckxech);
1349 goto reprompt;
1350 } else if (x == -1) {
1351 goto reparse;
1352 } else
1353 goto reprompt;
1354 }
1355 if (cmcfm() < 0) /* Get confirmation */
1356 goto reparse;
1357 gokdone:
1358 askflag = 0;
1359 cmsetp(psave); /* Restore prompt */
1360 #ifdef VMS
1361 if (cmdlvl > 0) /* In VMS and not at top level, */
1362 conres(); /* restore console again. */
1363 #endif /* VMS */
1364 timelimit = 0;
1365 return(x); /* Return success or failure */
1366 } else if (cx == XXGETC /* GETC */
1367 #ifdef OS2
1368 || cx == XXGETK /* or GETKEYCODE */
1369 #endif /* OS2 */
1370 ) { /* GETC */
1371 char tmp[16];
1372 conbin((char)escape); /* Put keyboard in raw mode */
1373 #ifndef NOSETKEY
1374 #ifdef OS2
1375 if (cx == XXGETK) { /* GETKEYCODE */
1376 extern int os2gks;
1377 int t;
1378 t = os2gks; /* Turn off kverb recognition */
1379 os2gks = 0;
1380 x = congks(timelimit); /* Read a key event, blocking */
1381 os2gks = t; /* Put back kverb recognition */
1382 } else /* GETC */
1383 #endif /* OS2 */
1384 #endif /* NOSETKEY */
1385 {
1386 x = coninc(timelimit); /* Read one character */
1387 debug(F101,"GETC coninc","",x);
1388 }
1389 concb((char)escape); /* Put keyboard back in cbreak mode */
1390 if (x > -1) {
1391 if (xcmdsrc == 0)
1392 printf("\r\n");
1393 #ifdef OS2
1394 if (cx == XXGETK) { /* GETKEYCODE */
1395 sprintf(tmp,"%d",x); /* SAFE */
1396 } else {
1397 #endif /* OS2 */
1398 tmp[0] = (char) (x & 0xff);
1399 tmp[1] = NUL;
1400 #ifdef OS2
1401 }
1402 #endif /* OS2 */
1403 y = addmac(vnp,tmp); /* Add it to the macro table. */
1404 debug(F111,"getc/getk addmac",vnp,y);
1405 } else y = -1;
1406 cmsetp(psave); /* Restore old prompt. */
1407 if (x < -1) {
1408 asktimedout = 1;
1409 if (!quiet && !nomsg)
1410 printf("?Timed out");
1411 printf("\n");
1412 }
1413 timelimit = 0;
1414 return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0)));
1415 } else { /* ASK or ASKQ */
1416 #ifdef CK_RECALL
1417 on_recall = 0; /* Don't put response in recall buf */
1418 #endif /* CK_RECALL */
1419 askflag = 1; /* ASK[Q] always goes to terminal */
1420 y = cmdgquo(); /* Get current quoting */
1421 cmdsquo(0); /* Turn off quoting */
1422 while (x == -1) { /* Prompt till they answer */
1423 x = cmtxt("Please respond.",dfanswer,&s,NULL);
1424 debug(F111,"ASK cmtxt",s,x);
1425 cmres();
1426 }
1427 cmdsquo(y); /* Restore previous quoting */
1428 if (cx == XXASKQ) /* ASKQ must echo CRLF here */
1429 printf("\r\n");
1430 if (x == -10 && dfanswer) { /* Don't fail on timeout if */
1431 s = dfanswer; /* a default was specified */
1432 asktimedout = 0; /* and don't fail */
1433 x = 0;
1434 }
1435 if (x < 0) { /* If cmtxt parse error, */
1436 cmsetp(psave); /* restore original prompt */
1437 #ifdef VMS
1438 if (cmdlvl > 0) /* In VMS and not at top level, */
1439 conres(); /* restore console again. */
1440 #endif /* VMS */
1441 if (x == -10) { /* Timed out with no response */
1442 if (!nomsg)
1443 printf("?Timed out");
1444 printf("\n");
1445 asktimedout = 1;
1446 if (dfanswer) /* Supply default answer if any */
1447 s = dfanswer;
1448 success = x = 0; /* (was "x = -9;") */
1449 }
1450 timelimit = 0;
1451 return(x); /* and return cmtxt's error code. */
1452 }
1453 if (!s || *s == NUL) { /* If user typed a bare CR, */
1454 cmsetp(psave); /* Restore old prompt, */
1455 delmac(vnp,0); /* delete variable if it exists, */
1456 #ifdef VMS
1457 if (cmdlvl > 0) /* In VMS and not at top level, */
1458 conres(); /* restore console again. */
1459 #endif /* VMS */
1460 timelimit = 0;
1461 return(success = 1); /* and return. */
1462 }
1463 y = addmac(vnp,s); /* Add it to the macro table. */
1464 debug(F111,"ask addmac",vnp,y);
1465 cmsetp(psave); /* Restore old prompt. */
1466 #ifdef VMS
1467 if (cmdlvl > 0) /* In VMS and not at top level, */
1468 conres(); /* restore console again. */
1469 #endif /* VMS */
1470 timelimit = 0;
1471 return(success = (y < 0 ? 0 : 1) && (asktimedout == 0));
1472 }
1473 }
1474 #endif /* NOSPL */
1475
1476 #ifndef NOSPL
1477 int
doincr(cx)1478 doincr(cx) int cx; { /* INCREMENT, DECREMENT */
1479 char vnambuf[VNAML+1]; /* Buffer for variable names */
1480 int eval = 0;
1481 CK_OFF_T x;
1482 eval = (cx == XX_DECR || cx == XX_INCR);
1483
1484 if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
1485 if (y == -3) {
1486 printf("?Variable name required\n");
1487 return(-9);
1488 } else return(y);
1489 }
1490 ckstrncpy(vnambuf,s,VNAML);
1491 if ((y = cmnumw("by amount","1",10,&x,xxstring)) < 0)
1492 return(y);
1493 if ((y = cmcfm()) < 0)
1494 return(y);
1495
1496 z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */
1497
1498 if (incvar(vnambuf,x,z) < 0) {
1499 printf("?Variable %s not defined or not numeric\n",vnambuf);
1500 return(success = 0);
1501 }
1502 return(success = 1);
1503 }
1504
1505 /* Used by doundef() */
1506 static int
xxundef(s,verbose,simulate)1507 xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
1508 int rc = 0;
1509 if (!s) return(0);
1510 if (*s == CMDQ && *(s+1) == '%') {
1511 char c = *(s+2), * p = NULL;
1512 if (c >= '0' && c <= '9') {
1513 if (maclvl < 0)
1514 p = g_var[c];
1515 else
1516 p = m_arg[maclvl][c - '0'];
1517 } else {
1518 if (isupper(c)) c += ('a'-'A');
1519 if (c >= 'a' && c <= 'z')
1520 p = g_var[c];
1521 }
1522 if (!p) return(-1);
1523 }
1524 if (verbose)
1525 printf(" %s ",s);
1526 if (simulate) {
1527 printf("(SELECTED)\n");
1528 } else if ((x = delmac(s,1)) > -1) { /* Full name required */
1529 rc = 1;
1530 if (verbose) printf("(OK)\n");
1531 } else if (verbose)
1532 printf("(FAILED)\n");
1533 return(rc);
1534 }
1535
1536 /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
1537
1538 #define UND_MAT 1
1539 #define UND_VRB 2
1540 #define UND_EXC 3
1541 #define UND_SIM 3
1542
1543 static struct keytab undefswi[] = {
1544 { "/list", UND_VRB, 0 },
1545 #ifdef COMMENT
1546 { "/except", UND_EXC, CM_ARG },
1547 #endif /* COMMENT */
1548 { "/matching", UND_MAT, 0 },
1549 { "/simulate", UND_SIM, 0 },
1550 { "/verbose", UND_VRB, CM_INV }
1551 };
1552 static int nundefswi = sizeof(undefswi) / sizeof(struct keytab);
1553
1554 #define UNDEFMAX 64
1555 static char ** undeflist = NULL;
1556 int
doundef(cx)1557 doundef(cx) int cx; { /* UNDEF, _UNDEF */
1558 int i, j, n, rc = 0, arraymsg = 0;
1559 int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0;
1560 char *vnp, vnbuf[4];
1561 #ifdef COMMENT
1562 char *except = NULL;
1563 #endif /* COMMENT */
1564 struct FDB sw, fl;
1565 int getval;
1566 char c;
1567
1568 if (!undeflist) { /* Allocate list if necessary */
1569 undeflist = (char **)malloc(UNDEFMAX * sizeof(char *));
1570 if (!undeflist) {
1571 printf("?Memory allocation failure\n");
1572 return(-9);
1573 }
1574 for (i = 0; i < UNDEFMAX; i++)
1575 undeflist[i] = NULL;
1576 }
1577 cmfdbi(&sw, /* First FDB - command switches */
1578 _CMKEY, /* fcode */
1579 "Variable name or switch",
1580 "", /* default */
1581 "", /* addtl string data */
1582 nundefswi, /* addtl numeric data 1: tbl size */
1583 4, /* addtl numeric data 2: 4 = cmswi */
1584 xxstring, /* Processing function */
1585 undefswi, /* Keyword table */
1586 &fl /* Pointer to next FDB */
1587 );
1588 cmfdbi(&fl, /* Anything that doesn't match */
1589 _CMFLD, /* fcode */
1590 "", /* hlpmsg */
1591 "", /* default */
1592 "", /* addtl string data */
1593 0, /* addtl numeric data 1 */
1594 0, /* addtl numeric data 2 */
1595 (cx == XXUNDEF) ? NULL : xxstring,
1596 NULL,
1597 NULL
1598 );
1599 while (1) { /* Parse 0 or more switches */
1600 x = cmfdb(&sw); /* Parse something */
1601 if (x < 0)
1602 return(x);
1603 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
1604 break;
1605 c = cmgbrk();
1606 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1607 printf("?This switch does not take an argument\n");
1608 return(-9);
1609 }
1610 switch (cmresult.nresult) {
1611 case UND_MAT: domatch = 1; break;
1612 case UND_SIM: simulate = 1; /* fall thru on purpose */
1613 case UND_VRB: verbose = 1; break;
1614
1615 #ifdef COMMENT
1616 case UND_EXC:
1617 if (!getval) break;
1618 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
1619 if (x == -3) {
1620 printf("?Pattern required\n");
1621 x = -9;
1622 }
1623 goto xgetx;
1624 }
1625 makestr(&except,cmresult.sresult);
1626 break;
1627 #endif /* COMMENT */
1628
1629 default:
1630 return(-2);
1631 }
1632 }
1633 n = 0;
1634 makestr(&(undeflist[n++]),cmresult.sresult);
1635 for (i = 1; i < UNDEFMAX; i++) {
1636 x = cmfld("Macro or variable name","",&s,
1637 ((cx == XXUNDEF) ? NULL : xxstring)
1638 );
1639 if (x == -3) {
1640 if ((y = cmcfm()) < 0)
1641 return(y);
1642 break;
1643 } else if (y < 0) {
1644 return(y);
1645 }
1646 makestr(&(undeflist[n++]),s);
1647 }
1648 /* Now we have a list of n variables or patterns to undefine */
1649
1650 for (i = 0; i < n; i++) {
1651 flag = 0;
1652 if (!(vnp = undeflist[i]))
1653 continue;
1654 if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) {
1655 flag++;
1656 vnp++;
1657 }
1658 if (!domatch) { /* Pattern match not requested */
1659 if (flag) {
1660 if ((y = parsevar(vnp,&x,&z)) < 0) {
1661 vnp--;
1662 if (verbose) printf(" %s...error\n",vnp);
1663 continue;
1664 }
1665 vnp--;
1666 }
1667 x = xxundef(vnp,verbose,simulate);
1668 if (x > -1) {
1669 if (!x && !simulate) errors++;
1670 rc += x;
1671 }
1672 continue;
1673 }
1674 /* Pattern match requested */
1675
1676 if (!flag) { /* It's a macro */
1677 for (j = 0; j < nmac; j++) {
1678 if (ckmatch(vnp,mactab[j].kwd,0,1)) {
1679 x = xxundef(mactab[j].kwd,verbose,simulate);
1680 if (x > -1) {
1681 rc += x;
1682 if (!x) errors++;
1683 }
1684 if (!simulate)
1685 j--; /* Because mactab shifted up */
1686 }
1687 }
1688 } else if (vnp[0] == '%') { /* It's a \%x variable */
1689 vnbuf[0] = CMDQ;
1690 vnbuf[1] = '%';
1691 vnbuf[3] = NUL;
1692 for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */
1693 vnbuf[2] = j;
1694 if (ckmatch(vnp,&vnbuf[1],0,1)) {
1695 x = xxundef(vnbuf,verbose,simulate);
1696 if (x > -1) {
1697 if (!x) errors++;
1698 rc += x;
1699 }
1700 }
1701 if (j == '9') j = (int)'a' - 1; /* 9 -> a */
1702 }
1703 } else if (vnp[0] == '&') {
1704 if (!arraymsg && !quiet) {
1705 printf("?UNDEFINE /MATCH can't be used with arrays.\n");
1706 printf("(Type HELP ARRAY to see other methods.)\n");
1707 }
1708 arraymsg++;
1709 errors++;
1710 }
1711 }
1712 if (verbose)
1713 printf("undefined: %d, errors: %d\n",rc,errors);
1714
1715 for (i = 0; i < UNDEFMAX; i++) { /* Check them all */
1716 if (undeflist[i]) { /* in case we were interrupted */
1717 free(undeflist[i]); /* previously... */
1718 undeflist[i] = NULL;
1719 }
1720 }
1721 return(success = (errors == 0) ? 1 : 0);
1722 }
1723
1724 int
dodef(cx)1725 dodef(cx) int cx; {
1726 extern int xxdot;
1727 extern char ppvnambuf[];
1728 int doeval = 0;
1729 char vnambuf[VNAML+1]; /* Buffer for variable names */
1730 char *vnp; /* Pointer to same */
1731 int k, mydot;
1732 mydot = xxdot; /* Copy */
1733 xxdot = 0; /* and reset */
1734 /*
1735 In case we got here from a command that begins like ".\%a", cmkey() has
1736 already evaluated \%a, but we don't want that, so we retrieve the variable
1737 name from a special pre-evaluation buffer in the command module, and we
1738 undo the "unget word" that would be done because of the token, because if
1739 the variable was defined, it will unget its value rather than its name.
1740 */
1741 s = NULL;
1742
1743 if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
1744 s = ppvnambuf+1;
1745 unungw();
1746 }
1747 if (!s) {
1748 if (cx == XXDFX || cx == XXASX)
1749 /* Evaluate variable name */
1750 y = cmfld("Macro or variable name","",&s,xxstring);
1751 else
1752 /* Don't evaluate the variable name */
1753 y = cmfld("Macro or variable name","",&s,NULL);
1754 if (y < 0) {
1755 if (y == -3) {
1756 printf("?Variable name required\n");
1757 return(-9);
1758 } else return(y);
1759 }
1760 }
1761 k = strlen(s);
1762 if (k > VNAML) {
1763 printf("?Name too long: \"%s\"\n",s);
1764 return(-9);
1765 }
1766 ckstrncpy(vnambuf,s,VNAML);
1767 vnambuf[VNAML] = NUL;
1768 vnp = vnambuf;
1769 if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
1770 if (*vnp == '%' || *vnp == '&') {
1771 if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
1772 #ifdef COMMENT
1773 if (cx == XXUNDEF) { /* Undefine */
1774 if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1775 delmac(vnp,0);
1776 return(success = 1);
1777 }
1778 #endif /* COMMENT */
1779 debug(F101,"dodef parsevar x","",x);
1780 if (mydot) {
1781 if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1782 return(doeval);
1783 if (doeval > 0) /* Type of assignment */
1784 cx = XXASS;
1785 }
1786 if (y == 1) { /* Simple variable */
1787 if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
1788 return(y);
1789 s = brstrip(s);
1790 debug(F110,"xxdef var name",vnp,0);
1791 debug(F110,"xxdef var def",s,0);
1792 } else if (y == 2) { /* Array element */
1793 if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
1794 if (x == 96) {
1795 printf("?Argument vector array is read-only\n");
1796 return(-9);
1797 }
1798 if (chkarray(x,z) < 0) return(-2);
1799 if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
1800 return(y);
1801 debug(F110,"xxdef array ref",vnp,0);
1802 debug(F110,"xxdef array def",s,0);
1803 }
1804 } else { /* Macro */
1805 #ifdef COMMENT
1806 if (cx == XXUNDEF) { /* Undefine */
1807 if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1808 delmac(vnp,0);
1809 return(success = 1);
1810 }
1811 #endif /* COMMENT */
1812 if (mydot) {
1813 if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1814 return(doeval);
1815 if (doeval > 0)
1816 cx = XXASS;
1817 }
1818 if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
1819 #ifdef DEBUG
1820 if (deblog) {
1821 debug(F110,"xxdef macro name",vnp,0);
1822 debug(F010,"xxdef macro def",s,0);
1823 }
1824 #endif /* DEBUG */
1825 s = brstrip(s);
1826 }
1827 if (*s == NUL) { /* No arg given, undefine */
1828 delmac(vnp,1); /* silently... */
1829 return(success = 1); /* even if it doesn't exist... */
1830 }
1831 /* Defining a new macro or variable */
1832
1833 if (cx == XXASS || cx == XXASX) { /* ASSIGN rather than DEFINE? */
1834 int t;
1835 t = LINBUFSIZ-1;
1836 lp = line; /* If so, expand its value now */
1837 zzstring(s,&lp,&t);
1838 s = line;
1839 }
1840 if (doeval == 2) { /* Arithmetic evaluation wanted too? */
1841 ckstrncpy(line,evala(s),LINBUFSIZ);
1842 line[LINBUFSIZ] = NUL;
1843 }
1844 /* debug(F111,"calling addmac",s,(int)strlen(s)); */
1845
1846 y = addmac(vnp,s); /* Add it to the appropriate table. */
1847 if (y < 0) {
1848 printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
1849 "ASSIGN" : "DEFINE");
1850 return(success = 0);
1851 } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
1852 return(1); /* don't change success variable */
1853 else
1854 return(success = 1);
1855 }
1856 #endif /* NOSPL */
1857
1858
1859 #ifndef NODIAL
1860 /*
1861 L U D I A L -- Lookup up dialing directory entry.
1862
1863 Call with string to look up and file descriptor of open dialing directory
1864 file. On success, returns number of matches found, with numbers stored
1865 in an array accessible via getdnum().
1866 */
1867 static char *dn_p[MAXDNUMS + 1]; /* Dial Number pointers */
1868 static char *dn_p2[MAXDNUMS + 1]; /* Converted dial number pointers */
1869 static int dn_x[MAXDNUMS + 1]; /* Type of call */
1870 static int dncount = 0;
1871 char * d_name = NULL; /* Dial name pointer */
1872
1873 char * /* Get dial directory entry name */
getdname()1874 getdname() {
1875 return(d_name ? d_name : "");
1876 }
1877
1878 char *
getdnum(n)1879 getdnum(n) int n; { /* Get dial number n from directory */
1880 if (n < 0 || n > dncount || n > MAXDNUMS)
1881 return("");
1882 else
1883 return(dn_p[n]);
1884 }
1885
1886 char * /* Check area code for spurious leading digit */
chk_ac(i,buf)1887 chk_ac(i,buf) int i; char buf[]; {
1888 char *p;
1889 if (!buf)
1890 return("");
1891 p = (char *) buf; /* Country we are calling: */
1892 if (i == 44 || /* UK */
1893 i == 49 || /* Germany */
1894 i == 39 || /* Italy */
1895 i == 31 || /* Netherlands */
1896 i == 351 || /* Portugal */
1897 i == 55 || /* Brazil */
1898 i == 972 || /* Israel */
1899 i == 41 || /* Switzerland */
1900 i == 43 || /* Austria */
1901 i == 42 || /* Czech Republic */
1902 i == 36 || /* Hungary */
1903 i == 30 || /* Greece */
1904 i == 352 || /* Luxembourg */
1905 i == 48 || /* Poland */
1906 i == 27 || /* South Africa */
1907 i == 33 || /* France (as of 1997) */
1908 i == 358 /* Finland (ditto) */
1909 ) {
1910 if (buf[0] == '0')
1911 p++;
1912 }
1913 return(p);
1914 }
1915
1916 /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
1917 /*
1918 src = area code of caller
1919 dest = area code of callee
1920 Returns:
1921 0 if call is local
1922 1 if call is long distance
1923 2 if call is local but area code must be dialed anyway
1924 */
1925 static int
callisld(src,dest)1926 callisld(src, dest) char * src, * dest; {
1927 int i;
1928 if (dialfld) /* Force long distance? */
1929 return(1);
1930 if (!strcmp(src,dest)) { /* Area codes are the same */
1931 for (i = 0; i < nlocalac; i++) /* Is AC in the lc-area-codes list? */
1932 if (!strcmp(src,diallcac[i]))
1933 return(2); /* Yes so must be dialed */
1934 return(0); /* No so don't dial it. */
1935 }
1936 for (i = 0; i < nlocalac; i++) /* ACs not the same so look in list */
1937 if (!strcmp(dest,diallcac[i])) /* Match */
1938 return(2); /* So local call with area code */
1939 return(1); /* Not local so long-distance */
1940 }
1941
1942 char pdsfx[64] = { NUL, NUL };
1943
1944 #ifndef NOSPL
1945 static char *
xdial(s)1946 xdial(s) char *s; { /* Run dial string thru macro */
1947 int x, m;
1948 char * s2;
1949 s2 = NULL;
1950 makestr(&s2,s); /* Copy the argument */
1951 if (!dialmac) /* Dial macro name given? */
1952 return(NULL);
1953 if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
1954 return(NULL);
1955 m = maclvl;
1956 x = dodo(x,s2,0); /* Set up the macro */
1957 if (s2) free(s2);
1958 if (x > 0) {
1959 while (maclvl > m) /* Execute the parser */
1960 parser(1);
1961 return(mrval[maclvl+1]); /* Return the result */
1962 }
1963 return(NULL);
1964 }
1965 #endif /* NOSPL */
1966
1967 static int
dncvt(k,cx,prefix,suffix)1968 dncvt(k,cx, prefix, suffix)
1969 int k, cx, prefix, suffix; { /* Dial Number Convert */
1970 int i, j, n, what; /* cx is top-level command index */
1971 char *ss; /* prefix - add prefixes? */
1972 char *p, *p2, *pxo; /* suffix - add suffixes? */
1973 char *lac;
1974 char *npr;
1975 char *sfx;
1976 /* char *psfx; */
1977 char ccbuf[128];
1978 int cc;
1979 char acbuf[24];
1980 char *acptr;
1981 char outbuf[256];
1982 /*
1983 First pass for strict (punctuation-based) interpretation.
1984 If it fails, we try the looser (length-based) one.
1985 */
1986 dialtype = -1;
1987 what = 0; /* Type of call */
1988 s = dn_p[k]; /* Number to be converted. */
1989 debug(F111,"dncvt",s,k);
1990 if (dn_p2[k]) {
1991 free(dn_p2[k]);
1992 dn_p2[k] = NULL;
1993 }
1994 if (!s) {
1995 printf("Error - No phone number to convert\n");
1996 return(-1);
1997 }
1998 if ((int)strlen(s) > 200) {
1999 ckstrncpy(outbuf,s,40);
2000 printf("?Too long: \"%s...\"\n",outbuf);
2001 return(-1);
2002 }
2003 npr = (prefix && dialnpr) ? dialnpr : "";
2004 sfx = (suffix && dialsfx) ? dialsfx : "";
2005 /* if (partial) psfx = dialsfx ? dialsfx : ""; */
2006 pxo = (prefix && dialpxo) ? dialpxo : "";
2007 lac = diallac ? diallac : ""; /* Local area code */
2008
2009 outbuf[0] = NUL; /* Initialize conversion buffer */
2010 ss = s; /* Remember original string */
2011
2012 if (*s != '+') { /* Literal number */
2013 dn_x[k] = DN_UNK; /* Sort key is "unknown". */
2014 ckmakmsg(outbuf,256, /* Sandwich it between */
2015 pxo,npr,s,sfx /* DIAL PREFIX and SUFFIX */
2016 );
2017 #ifdef CK_TAPI
2018 if (tttapi && /* TAPI does its own conversions */
2019 !tapipass && /* if not in passthru mode */
2020 tapiconv == CK_AUTO || /* and TAPI conversions are AUTO */
2021 tapiconv == CK_ON /* OR if TAPI conversions are ON */
2022 ) {
2023 char * p = NULL;
2024 dialtype = -2;
2025 if (!cktapiConvertPhoneNumber(dn_p[k], &p))
2026 return(-1);
2027 makestr(&dn_p2[k], p);
2028 if (p) free(p);
2029 return(0);
2030 } else
2031 #endif /* CK_TAPI */
2032 makestr(&dn_p2[k], outbuf); /* Not TAPI */
2033 dialtype = what;
2034 return(0); /* Done. */
2035 }
2036 i = 0; /* Portable number */
2037 s++; /* Tiptoe past the plus sign */
2038 ccbuf[0] = NUL; /* Do country code first */
2039
2040 if (!diallcc) { /* Do we know our own? */
2041 if (cx != XXLOOK)
2042 printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
2043 return(-1);
2044 }
2045
2046 /* Parse the number */
2047
2048 while (1) { /* Get the country code */
2049 while (*s == HT || *s == SP)
2050 s++;
2051 if (!s) /* Not in standard format */
2052 break;
2053 if (*s == '(') { /* Beginning of area code */
2054 s++; /* Skip past parenthesis */
2055 ccbuf[i] = NUL; /* End of country code */
2056 if (!s) { /* Check for end of string */
2057 printf("Error - phone number ends prematurely: \"%s\"\n",ss);
2058 return(-1);
2059 }
2060 break;
2061 } else { /* Collect country code */
2062 if (isdigit(*s))
2063 ccbuf[i++] = *s; /* copy this character */
2064 s++;
2065 if (!*s || i > 127) /* watch out for memory leak */
2066 break;
2067 }
2068 }
2069 cc = atoi(ccbuf); /* Numeric version of country code */
2070
2071 i = 0; /* Now get area code */
2072 acbuf[0] = NUL; /* Initialize area-code buffer */
2073 acptr = acbuf; /* and pointer. */
2074 while (1) {
2075 while (*s == HT || *s == SP) /* Ignore whitespace */
2076 s++;
2077 if (!s) /* String finished */
2078 break;
2079 if (*s == ')') { /* End of area code */
2080 s++; /* Skip past parenthesis */
2081 acbuf[i] = NUL; /* Terminate area-code buffer */
2082 break;
2083 } else { /* Part of area code */
2084 if (isdigit(*s)) /* If it's a digit, */
2085 acbuf[i++] = *s; /* copy this character */
2086 s++; /* Point to next */
2087 if (!*s || i > 23) /* Watch out for overflow */
2088 break;
2089 }
2090 }
2091
2092 /*
2093 Here we strip any leading 0 for countries that we know have
2094 0 as a long-distance prefix and do not have any area codes that
2095 start with 0 (formerly also ditto for "9" in Finland...)
2096 */
2097 i = atoi(ccbuf);
2098 acptr = chk_ac(i,acbuf);
2099
2100 while (*s == HT || *s == SP) /* Skip whitespace */
2101 s++;
2102
2103 /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
2104
2105 if (*s && *acptr) { /* Area code was delimited */
2106
2107 while (*s == '-' || *s == '.') /* Skip past gratuitious punctuation */
2108 s++;
2109 if (!*s) s--; /* But not to end of string */
2110
2111 if (strcmp(diallcc,ccbuf)) { /* Out of country? */
2112 if (!dialixp) { /* Need intl-prefix */
2113 if (cx != XXLOOK)
2114 printf("Error - No international dialing prefix defined\n");
2115 return(-1);
2116 }
2117 what = dn_x[k] = DN_INTL;
2118 p = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
2119 p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
2120
2121 /* Form the final phone number */
2122 #ifdef COMMENT
2123 sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */
2124 sprintf(outbuf,
2125 "%s%s%s%s%s%s%s%s",
2126 pxo,npr,p,ccbuf,acptr,s,p2,sfx
2127 );
2128 #else
2129 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2130 ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx,
2131 NULL,NULL,NULL,NULL);
2132 #endif /* COMMENT */
2133
2134 } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
2135 if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
2136 if (cc == 1)
2137 printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
2138 }
2139 if (x == 2) { /* Local call with area code */
2140 what = dn_x[k] = DN_LOCAL; /* Local-call */
2141 p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
2142 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
2143 } else {
2144 what = dn_x[k] = DN_LONG; /* Long-distance */
2145 for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
2146 if (!strcmp(acptr,dialtfc[i])) {
2147 what = dn_x[k] = DN_FREE;
2148 break;
2149 }
2150 }
2151 if (what == DN_FREE) { /* Toll-free call */
2152 p = (prefix && dialtfp) ? dialtfp :
2153 ((prefix && dialldp) ? dialldp : "");
2154 p2 = ""; /* no suffix */
2155 } else { /* normal long distance */
2156 p = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
2157 p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
2158 }
2159 }
2160 /* Form the number to be dialed */
2161 #ifdef COMMENT
2162 sprintf(outbuf,"%s%s%s%s%s%s%s",
2163 pxo,npr,p,acptr,s,p2,sfx
2164 );
2165 sprintf(pdsfx,"%s%s",p2,sfx);
2166 #else
2167 ckmakxmsg(outbuf,256,
2168 pxo,npr,p,acptr,s,p2,sfx,
2169 NULL,NULL,NULL,NULL,NULL);
2170 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2171 #endif /* COMMENT */
2172 } else { /* Same country, same area code */
2173 what = dn_x[k] = DN_LOCAL; /* So it's a local call. */
2174 if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
2175 p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
2176 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
2177 #ifdef COMMENT
2178 if (x == 2)
2179 sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
2180 else
2181 sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
2182 sprintf(pdsfx,"%s%s",p2,sfx);
2183 #else
2184 if (x == 2)
2185 ckmakxmsg(outbuf,256,
2186 npr,p,acptr,s,p2,sfx,
2187 NULL,NULL,NULL,NULL,NULL,NULL);
2188 else
2189 ckmakxmsg(outbuf,256,
2190 npr,p,s,p2,sfx,
2191 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
2192 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2193 #endif /* COMMENT */
2194
2195 } else { /* Dialing from a PBX and not TAPI */
2196 if (ndialpxx) { /* Is it internal? */
2197 #ifdef COMMENT
2198 i = (int) strlen(dialpxx);
2199 j = (int) strlen(s);
2200 x = -1;
2201 if (j > i)
2202 x = ckstrcmp(dialpxx,s,i,0);
2203 #else
2204 int kx;
2205 x = -1;
2206 j = (int) strlen(s);
2207 for (kx = 0; kx < ndialpxx; kx++) {
2208 i = (int) strlen(dialpxx[kx]);
2209 if (j > i)
2210 if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
2211 break;
2212 }
2213 #endif /* COMMENT */
2214 if (!x) {
2215 char * icp, buf[32];
2216 makestr(&matchpxx,dialpxx[kx]);
2217 debug(F111,"dncvt matchpxx",matchpxx,kx);
2218 what = dn_x[kx] = DN_INTERN; /* Internal call. */
2219 s += i;
2220 /* Internal-call prefix */
2221 icp = dialpxi;
2222 #ifndef NOSPL
2223 if (icp) {
2224 if (*icp == '\\') {
2225 char c, *bp;
2226 int n;
2227 c = *(icp+1);
2228 if (isupper(c)) c = tolower(c);
2229 if (c == 'v' || c == 'f') {
2230 n = 32;
2231 bp = buf;
2232 zzstring(icp,&bp,&n);
2233 icp = buf;
2234 }
2235 }
2236 }
2237 #endif /* NOSPL */
2238 p = (prefix && icp) ? icp : "";
2239 #ifdef COMMENT
2240 sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx);
2241 #else
2242 ckmakmsg(outbuf,256,npr,p,s,sfx);
2243 #endif /* COMMENT */
2244 } else { /* External local call */
2245 /* local-prefix */
2246 p = (prefix && diallcp) ? diallcp : "";
2247 /* local-suffix */
2248 p2 = (prefix && diallcs) ? diallcs : "";
2249 #ifdef COMMENT
2250 if (x == 2)
2251 sprintf(outbuf,"%s%s%s%s%s%s%s",
2252 dialpxo ? dialpxo : "",
2253 npr,p,acptr,s,p2,sfx);
2254 else
2255 sprintf(outbuf,
2256 "%s%s%s%s%s%s",
2257 dialpxo ? dialpxo : "",
2258 npr,p,s,p2,sfx
2259 );
2260 #else
2261 if (x == 2)
2262 ckmakxmsg(outbuf, 256,
2263 dialpxo ? dialpxo : "",
2264 npr,p,acptr,s,p2,sfx,
2265 NULL,NULL,NULL,NULL,NULL);
2266 else
2267 ckmakxmsg(outbuf, 256,
2268 dialpxo ? dialpxo : "",
2269 npr,p,s,p2,sfx,
2270 NULL,NULL,NULL,NULL,NULL,NULL);
2271 #endif /* COMMENT */
2272 }
2273 }
2274 }
2275 }
2276
2277 } else { /* Area code was not delimited */
2278
2279 char xbuf[256]; /* Comparison based only on length */
2280 char ybuf[256];
2281 int x, j;
2282
2283 s = ss;
2284
2285 for (i = 0; i < 255; i++) {
2286 if (!*s) break;
2287 while (!isdigit(*s)) { /* Pay attention only to digits */
2288 s++;
2289 if (!*s) break;
2290 }
2291 xbuf[i] = *s++;
2292 }
2293 xbuf[i] = NUL;
2294
2295 x = 1; /* Assume LD */
2296 n = 0;
2297 if (!dialfld) { /* If LD not forced */
2298 for (j = 0; j < nlocalac; j++) { /* check local AC list? */
2299 ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL);
2300 n = (int) strlen(ybuf);
2301 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
2302 x = 2;
2303 break;
2304 }
2305 }
2306 if (x == 1) { /* Or exact match with local CC+AC? */
2307 ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL);
2308 n = (int) strlen(ybuf);
2309 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
2310 x = 0;
2311 }
2312 }
2313 if (x == 0 || x == 2) { /* Local call */
2314 int xx,kx; /* Begin 1 Dec 2001... */
2315 /* Account for PBX internal calls */
2316 if (ndialpxx) {
2317 xx = -1;
2318 j = (int) strlen(ybuf);
2319 for (kx = 0; kx < ndialpxx; kx++) {
2320 i = (int) strlen(dialpxx[kx]);
2321 if (j >= i)
2322 if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0)))
2323 break;
2324 }
2325 }
2326 if (!xx) {
2327 char * icp, buf[32];
2328 makestr(&matchpxx,dialpxx[kx]);
2329 debug(F111,"dncvt matchpxx",matchpxx,kx);
2330 what = dn_x[kx] = DN_INTERN; /* Internal call. */
2331 s = xbuf + j + i;
2332 icp = dialpxi; /* Internal-call prefix */
2333 #ifndef NOSPL
2334 if (icp) {
2335 if (*icp == '\\') {
2336 char c, *bp;
2337 int n;
2338 c = *(icp+1);
2339 if (isupper(c)) c = tolower(c);
2340 if (c == 'v' || c == 'f') {
2341 n = 32;
2342 bp = buf;
2343 zzstring(icp,&bp,&n);
2344 icp = buf;
2345 }
2346 }
2347 }
2348 #endif /* NOSPL */
2349 p = (prefix && icp) ? icp : "";
2350 ckmakmsg(outbuf,256,npr,p,s,sfx);
2351 /* End 1 Dec 2001... */
2352
2353 } else { /* Not PBX internal */
2354
2355 dn_x[k] = DN_LOCAL;
2356 p = (prefix && diallcp) ? diallcp : "";
2357 p2 = (suffix && diallcs) ? diallcs : "";
2358 s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
2359 ckmakxmsg(outbuf,256,
2360 pxo,npr,p,s,p2,sfx,
2361 NULL,NULL,NULL,NULL,NULL,NULL);
2362 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2363 }
2364 } else { /* Not local */
2365 n = ckstrncpy(ybuf,diallcc,256);
2366 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
2367 dn_x[k] = DN_LONG;
2368 p = (prefix && dialldp) ? dialldp : "";
2369 p2 = (suffix && diallds) ? diallds : "";
2370 s = xbuf + n;
2371 while (*s == '-' || *s == '.')
2372 s++;
2373 #ifdef COMMENT
2374 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
2375 sprintf(pdsfx,"%s%s",p2,sfx);
2376 #else
2377 ckmakxmsg(outbuf,256,
2378 pxo,npr,p,s,p2,sfx,
2379 NULL,NULL,NULL,NULL,NULL,NULL);
2380 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2381 #endif /* COMMENT */
2382 } else {
2383 dn_x[k] = DN_INTL; /* International */
2384 if (!dialixp) {
2385 if (cx != XXLOOK) {
2386 printf(
2387 "Error - No international dialing prefix defined\n"
2388 );
2389 return(-1);
2390 }
2391 }
2392 p = (prefix && dialixp) ? dialixp : "";
2393 p2 = (suffix && dialixs) ? dialixs : "";
2394 #ifdef COMMENT
2395 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
2396 sprintf(pdsfx,"%s%s",p2,sfx);
2397 #else
2398 ckmakxmsg(outbuf,256,
2399 pxo,npr,p,xbuf,p2,sfx,
2400 NULL,NULL,NULL,NULL,NULL,NULL);
2401 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2402 #endif /* COMMENT */
2403 }
2404 }
2405 }
2406 #ifdef CK_TAPI
2407 if (tttapi && /* TAPI performs the conversions */
2408 !tapipass &&
2409 tapiconv == CK_AUTO ||
2410 tapiconv == CK_ON
2411 ) {
2412 p = NULL;
2413 dialtype = -2;
2414 if (!cktapiConvertPhoneNumber(dn_p[k],&p))
2415 return(-1);
2416 makestr(&dn_p2[k], p);
2417 if (p) free(p);
2418 return(0);
2419 } else {
2420 #endif /* CK_TAPI */
2421 makestr(&dn_p2[k], outbuf);
2422 #ifdef CK_TAPI
2423 }
2424 #endif /* CK_TAPI */
2425 dialtype = what;
2426 return(0);
2427 }
2428
2429 static int
ddcvt(s,f,n)2430 ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
2431 char linebuf[1024], *s2; /* Buffers and pointers */
2432 #ifdef VMS
2433 char * temp = NULL;
2434 #endif /* VMS */
2435 char *info[8]; /* Pointers to words from entry */
2436 FILE * f2 = NULL;
2437 int x, rc;
2438 rc = -1;
2439
2440 debug(F110,"ddcvt file",s,0);
2441
2442 if (!s || !f) /* No filename or file */
2443 return(-1);
2444 if (!*s)
2445
2446 fclose(f);
2447 znewn(s,&s2); /* s2 = address of static buffer */
2448 debug(F110,"ddcvt newname",s2,0);
2449
2450 #ifdef VMS
2451 /* In VMS, znewn() returns the same file name with a new version number */
2452 makestr(&temp,s); /* Swap - otherwise the new */
2453 s = s2; /* version has the older version */
2454 s2 = temp; /* number... */
2455 debug(F110,"ddcvt after swap s",s,0);
2456 debug(F110,"ddcvt after swap s2",s2,0);
2457 makestr(&(dialdir[n]),s); /* New file gets new version number */
2458 debug(F110,"ddcvt after makestr s2",s2,0);
2459 debug(F111,"ddcvt dialdir[n]",dialdir[n],n);
2460 #else
2461 if (zrename(s,s2) < 0) { /* Not VMS - rename old file */
2462 perror(s2); /* to new (wierd) name. */
2463 goto ddexit;
2464 }
2465 #endif /* VMS */
2466 debug(F110,"ddcvt s2 (old)",s2,0);
2467 if ((f = fopen(s2,"r")) == NULL) { /* Reopen old file with wierd name */
2468 debug(F110,"ddcvt s2 open error",ck_errstr(),0);
2469 dirline = 0; /* (or in VMS, old version) */
2470 perror(s2);
2471 goto ddexit;
2472 }
2473 debug(F110,"ddcvt fopen(s2) OK",s2,0);
2474
2475 debug(F110,"ddcvt s (new)",s,0);
2476 if ((f2 = fopen(s,"w")) == NULL) { /* Create new file with old name */
2477 debug(F110,"ddcvt s open error",ck_errstr(),0);
2478 perror(s); /* (or in VMS, new version) */
2479 goto ddexit;
2480 }
2481 debug(F110,"ddcvt fopen(s) OK",s,0);
2482
2483 printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
2484 fprintf(f2,"; %s - Kermit dialing directory\n", s);
2485 fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
2486 "; Name","Number","Speed","Parity","Comment"
2487 );
2488
2489 while (1) {
2490 linebuf[0] = NUL; /* Read a line */
2491 if (fgets(linebuf,1023,f) == NULL)
2492 break;
2493 debug(F110,"ddcvt linebuf",linebuf,0);
2494 if (!linebuf[0]) { /* Empty line */
2495 fprintf(f2,"\n");
2496 continue;
2497 }
2498 x = (int) strlen(linebuf); /* Strip line terminator, */
2499 while (x-- > 0) { /* if any. */
2500 if (linebuf[x] <= SP)
2501 linebuf[x] = NUL;
2502 else
2503 break;
2504 }
2505 xwords(linebuf,5,info,1); /* Parse it the old way */
2506 for (x = 1; x < 6; x++)
2507 if (!info[x]) info[x] = "";
2508 fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
2509 info[1],info[2],info[3],info[4],info[5]
2510 );
2511 }
2512 printf(" OK\n\n");
2513 rc = 0; /* Success */
2514 ddexit:
2515 if (f) fclose(f);
2516 if (f2) fclose(f2);
2517 #ifdef VMS
2518 if (temp) free(temp);
2519 #endif /* VMS */
2520 return(rc);
2521 }
2522
2523 int /* s = name to look up */
2524 #ifdef CK_ANSIC /* cx = index of command */
ludial(char * s,int cx)2525 ludial(char *s, int cx) /* (DIAL, LOOKUP, etc) */
2526 #else
2527 ludial(s, cx) char *s; int cx;
2528 #endif /* CK_ANSIC */
2529 /* ludial */ {
2530
2531 int dd, n1, n2, n3, i, j, t; /* Workers */
2532 int olddir, newdir, oldentry, newentry;
2533 int pass = 0;
2534 int oldflg = 0;
2535 int ambiguous = 0; /* Flag for lookup was ambiguous */
2536 char *info[7]; /* Pointers to words from entry */
2537 char *pp; /* Pointer to element of array */
2538 FILE * f;
2539 char *line; /* File input buffer */
2540
2541 /* #define LUDEBUG */
2542
2543 #ifdef LUDEBUG
2544 int zz = 1;
2545 #endif /* LUDEBUG */
2546
2547 if (!s || ndialdir < 1) /* Validate arguments */
2548 return(-1);
2549
2550 if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */
2551 return(-1);
2552
2553 if (!(line = malloc(1024))) /* Allocate input buffer */
2554 return(-1);
2555
2556 #ifdef LUDEBUG
2557 if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
2558 #endif /* LUDEBUG */
2559
2560 pass = 0;
2561 lu_again:
2562 f = NULL; /* Dial directory file descriptor */
2563 t = dncount = 0; /* Dial-number match count */
2564 dd = 0; /* Directory counter */
2565 olddir = 0;
2566 newdir = 0;
2567 /*
2568 We need to recognize both old- and new-style directories.
2569 But we can't allow old-style and new-style entries in the same
2570 directory because there is no way to tell for sure the difference between
2571 an old-style entry like this:
2572
2573 foo 5551212 9600
2574
2575 and a new-style literal entry like this:
2576
2577 foo 555 9600
2578
2579 I.e. is the "9600" a speed, or part of the phone number?
2580 */
2581 while (1) { /* We make one pass */
2582 if (!f) { /* Directory not open */
2583 if (dd >= ndialdir) /* No directories left? */
2584 break; /* Done. */
2585 debug(F111,"ludial dialdir[dd]",dialdir[dd],dd);
2586 if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
2587 perror(dialdir[dd]); /* Can't, print message saying why */
2588 if (line) {
2589 free(line);
2590 line = NULL;
2591 }
2592 dd++; /* Go on to next one, if any... */
2593 continue;
2594 }
2595 dirline = 0; /* Directory file line number */
2596 if (dialdpy && !pass)
2597 printf("Opening: %s...\n",dialdir[dd]);
2598 dd++;
2599 if (!oldflg) olddir = 0;
2600 newdir = 0;
2601 }
2602 oldentry = 0;
2603 newentry = 0;
2604 line[0] = NUL;
2605 if (getnct(line,1023,f,1) < 0) { /* Read a line */
2606 if (f) { /* f can be clobbered! */
2607 fclose(f); /* Close the file */
2608 f = NULL; /* Indicate next one needs opening */
2609 oldflg = 0;
2610 }
2611 continue;
2612 }
2613 if (!line[0]) /* Empty line */
2614 continue;
2615 #ifdef LUDEBUG
2616 if (zz) printf("LUDIAL 2 s[%s]\n",s);
2617 #endif /* LUDEBUG */
2618
2619 /* Make a copy and parse it the old way */
2620 /* A copy is needed because xwords() pokes NULs into the string */
2621
2622 if ((pp = malloc((int)strlen(line) + 1))) {
2623 strcpy(pp,line); /* safe */
2624 xwords(pp,5,info,0); /* Parse it the old way */
2625
2626 #ifdef LUDEBUG
2627 if (zz) printf("LUDIAL 3 s[%s]\n",s);
2628 #endif /* LUDEBUG */
2629
2630 if (!info[1])
2631 continue;
2632 if (*info[1] == ';') { /* If full-line comment, */
2633 newdir = 1; /* (only new directories have them) */
2634 continue; /* keep reading. */
2635 }
2636 if (!info[2])
2637 continue;
2638 if (*info[2] == '+')
2639 newentry = 1;
2640 if (info[4]) {
2641 if ((*info[4] == '=') ||
2642 !ckstrcmp(info[4],"none", 4,0) ||
2643 !ckstrcmp(info[4],"even", 4,0) ||
2644 !ckstrcmp(info[4],"space",5,0) ||
2645 !ckstrcmp(info[4],"mark", 4,0) ||
2646 !ckstrcmp(info[4],"odd", 3,0)
2647 )
2648 oldentry = 1;
2649 }
2650 }
2651 if (pp) {
2652 free(pp);
2653 pp = NULL;
2654 }
2655
2656 /* Check consistency */
2657
2658 if ((oldentry || olddir) && (newentry || newdir)) {
2659 printf(
2660 "\nERROR: You seem to have old- and new-format entries mixed in your\n");
2661 printf(
2662 "dialing directory. You'll have to edit it by hand to convert it to the\n");
2663 #ifndef NOHELP
2664 printf("new format. Type HELP DIAL for further information.\n\n");
2665 #else
2666 printf("new format.\n\n");
2667 #endif /* NOHELP */
2668 if (line) {
2669 free(line);
2670 line = NULL;
2671 }
2672 return(-1);
2673 }
2674 if (!olddir && oldentry) {
2675 int convert = 0;
2676 olddir = 1;
2677 if (dialcvt == 2) { /* 2 == ASK */
2678 sprintf(tmpbuf,
2679 "WARNING: Old-style dialing directory detected:\n%s", line);
2680 convert = uq_ok(tmpbuf,
2681 "Shall I convert it for you? ",3,NULL,0);
2682 } else
2683 convert = dialcvt;
2684 if (convert) {
2685 debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd);
2686 if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
2687 debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd);
2688 oldflg = 1;
2689 printf(
2690 " Sorry, can't convert.");
2691 printf(
2692 " Will ignore speed and parity fields, continuing...\n\n");
2693 } else {
2694 olddir = newdir = 0;
2695 debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd);
2696 }
2697 dd--;
2698 f = NULL;
2699 continue;
2700 } else {
2701 if (dialcvt == 2)
2702 printf(
2703 " OK, will ignore speed and parity fields, continuing...\n\n");
2704 olddir = 1;
2705 }
2706 }
2707
2708 #ifdef LUDEBUG
2709 if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
2710 #endif /* LUDEBUG */
2711
2712 /* Now parse again for real */
2713
2714 if (oldentry) /* Parse it the old way */
2715 xwords(line,5,info,0);
2716 else /* Parse it the new way */
2717 xwords(line,2,info,1);
2718
2719 #ifdef LUDEBUG
2720 if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
2721 if (zz) printf("%s [%s]\n",info[1],info[2]);
2722 #endif /* LUDEBUG */
2723
2724 if (info[1]) { /* First word is entry name */
2725 if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
2726 continue; /* If no first word, keep reading. */
2727 if (n3 < n1) /* Search name is longer */
2728 continue; /* Can't possibly match */
2729 if (ambiguous && n3 != n1)
2730 continue;
2731
2732 #ifdef LUDEBUG
2733 if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
2734 #endif /* LUDEBUG */
2735
2736 if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
2737 continue;
2738
2739 #ifdef LUDEBUG
2740 if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
2741 #endif /* LUDEBUG */
2742
2743 if (!info[2]) /* No phone number given */
2744 continue;
2745 if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
2746 continue; /* Ignore empty phone numbers */
2747
2748 /* Got one */
2749
2750 if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
2751 printf("?internal error - ludial malloc 1\n");
2752 if (line) {
2753 free(line);
2754 line = NULL;
2755 }
2756 dncount = 0;
2757 return(-1);
2758 }
2759 strcpy(pp,info[2]); /* safe */
2760
2761 if (dncount > MAXDNUMS) {
2762 printf("Warning: %d matches found, %d max\n",
2763 dncount,
2764 MAXDNUMS
2765 );
2766 dncount = MAXDNUMS;
2767 break;
2768 }
2769 dn_p[dncount++] = pp; /* Add pointer to array. */
2770 if (dncount == 1) { /* First one... */
2771 if (d_name) free(d_name);
2772 if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
2773 printf("?internal error - ludial malloc 2\n");
2774 if (line) {
2775 free(line);
2776 line = NULL;
2777 }
2778 dncount = 0;
2779 return(-1);
2780 }
2781 t = n3; /* And its length */
2782 strcpy(d_name,info[1]); /* safe */
2783 } else { /* Second or subsequent one */
2784
2785 #ifdef LUDEBUG
2786 if (zz)
2787 printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
2788 #endif /* LUDEBUG */
2789
2790 if ((int) strlen(info[1]) == t) /* Lengths compare */
2791 if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
2792 continue;
2793
2794 /* Name given by user matches entries with different names */
2795
2796 if (ambiguous) /* Been here before */
2797 break;
2798
2799 ambiguous = 1; /* Now an exact match is required */
2800 for (j = 0; j < dncount; j++) { /* Clean out previous list */
2801 if (dn_p[j]) {
2802 free(dn_p[j]);
2803 dn_p[j] = NULL;
2804 }
2805 }
2806 pass++; /* Second pass... */
2807 goto lu_again; /* Do it all over again. */
2808 }
2809 }
2810 }
2811 if (line) free(line);
2812 if (dncount == 0 && ambiguous) {
2813 printf(" Lookup: \"%s\" - ambiguous%s\n",
2814 s,
2815 cx == XXLOOK ? "" : " - dialing skipped"
2816 );
2817 return(-2);
2818 }
2819 return(dncount);
2820 }
2821
2822 char *
pncvt(s)2823 pncvt(s) char *s; { /* Phone number conversion */
2824 char *p = NULL; /* (just a wrapper for dncvt() */
2825 char *q = NULL;
2826 static char pnbuf[128];
2827 makestr(&p,dn_p[0]); /* Save these in case they are */
2828 makestr(&q,dn_p2[0]); /* being used */
2829 makestr(&dn_p[0],s); /* Copy the argument string to here */
2830 dncvt(0,XXLOOK,1,1); /* Convert it */
2831 if (!dn_p2[0]) /* Put result where can return it */
2832 pnbuf[0] = NUL;
2833 else
2834 ckstrncpy(pnbuf,dn_p2[0],127);
2835 makestr(&dn_p[0],p); /* Restore these */
2836 makestr(&dn_p2[0],q);
2837 makestr(&p,NULL); /* Free these */
2838 makestr(&q,NULL);
2839 return((char *)pnbuf);
2840 }
2841
2842 int
dodial(cx)2843 dodial(cx) int cx; { /* DIAL or REDIAL */
2844 int i = 0, x = 0; /* Workers */
2845 int sparity = -1; /* For saving global parity value */
2846 int previous = 0;
2847 int len = 0;
2848 int literal = 0;
2849 int flowsave;
2850 int lufound = 0; /* Did any lookup succeed? */
2851 int prefix = 1;
2852 int postfix = 1;
2853 int wasalpha = 0;
2854 int xredial = 0;
2855 int braces = 0;
2856
2857 char *p = NULL, *s3 = NULL, * sav = NULL;
2858 int j = 0, t = 0, n = 0;
2859 int xretries, xlcc;
2860
2861 #ifdef COMMENT
2862 debug(F101,"dodial cx","",cx);
2863 debug(F111,"dodial diallcc",diallcc,diallcc);
2864 #endif /* COMMENT */
2865
2866 xretries = dialrtr; /* If retries not set, */
2867 if (diallcc) { /* choose default based on */
2868 xlcc = atoi(diallcc); /* local country code. */
2869 if (xretries < 0) {
2870 switch (xlcc) {
2871 case 1: xretries = 10; break; /* No restrictions in NANP */
2872 /* Add other country codes here */
2873 /* that are known to have no restrictions on redialing. */
2874 default: xretries = 1;
2875 }
2876 }
2877 }
2878 if (cx == XXPDIA) { /* Shortcut... */
2879 cx = XXDIAL;
2880 partial = 1;
2881 debug(F100,"PDIAL sets partial=1","",0);
2882 postfix = 0; /* Do not add postfix */
2883 } else {
2884 partial = 0;
2885 debug(F100,"DIAL sets partial=0","",0);
2886 }
2887 previous = dialsta; /* Status of previous call, if any */
2888 if (previous == DIA_PART) {
2889 prefix = 0; /* do not add prefix */
2890 }
2891 s = NULL; /* Initialize user's dial string */
2892 if (cx == XXRED) { /* REDIAL or... */
2893 if ((y = cmcfm()) < 0)
2894 return(y);
2895 } else if (cx == XXANSW) { /* ANSWER or ... */
2896 if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
2897 return(y);
2898 dialatmo = x;
2899 if ((y = cmcfm()) < 0)
2900 return(y);
2901 } else { /* DIAL or LOOKUP */
2902 if (ndialdir > 0)
2903 s3 = "Number to dial or entry from dial directory";
2904 else
2905 s3 = "Number to dial";
2906 if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
2907 return(x);
2908 if (s) {
2909 len = (int) strlen(s);
2910 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
2911 #ifdef COMMENT
2912 if (len > 1) { /* Strip outer braces if given */
2913 if (*s == '{') {
2914 if (s[len-1] == '}') {
2915 s[len-1] = NUL;
2916 s++;
2917 len -= 2;
2918 }
2919 }
2920 }
2921 #else
2922 s = brstrip(s); /* Strip outer braces or quotes */
2923 #endif /* COMMENT */
2924 }
2925 }
2926
2927 if (cx != XXLOOK) { /* Not LOOKUP */
2928 #ifdef IKSD
2929 if (inserver) {
2930 printf("Sorry, dialing is disabled.\r\n");
2931 return(success = 0);
2932 }
2933 #endif /* IKSD */
2934 #ifdef CK_TAPI
2935 if (tttapi && !tapipass) {
2936 ; /* Skip the modem test if TAPI */
2937 } else
2938 #endif /* CK_TAPI */
2939 if (mdmtyp < 1 && !dialtest) {
2940 if (network
2941 #ifdef TN_COMPORT
2942 && !istncomport()
2943 #endif /* TN_COMPORT */
2944 )
2945 printf("Please SET HOST first, and then SET MODEM TYPE\n");
2946 else
2947 printf("Sorry, you must SET MODEM TYPE first\n");
2948 dialsta = DIA_NOMO;
2949 return(success = 0);
2950 }
2951 if (!local && !dialtest) {
2952 printf("Sorry, you must SET %s or SET HOST first\n",
2953 #ifdef OS2
2954 "PORT"
2955 #else
2956 "LINE"
2957 #endif /* OS2 */
2958 );
2959 dialsta = DIA_NOLI;
2960 return(success = 0);
2961 }
2962 if ((!network
2963 #ifdef TN_COMPORT
2964 || istncomport()
2965 #endif /* TN_COMPORT */
2966 ) && !dialtest &&
2967 #ifdef CK_TAPI
2968 !tttapi &&
2969 #endif /* CK_TAPI */
2970 (speed < 0L)
2971 #ifdef UNIX
2972 && (strcmp(ttname,"/dev/null"))
2973 #else
2974 #ifdef OSK
2975 && (strcmp(ttname,"/nil"))
2976 #endif /* OSK */
2977 #endif /* UNIX */
2978 ) {
2979 printf("\nSorry, you must SET SPEED first\n");
2980 dialsta = DIA_NOSP;
2981 return(success = 0);
2982 }
2983 }
2984 if (cx != XXANSW) {
2985 for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
2986 if (!dialnum) { /* First time dialing */
2987 dn_p[j] = NULL; /* initialize all pointers. */
2988 dn_p2[j] = NULL;
2989 } else if (dn_p[j]) { /* Not the first time, */
2990 free(dn_p[j]); /* free previous, if any, */
2991 dn_p[j] = NULL; /* then set to NULL. */
2992 if (dn_p2[j])
2993 free(dn_p2[j]);
2994 dn_p2[j] = NULL;
2995 } else break; /* Already NULL */
2996 }
2997 if (len == 0)
2998 s = NULL;
2999 if (!s)
3000 s = dialnum;
3001 if (!s) {
3002 if (cx == XXLOOK)
3003 printf("?Lookup what?\n");
3004 else
3005 printf("%s\n", (cx == XXRED) ?
3006 "?No DIAL command given yet" :
3007 "?You must specify a number to dial"
3008 );
3009 return(-9);
3010 }
3011
3012 /* Now we have the "raw" dial or lookup string and s is not NULL */
3013
3014 makestr(&dscopy,s); /* Put it in a safe place */
3015 s = dscopy;
3016 n = 0;
3017
3018 debug(F111,"dodial",s,ndialdir);
3019
3020 wasalpha = 0;
3021 if (isalpha(*s)) {
3022 wasalpha = 1;
3023 if (ndialdir > 0) { /* Do we have a dialing directory? */
3024 n = ludial(s,cx); /* Look up what the user typed */
3025 if (n == 0)
3026 printf(" Lookup: \"%s\" - not found%s\n",
3027 s,
3028 cx == XXLOOK ? "" : " - dialing as given\n"
3029 );
3030 }
3031 debug(F101,"dodial",s,n);
3032 if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
3033 if (n == -1) /* -2 means ludial already gave msg */
3034 printf(" Lookup: fatal error - dialing skipped\n");
3035 dialsta = DIA_DIR;
3036 return(-9);
3037 }
3038 if (n > 0) /* A successful lookup */
3039 lufound = 1;
3040 } else if (*s == '=') { /* If number starts with = sign */
3041 s++; /* strip it */
3042 literal = 1; /* remember this */
3043 while (*s == SP) s++; /* and then also any leading spaces */
3044 } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
3045 makelist(tmpbuf,dn_p,MAXDNUMS);
3046 makestr(&dscopy,tmpbuf);
3047 s = tmpbuf;
3048 for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
3049 if (!dn_p[n]) break;
3050 braces = 1;
3051 }
3052 if (cx == XXLOOK && !wasalpha && !braces) {
3053 /* We've been told to lookup a number or a quoted name */
3054 char *p;
3055 n = 0;
3056 p = literal ? s : pncvt(dscopy);
3057 if (!p) p = "";
3058 if (*p) {
3059 printf("%s => %s\n", dscopy, p);
3060 return(success = 1);
3061 } else {
3062 printf("?Bad phone number\n");
3063 return(success = 0);
3064 }
3065 }
3066 /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
3067 /* But don't save pieces of partial dial ... */
3068
3069 debug(F101,"DIAL save dialnum partial","",partial);
3070 debug(F101,"DIAL save dialnum previous","",previous);
3071 if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
3072 (cx == XXLOOK && n > 0)) {
3073 makestr(&dialnum,dscopy);
3074 if (!quiet && dscopy && !dialnum)
3075 printf("WARNING - memory allocation failure: redial number\n");
3076 }
3077 if (n > 0) {
3078 if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
3079 if (!strcmp(d_name,s))
3080 printf(" Lookup: \"%s\" - exact match\n",s);
3081 else
3082 printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
3083 s,
3084 d_name
3085 );
3086 }
3087 if ((cx == XXLOOK) ||
3088 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
3089 printf(" %d telephone number%sfound for \"%s\"%s\n",
3090 n,
3091 (n == 1) ? " " : "s ",
3092 s,
3093 (n > 0) ? ":" : "."
3094 );
3095 s3 = getdname();
3096 }
3097 for (i = 0; i < n; i++) { /* Convert */
3098 dn_x[i] = -1;
3099 if (dncvt(i,cx,prefix,postfix) < 0) {
3100 if (cx != XXLOOK) {
3101 dialsta = DIA_DIR;
3102 return(-9);
3103 }
3104 }
3105 }
3106 if (dialsrt && n > 1) { /* Sort into optimal order */
3107 for (i = 0; i < n-1; i++) {
3108 for (j = i+1; j < n; j++) {
3109 if (dn_x[j] < dn_x[i]) {
3110 t = dn_x[j];
3111 dn_x[j] = dn_x[i];
3112 dn_x[i] = t;
3113 p = dn_p[j];
3114 dn_p[j] = dn_p[i];
3115 dn_p[i] = p;
3116 p = dn_p2[j];
3117 dn_p2[j] = dn_p2[i];
3118 dn_p2[i] = p;
3119 }
3120 }
3121 }
3122 }
3123 if ((cx == XXLOOK) ||
3124 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
3125 int nn = n;
3126 #ifndef NOSPL
3127 char * p;
3128 #endif /* NOSPL */
3129 if (cx != XXLOOK)
3130 if (n > 12) nn = 12;
3131 for (i = 0; i < nn; i++) {
3132 printf("%3d. %-12s %-20s => %-20s (%d)\n",i+1,
3133 s3, dn_p[i],
3134 dn_p2[i] ? dn_p2[i] : "(processing failed)",
3135 dn_x[i]
3136 );
3137 }
3138 if (cx != XXLOOK && n != nn)
3139 printf("And %d more...\n", n - nn);
3140 }
3141 } else if (n == 0) { /* Not found in directory */
3142 makestr(&(dn_p[0]),literal ? s : dscopy);
3143 makestr(&d_name,literal ? s : dscopy);
3144 dncount = 1;
3145 n = 1;
3146 if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
3147 dialsta = DIA_DIR; /* portable-format number ... */
3148 return(-9);
3149 }
3150 }
3151
3152 #ifndef NONET
3153 #ifdef NETCONN
3154 /* It's not good that the networks directory depends on NOT-NODIAL.. */
3155 if (cx == XXLOOK && dscopy) { /* Networks here too... */
3156 extern char *nh_p[], *nh_p2[], *n_name;
3157 extern char *nh_px[4][MAXDNUMS+1];
3158 n = -1;
3159 if (nnetdir > 0) { /* Do we have a network directory? */
3160 dirline = 0;
3161 n = lunet(dscopy); /* Look up what the user typed */
3162 }
3163 if (n > -1) {
3164 int k;
3165 if (n > 0) /* A successful lookup */
3166 lufound = 1;
3167 if (cx == XXLOOK && n == 0)
3168 printf(" Lookup: \"%s\" - not found\n",dscopy);
3169 else
3170 printf("%s %d network entr%s found for \"%s\"%s\n",
3171 cx == XXLOOK ? " Lookup:" : "",
3172 n,
3173 (n == 1) ? "y" : "ies",
3174 dscopy,
3175 (n > 0) ? ":" : "."
3176 );
3177
3178 for (i = 0; i < n; i++) {
3179
3180 printf("%3d. %-12s => %-9s %s",
3181 i+1,n_name,nh_p2[i],nh_p[i]);
3182 for (k = 0; k < 4; k++) {
3183 if (nh_px[k][i]) {
3184 printf(" %s",nh_px[k][i]);
3185 } else
3186 break;
3187 }
3188 printf("\n");
3189 }
3190 }
3191 }
3192 #endif /* NETCONN */
3193 #endif /* NONET */
3194 if (cx == XXLOOK)
3195 return(success = lufound);
3196 } /* cx != XXANSW */
3197
3198 #ifdef VMS
3199 conres(); /* So Ctrl-C/Y will work */
3200 #endif /* VMS */
3201 /*
3202 Some modems do not react well to parity. Also, if we are dialing through a
3203 TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
3204 negotiations.
3205
3206 This should work even if the user interrupts the DIAL command, because the
3207 DIAL module has its own interrupt handler. BUT... if, for some reason, a
3208 dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
3209 parity should be used), this might prevent successful dialing. For that
3210 reason, we don't do this for V.25bis modems.
3211 */
3212 sparity = parity; /* Save current parity */
3213 if ((dialcapas & CKD_V25) == 0) /* If not V.25bis... */
3214 parity = 0; /* Set parity to NONE */
3215
3216 flowsave = flow;
3217 /*
3218 These modems use some kind of screwy flow control while in command mode,
3219 and do not present CTS as they should. So if RTS/CTS is set (or even if
3220 it isn't) disable flow control during dialing.
3221 */
3222 #ifndef MINIDIAL
3223 if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
3224 flow = FLO_NONE; /* This is not enough */
3225 #ifdef CK_TTSETFLOW
3226 ttsetflow(FLO_NONE); /* Really turn it off */
3227 #endif /* CK_TTSETFLOW */
3228 }
3229 #endif /* MINIDIAL */
3230 if (!network
3231 #ifdef TN_COMPORT
3232 || istncomport()
3233 #endif /* TN_COMPORT */
3234 ) {
3235 int x;
3236 if ((x = ttgmdm()) > -1) {
3237 if (!x && msgflg) {
3238 printf(
3239 "WARNING - No modem signals detected. Is your modem turned on? If not,\n\
3240 use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n",
3241 cx == XXANSW ?
3242 "ANSWER again" :
3243 "REDIAL"
3244 );
3245 }
3246 if (flow == FLO_RTSC) {
3247 if (!(x & BM_CTS)) {
3248 if (msgflg)
3249 printf(
3250 "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
3251 Disabling flow control temporarily %s...\n",
3252 cx == XXANSW ?
3253 "while waiting for call" :
3254 "during dialing"
3255 );
3256 flow = FLO_NONE;
3257 }
3258 }
3259 }
3260 }
3261 if (cx == XXANSW) { /* ANSWER */
3262 success = ckdial("",0,0,1,0);
3263 goto dialfin;
3264 }
3265
3266 /* Edit 192 adds the ability to dial repeatedly. */
3267
3268 i = 0;
3269 dialcount = 0;
3270 do {
3271 if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
3272 dialcount = i+1;
3273 success = 0;
3274 /* And the ability to dial alternate numbers. */
3275 /* Loop to dial each in a list of numbers for the same name... */
3276 for (j = 0; j < n && !success; j++) { /* until one answers. */
3277 s = dn_p2[j]; /* Next number in list */
3278 if (dn_x[j] >= dialrstr) { /* Dial restriction */
3279 printf("Restricted: %s, skipping...\n",dn_p[j]);
3280 continue;
3281 }
3282 xredial = (i == 0 && j == 0) ? 0 : 1;
3283 if (!s) s = dn_p[j];
3284
3285 #ifndef NOSPL
3286 sav = s;
3287 p = xdial(s); /* Apply DIAL macro now */
3288 if (p) if (*p) s = p;
3289 #endif /* NOSPL */
3290
3291 /* Dial confirmation */
3292 /* NOTE: the uq_xxx() calls allow for a GUI dialog */
3293
3294 if (i == 0 && dialcnf) {
3295 char msgbuf[128];
3296 ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL);
3297 x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0);
3298 if (!x) {
3299
3300 #ifndef COMMENT
3301 x = uq_txt( /* Allow GUI dialog */
3302 #ifdef OS2
3303 " Please enter the correct number,\r\n or press Enter to skip.",
3304 #else
3305 " Please enter the correct number,\r\n or press Return to skip.",
3306 #endif /* OS2 */
3307 "Corrected phone number: ",
3308 1,
3309 NULL,
3310 atmbuf,
3311 ATMBL,
3312 s,
3313 DEFAULT_UQ_TIMEOUT
3314 );
3315 if (x && atmbuf[0]) { /* They gave a new one */
3316 s = atmbuf;
3317 makestr(&(dn_p2[j]), s);
3318 }
3319
3320 #else /* COMMENT */
3321
3322 #ifdef CK_RECALL
3323 extern int on_recall;
3324 #endif /* CK_RECALL */
3325 cmsavp(psave,PROMPTL);
3326 cmsetp(
3327 #ifdef OS2
3328 " Please enter the correct number,\r\n or press Enter to skip: "
3329 #else
3330 " Please enter the correct number,\r\n or press Return to skip: "
3331 #endif /* OS2 */
3332 );
3333 cmini(ckxech);
3334 x = -1;
3335 if (pflag) prompt(NULL);
3336 #ifdef CK_RECALL
3337 on_recall = 0;
3338 #endif /* CK_RECALL */
3339 y = cmdgquo();
3340 cmdsquo(0);
3341 while (x < 0) {
3342 x = cmtxt("Corrected phone number","",&s,NULL);
3343 cmres();
3344 }
3345 if ((int) strlen(s) < 1) {
3346 cmsetp(psave);
3347 continue;
3348 }
3349 makestr(&(dn_p2[j]), s);
3350 cmdsquo(y);
3351 cmsetp(psave);
3352 #endif /* COMMENT */
3353 }
3354 }
3355 if (dialtest) { /* Just testing */
3356 if (i + j == 0)
3357 printf("\nTESTING...\n");
3358 if (dialmac)
3359 printf(" Number: \"%s\" => \"%s\"\n",sav,s);
3360 else
3361 printf(" Number: \"%s\"\n",s);
3362 dialsta = DIA_BUSY;
3363 success = 0;
3364 } else {
3365 what |= W_DIALING;
3366 success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
3367 what &= ~(W_DIALING);
3368 if (!success) {
3369 if (dialsta < 8 || /* Break out if unrecoverable error */
3370 dialsta == DIA_INTR ||
3371 dialsta == DIA_ERR ||
3372 previous == DIA_PART
3373 )
3374 break;
3375 }
3376 }
3377 }
3378 if (success) /* Succeeded, leave the outer loop */
3379 break;
3380 if (dialsta < 8 || /* Break out if unrecoverable error */
3381 dialsta == DIA_INTR || /* Interrupted */
3382 dialsta == DIA_NODT || /* No dialtone */
3383 dialsta == DIA_NOAC || /* Access forbidden */
3384 dialsta == DIA_BLCK || /* Blacklisted */
3385 dialsta == DIA_DIR || /* Dialing directory error */
3386 dialsta == DIA_ERR || /* Modem command error */
3387 previous == DIA_PART)
3388 break;
3389 if (++i >= xretries) /* Break out if too many tries */
3390 break;
3391 if (!backgrd && !quiet) {
3392 if (dialint > 5)
3393 printf(
3394 "\nWill redial in %d second%s- press any key to redial immediately.\n",
3395 dialint,
3396 dialint == 1 ? " " : "s "
3397 );
3398 printf("Ctrl-C to cancel...\n");
3399 }
3400 x = dialint; /* Redial interval */
3401 while (x-- > 0) {
3402 if ((y = conchk()) > 0) { /* Did they type something? */
3403 while (y--) coninc(0); /* Yes, absorb it */
3404 break; /* And wake up */
3405 }
3406 sleep(1); /* No interrupt, sleep a sec */
3407 }
3408 } while (!success);
3409
3410 dialfin:
3411
3412 if (cx != XXLOOK) {
3413 if (!success)
3414 bleep((short) BP_FAIL);
3415 else if (!quiet)
3416 bleep((short) BP_NOTE);
3417 #ifdef OS2
3418 setint(); /* Fix OS/2 interrupts */
3419 #endif /* OS2 */
3420 if (sparity > -1)
3421 parity = sparity; /* Restore parity if we saved it */
3422 flow = flowsave;
3423 #ifdef OS2
3424 ttres(); /* Restore DIAL device */
3425 #endif /* OS2 */
3426 #ifdef VMS
3427 concb((char)escape); /* Restore console */
3428 #endif /* VMS */
3429 #ifdef OS2
3430 { /* Set session title */
3431 char * p, name[72]; /* in window list. */
3432 char * q;
3433 if (cx == XXANSW) {
3434 q = "Incoming call";
3435 } else {
3436 if (d_name)
3437 q = d_name;
3438 else if (dialnum)
3439 q = dialnum;
3440 else if (ttname[0])
3441 q = ttname;
3442 else q = "";
3443 }
3444 p = name;
3445 if (success) {
3446 strncpy(name,q,48);
3447 while (*p) { /* Uppercase it for emphasis. */
3448 if (islower(*p))
3449 *p = toupper(*p);
3450 p++;
3451 }
3452 } else
3453 name[0] = NUL ;
3454 os2settitle((char *) name, TRUE);
3455 }
3456 #endif /* OS2 */
3457 }
3458 if (cx != XXLOOK) {
3459 if (success) {
3460 if (reliable == SET_AUTO) { /* It's not a reliable connection. */
3461 reliable = SET_OFF;
3462 debug(F101,"dodial reliable","",reliable);
3463 }
3464 } else {
3465 #ifndef NOHINTS
3466 extern int hints;
3467 if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */
3468 extern int dialmhu, dialhng, dialdpy;
3469 extern char * dialmsg[];
3470 printf("\n*************************\n");
3471 printf("DIAL-class command failed.\n");
3472 printf("Modem type: %s\n", gmdmtyp());
3473 printf("Device: %s\n", ttname);
3474 printf("Speed: %ld\n", speed);
3475 printf("Dial status: %d",dialsta);
3476 if (dialsta < 35 && dialmsg[dialsta])
3477 printf(" [%s]",dialmsg[dialsta]);
3478 printf("\n");
3479 if (dialsta == DIA_TIMO ||
3480 dialsta == DIA_NRDY ||
3481 (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN)
3482 ) {
3483 switch (dialsta) {
3484 case DIA_TIMO:
3485 printf(
3486 " . SET DIAL TIMEOUT to a greater value and try again.\n"
3487 );
3488 break;
3489 case DIA_NRSP:
3490 case DIA_NRDY:
3491 case DIA_NOIN:
3492 printf(
3493 " . Is the modem turned on?\n"
3494 );
3495 printf(
3496 " . Are you using the right communication port?\n"
3497 );
3498 break;
3499 case DIA_NODT:
3500 printf(
3501 " . Is the modem connected to the telephone line?\n"
3502 );
3503 }
3504 if (mdmtyp == n_GENERIC) {
3505 printf(
3506 " . Please choose a specific modem type with SET MODEM TYPE and try again.\n"
3507 );
3508 printf(
3509 " SET MODEM TYPE ? to see the list of known modem types.\n"
3510 );
3511 } else {
3512 printf(
3513 " . Are you sure you have chosen the appropriate modem type?\n"
3514 );
3515 }
3516 if (speed > 19200L) {
3517 printf(
3518 " . Maybe the interface speed (%ld) is too fast:\n", speed
3519 );
3520 printf(
3521 " SET SPEED to a lower speed and try again.\n"
3522 );
3523 printf(
3524 " SET SPEED ? to see the list of valid speeds.\n"
3525 );
3526 }
3527 if (dialhng) {
3528 if (dialmhu)
3529 printf(
3530 " . SET MODEM HANGUP-METHOD RS232 and try again.\n"
3531 );
3532 else
3533 printf(
3534 " . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n"
3535 );
3536 printf(
3537 " . If that doesn't work, try again with SET DIAL HANGUP OFF.\n"
3538 );
3539 } else {
3540 printf(
3541 " . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n"
3542 );
3543 }
3544 if (!dialdpy)
3545 printf(
3546 " . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n"
3547 );
3548 }
3549 #ifndef NOSHOW
3550 printf(
3551 " . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n"
3552 );
3553 #endif /* NOSHOW */
3554
3555 #ifndef NOHELP
3556 printf(
3557 " . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n"
3558 );
3559 #endif /* NOHELP */
3560 printf("(Use SET HINTS OFF to suppress future hints.)\n");
3561 printf("*************************\n\n");
3562 }
3563 #endif /* NOHINTS */
3564 }
3565 }
3566 return(success);
3567 }
3568 #endif /* NODIAL */
3569
3570 /* D O T Y P E -- Type (display) a file with various options... */
3571
3572 #ifdef BIGBUFOK
3573 #define TYPBUFL 16384
3574 #else
3575 #define TYPBUFL 256
3576 #endif /* BIGBUFOK */
3577
3578 int typ_lines = 0; /* \v(ty_ln) */
3579 int typ_mtchs = 0; /* \v(ty_lm) */
3580 static int typ_int = 0; /* Flag if TYPE interrupted */
3581
3582 #ifdef UNICODE
3583 extern int fcharset, fileorder, byteorder, ucsorder;
3584 #define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4
3585 static char * mp = NULL;
3586 static char * mbuf = NULL;
3587 static long xn = 0L;
3588
3589 static int
3590 #ifdef CK_ANSIC
storechar(char c)3591 storechar(char c)
3592 #else
3593 storechar(c) char c;
3594 #endif /* CK_ANSIC */
3595 {
3596 if (!mp) return(-1);
3597 if (++xn > TYPXBUFL)
3598 return(-1);
3599 debug(F111,"storechar xn",ckitoa((int)c),xn);
3600 *mp++ = c;
3601 return(0);
3602 }
3603 #endif /* UNICODE */
3604
3605 static FILE * ofp = NULL; /* For /OUTPUT: file */
3606
3607 static int
typeline(buf,len,outcs,ofp)3608 typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
3609 register int i;
3610
3611 debug(F011,"typeline buf",buf,len);
3612 /* debug(F101,"typeline outcs","",outcs); */
3613
3614 #ifdef OS2
3615 #ifndef NOLOCAL
3616 #ifdef UNICODE
3617 /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */
3618 /* Len is its length in bytes. There is no line terminator. */
3619 /* outcs is the file character-set number (FC_xxx) of the target set */
3620 /* that was requested by the user. */
3621 if (!inserver && !k95stdout) {
3622 extern int wherex[], wherey[];
3623 extern unsigned char colorcmd;
3624
3625 VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2,
3626 wherey[VCMD], wherex[VCMD], &colorcmd);
3627 printf("\r\n");
3628 return(0);
3629 }
3630 #endif /* UNICODE */
3631 #endif /* NOLOCAL */
3632 #endif /* OS2 */
3633
3634 /* In Unix, VMS, etc, the line has already been converted to the desired */
3635 /* character-set, if one was given. OR... on all platforms, including in */
3636 /* K95, we don't know the character set. In either case we dump the line */
3637 /* byte by byte in case it contains NULs (printf() would truncate). */
3638
3639 #ifdef COMMENT
3640 for (i = 0; i < len; i++)
3641 putchar(buf[i]);
3642 #else
3643 for (i = 0; i < len; i++) {
3644 if (ofp == stdout) {
3645 putchar(buf[i]);
3646 } else {
3647 putc(buf[i],ofp);
3648 }
3649 }
3650 #endif /* COMMENT */
3651
3652 #ifdef IKSD
3653 if (inserver) {
3654 #ifdef UNICODE
3655 if (outcs == FC_UCS2) {
3656 if (ofp == stdout) {
3657 putchar(NUL);
3658 } else {
3659 putc(NUL,ofp);
3660 }
3661 }
3662 #endif /* UNICODE */
3663 if (ofp == stdout) {
3664 putchar('\r');
3665 } else {
3666 putc('\r',ofp);
3667 }
3668 }
3669 #endif /* IKSD */
3670 #ifdef UNICODE
3671 if (outcs == FC_UCS2) {
3672 if (ofp == stdout) {
3673 putchar(NUL);
3674 } else {
3675 putc(NUL,ofp);
3676 }
3677 }
3678 #endif /* UNICODE */
3679 if (ofp == stdout) {
3680 putchar('\n');
3681 } else {
3682 putc('\n',ofp);
3683 }
3684 fflush(stdout);
3685 return(0);
3686 }
3687
3688 static int /* Get translated line */
typegetline(incs,outcs,buf,n)3689 typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
3690 int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0;
3691 #ifdef UNICODE
3692 int xxn = -1;
3693 int yyn = -9;
3694 xn = 0L;
3695
3696 #ifdef DEBUG
3697 if (deblog && typ_lines == 0) {
3698 debug(F101,"typegetline incs","",incs);
3699 debug(F101,"typegetline outcs","",outcs);
3700 debug(F101,"typegetline feol","",feol);
3701 debug(F101,"typegetline byteorder","",byteorder);
3702 debug(F101,"typegetline ucsorder ","",ucsorder);
3703 debug(F111,"typegetline fileorder","1",fileorder);
3704 }
3705 #endif /* DEBUG */
3706
3707 if (incs < 0) /* Shouldn't happen */
3708 return(-2);
3709
3710 if (outcs == -1) /* Can happen */
3711 outcs = incs;
3712
3713 if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */
3714 xlate = 1;
3715 if (!mbuf) { /* Allocate buffer if not allocated */
3716 mbuf = (char *)malloc(TYPXBUFL+1); /* yet */
3717 if (!mbuf) {
3718 printf("WARNING: Translation buffer allocation failure.\n");
3719 printf("Translation will be skipped...\n");
3720 xlate = 0;
3721 }
3722 }
3723 }
3724 if (xlate) { /* Translating... */
3725 mp = mbuf; /* Reset working buffer pointer */
3726 /*
3727 Here we call xgnbyte() in a loop, having it return UCS-2 bytes. In K95, we
3728 use UCS-2 directly. Elsewhere, we feed the UCS-2 bytes into xpnbyte() to
3729 convert them to the desired target character set. But since we are using
3730 UCS-2, we have several sources for confusion: (1) xgnbyte() might return in
3731 LE or BE byte order, with no explicit indication of what the order is; but
3732 (2) xpnbyte() wants BE; but (3) Windows wants LE.
3733 */
3734 while (1) {
3735 if (typ_int) /* Quit if interrupted */
3736 return(0);
3737 c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3738 debug(F000,"typegetline c0","",c0);
3739 if (c0 < 0) { /* EOF */
3740 eof++;
3741 break;
3742 }
3743 c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3744 debug(F000,"typegetline c1","",c1);
3745 if (c1 < 0) { /* EOF */
3746 eof++;
3747 break;
3748 }
3749 #ifdef DEBUG
3750 if (deblog && typ_lines == 0) {
3751 if (count == 0) /* Check fileorder after BOM */
3752 debug(F111,"typegetline fileorder","2",fileorder);
3753 }
3754 #endif /* DEBUG */
3755
3756 #ifdef COMMENT
3757 /* Now we have the two UCS-2 bytes. Which order are they in? */
3758
3759 if (fileorder > 0) { /* Little Endian */
3760 int t; /* So swap them */
3761 debug(F100,"typegetline swapping","",0);
3762 t = c1;
3763 c1 = c0;
3764 c0 = t;
3765 }
3766 #endif /* COMMENT */
3767 if (c0 == 0 && c1 == 0x0D) /* Now see if we have EOL */
3768 yyn = xn;
3769
3770 if (c0 == 0 && c1 == 0x0A) /* Now see if we have EOL */
3771 xxn = xn;
3772
3773 count++; /* Count byte */
3774
3775 /* Give the two bytes to xpnbyte() in BE order */
3776
3777 if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1);
3778 if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1);
3779
3780 if (xxn > -1) { /* Have end of line? */
3781 xn = xxn;
3782 if (yyn == xxn - 2) /* Adjust for CRLF */
3783 xn = yyn;
3784 break; /* And break out of loop. */
3785 }
3786 }
3787 mbuf[xn] = NUL;
3788 if (xn > n) /* Can truncate here... */
3789 xn = n;
3790 memcpy(buf,mbuf,xn);
3791 debug(F011,"typegetline xlate",buf,xn);
3792 return((eof && (xn == 0)) ? -1 : xn);
3793 }
3794 #endif /* UNICODE */
3795 #ifdef COMMENT
3796 /* We can't use this because, stupidly, zsinl() doesn't return a length. */
3797 /* It could be changed but then we'd have to change all ck?fio.c modules */
3798 x = zsinl(ZIFILE,buf,n);
3799 #else
3800 /* So instead, we copy zsinl() to here... */
3801 /* But note: This does not necessarily handle UCS-2 alignment properly; */
3802 /* that's what the code in the first section of this routine is for. */
3803 /* But it does tolerate files that contain NULs. */
3804 {
3805 int a;
3806 char *s;
3807
3808 s = buf;
3809 a = -1; /* Current character, none yet. */
3810 debug(F101,"typegetline zsinl simulation","",n);
3811 while (n--) { /* Up to given length */
3812 #ifdef COMMENT
3813 int old = 0;
3814 if (feol) /* Previous character */
3815 old = a;
3816 #endif /* COMMENT */
3817 if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */
3818 debug(F101,"typegetline zchin fail","",count);
3819 if (count == 0)
3820 x = -1; /* EOF or other error */
3821 break;
3822 } else
3823 count++;
3824 if (feol) { /* Single-character line terminator */
3825 if (a == feol)
3826 break;
3827 } else { /* CRLF line terminator */
3828 #ifdef COMMENT
3829 /* Debug log shows that in Windows, <CR><LF> is returned as <LF>. */
3830 /* Apparently we're not reading the file in binary mode. */
3831
3832 if (a == '\015') /* CR, get next character */
3833 continue;
3834 if (old == '\015') { /* Previous character was CR */
3835 if (a == '\012') { /* This one is LF, so we have a line */
3836 break;
3837 } else { /* Not LF, deposit CR */
3838 *s++ = '\015';
3839 n--;
3840 len++;
3841 }
3842 }
3843 #else
3844 if (a == LF) {
3845 if (s[len] == CR) { /* This probably won't happen */
3846 s[len] = NUL;
3847 s--;
3848 len--;
3849 }
3850 break;
3851 }
3852 #endif /* COMMENT */
3853 }
3854 *s = a; /* Deposit character */
3855 s++;
3856 len++;
3857 }
3858 *s = '\0'; /* Terminate the string */
3859 }
3860 #endif /* COMMENT */
3861 return(x < 0 ? -1 : len);
3862 }
3863
3864
3865 #ifndef MAC
3866 SIGTYP
3867 #ifdef CK_ANSIC
tytrap(int foo)3868 tytrap(int foo) /* TYPE interrupt trap */
3869 #else
3870 tytrap(foo) int foo;
3871 #endif /* CK_ANSIC */
3872 /* tytrap */ {
3873 #ifdef __EMX__
3874 signal(SIGINT, SIG_ACK);
3875 #endif
3876 debug(F100,"type tytrap SIGINT","",0);
3877 typ_int = 1; /* (Need arg for ANSI C) */
3878 SIGRETURN;
3879 }
3880 #endif /* MAC */
3881
3882 int
dotype(file,paging,first,head,pat,width,prefix,incs,outcs,outfile,z)3883 dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z)
3884 char * file, * pat, * prefix; int paging, first, head, width, incs, outcs;
3885 char * outfile; int z;
3886 /* dotype */ {
3887 extern CK_OFF_T ffc;
3888 char buf[TYPBUFL+2];
3889 char * s = NULL;
3890 int rc = 1, lines = 0, ucs2 = 0;
3891 char ** tail = NULL;
3892 int * tlen = NULL;
3893 int tailing = 0, counting = 0;
3894 int x, c, n, i, j, k = 0;
3895 int number = 0, save, len, pfxlen = 0, evalpfx = 1;
3896 #ifdef UNICODE
3897 int ucsbom_sav;
3898 extern int ucsbom;
3899 #endif /* UNICODE */
3900 #ifdef NT
3901 int gui = 0;
3902 #endif /* NT */
3903
3904 #ifndef MAC
3905 #ifdef OS2
3906 #ifdef NT
3907 SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
3908 #else /* NT */
3909 SIGTYP (* volatile oldsig)(int);
3910 #endif /* NT */
3911 #else /* OS2 */
3912 SIGTYP (* oldsig)();
3913 #endif /* OS2 */
3914 #endif /* MAC */
3915
3916 #ifdef KUI
3917 if (outfile == (char *)1) {
3918 gui = 1;
3919 outfile = "";
3920 }
3921 #endif /* KUI */
3922
3923 if (!file) file = "";
3924 if (!*file) return(-2);
3925
3926 if (ofp != stdout) { /* In case of previous interruption */
3927 if (ofp) fclose(ofp);
3928 ofp = stdout;
3929 }
3930 if (!outfile) outfile = "";
3931 if (outfile[0]) {
3932 ofp = fopen(outfile,"w"); /* Open output file */
3933 if (!ofp) {
3934 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
3935 ofp = stdout;
3936 return(-9);
3937 }
3938 }
3939 number = z;
3940 if (number && prefix) prefix = NULL;
3941
3942 #ifdef UNICODE
3943 ucsbom_sav = ucsbom; /* We are not creating a file */
3944 ucsbom = 0; /* Do not use BOM bytes */
3945 #endif /* UNICODE */
3946
3947 typ_int = 0;
3948
3949 save = binary; /* Save file type */
3950
3951 debug(F101,"dotype incs","",incs);
3952 debug(F101,"dotype outcs","",outcs);
3953
3954 #ifdef UNICODE
3955 debug(F111,"dotype fileorder","A",fileorder);
3956 #ifdef OS2
3957 if (!inserver && !k95stdout)
3958 outcs = FC_UCS2;
3959 #endif /* OS2 */
3960
3961 if (outcs == FC_UCS2) /* Output is UCS-2? */
3962 ucs2 = 1;
3963 if (fileorder < 0)
3964 fileorder = ucsorder;
3965 debug(F111,"dotype fileorder","B",fileorder);
3966 #endif /* UNICODE */
3967
3968 #ifdef CK_TTGWSIZ
3969 #ifdef OS2
3970 ttgcwsz();
3971 #else /* OS2 */
3972 /* Check whether window size changed */
3973 if (ttgwsiz() > 0) {
3974 if (tt_rows > 0 && tt_cols > 0) {
3975 cmd_rows = tt_rows;
3976 cmd_cols = tt_cols;
3977 debug(F101,"dotype cmd_rows","",cmd_rows);
3978 debug(F101,"dotype cmd_cols","",cmd_cols);
3979 }
3980 }
3981 #endif /* OS2 */
3982 #endif /* CK_TTGWSIZ */
3983
3984 if (prefix)
3985 pfxlen = strlen(prefix);
3986
3987 if (paging < 0) { /* Count only, don't print */
3988 counting = 1;
3989 prefix = NULL;
3990 width = 0;
3991 paging = 0;
3992 }
3993 if (ucs2) /* Crude... */
3994 width *= 2;
3995
3996 #ifdef OS2
3997 if (*file) {
3998 ckstrncpy(buf, file, TYPBUFL); /* Change / to \. */
3999 p = buf;
4000 while (*p) {
4001 if (*p == '/') *p = '\\';
4002 p++;
4003 }
4004 file = buf;
4005 } else {
4006 rc = 0;
4007 goto xdotype;
4008 }
4009 #endif /* OS2 */
4010
4011 if (zchki(file) == -2) { /* It's a directory */
4012 debug(F111,"dotype zchki failure",file,-2);
4013 if (xcmdsrc == 0) {
4014 printf("?Not a regular file: \"%s\"\n",file);
4015 rc = -9;
4016 } else
4017 rc = 0;
4018 goto xdotype;
4019 }
4020 if (!zopeni(ZIFILE, file)) { /* Not a directory, open it */
4021 debug(F111,"dotype zopeni failure",file,0);
4022 if (xcmdsrc == 0) {
4023 printf("?Can't open file: \"%s\"\n",file);
4024 rc = -9;
4025 } else
4026 rc = 0;
4027 goto xdotype;
4028 }
4029
4030 #ifndef AMIGA
4031 #ifndef MAC
4032 errno = 0;
4033 oldsig = signal(SIGINT, tytrap); /* Save current interrupt trap. */
4034 /* debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig); */
4035 #endif /* MAC */
4036 #endif /* AMIGA */
4037
4038 if (paging > -1) /* More-prompting */
4039 xaskmore = paging;
4040
4041 binary = 0;
4042
4043 if (head < 0) { /* "tail" was requested */
4044 tailing = 1; /* Set flag */
4045 head = 0 - head; /* Get absolute number of lines */
4046 if (!counting) {
4047 tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
4048 if (!tail) {
4049 printf("?Memory allocation failure\n");
4050 goto xdotype;
4051
4052 }
4053 tlen = (int *) malloc(head * sizeof(int));
4054 if (!tlen) {
4055 printf("?Memory allocation failure\n");
4056 goto xdotype;
4057
4058 }
4059 for (i = 0; i < head; i++) { /* Initialize each pointer in list. */
4060 tail[i] = NULL;
4061 tlen[i] = 0;
4062 }
4063 }
4064 }
4065 typ_lines = 0;
4066 typ_mtchs = 0;
4067
4068 #ifdef UNICODE
4069 if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */
4070 ffc = (CK_OFF_T)0;
4071 initxlate(incs,outcs); /* Set up translation functions */
4072 } else
4073 #endif /* UNICODE */
4074 outcs = -1; /* Means we don't know the charset */
4075
4076 debug(F101,"dotype ffc","",ffc);
4077 debug(F101,"dotype outcs 2","",outcs);
4078 #ifdef UNICODE
4079 debug(F111,"dotype fileorder","C",fileorder);
4080 #endif /* UNICODE */
4081
4082 /* Allow the buffer to contain NULs */
4083
4084 for (n = first;
4085 (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1;
4086 lines++
4087 ) {
4088 debug(F011,"dotype line",buf,len);
4089 #ifndef MAC
4090 if (typ_int) { /* Interrupted? */
4091 typ_int = 0;
4092 debug(F101,"type interrupted line","",lines);
4093 printf("^C...\n"); /* Print message */
4094 if (ofp != stdout) { /* Close any output file */
4095 if (ofp) fclose(ofp);
4096 ofp = stdout;
4097 }
4098 goto xxdotype;
4099 }
4100 #endif /* MAC */
4101 typ_lines++; /* For \v(ty_ln) */
4102 if (pat) /* Matching? */
4103 if (!ckmatch(pat,buf,1,1+4)) /* Line matches pattern? */
4104 continue; /* No, skip it */
4105 typ_mtchs++;
4106
4107 if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
4108 break;
4109
4110 buf[TYPBUFL+1] = NUL; /* Just in case... */
4111 if (prefix) { /* Add specified prefix to each line */
4112 char pbuf[64];
4113 char * pp;
4114 pp = prefix;
4115 #ifndef NOSPL
4116 if (evalpfx) { /* Prefix is a variable? */
4117 int n = 63; /* Maybe - evaluate it and see */
4118 char * p = pbuf;
4119 zzstring(prefix,&p,&n); /* If there is no change */
4120 if (!strcmp(prefix,pbuf)) { /* it's not a variable */
4121 evalpfx = 0; /* So don't do this again. */
4122 } else { /* It was a variable */
4123 pp = pbuf; /* So substitute its value */
4124 pfxlen = 63 - n; /* and get its new length */
4125 }
4126 }
4127 #endif /* NOSPL */
4128 if (len + pfxlen + 2 < TYPBUFL) {
4129 /* Shift right to make room for prefix */
4130 memcpy((char *)line+pfxlen,(char *)buf,len);
4131 lset((char *)line,pp,pfxlen,SP);
4132 debug(F110,"dotype prefix",line,pfxlen);
4133 len += pfxlen;
4134 memcpy((char *)buf,(char *)line,len);
4135 }
4136 } else if (number) { /* Line numbers */
4137 int x;
4138 sprintf(line,"%4d. ",typ_lines);
4139 x = strlen(line);
4140 len += x;
4141 if (len < LINBUFSIZ) {
4142 memcpy((char *)&line[x],(char *)buf,len);
4143 memcpy((char *)buf,(char *)line,len);
4144 }
4145 }
4146 if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
4147 char * obuf = line; /* But to do that first we must */
4148 int i,k,z; /* expand tabs; assume every 8 cols. */
4149 line[0] = NUL;
4150 for (i = 0, k = 0; i < width; k++) { /* Character loop... */
4151 if (!buf[k]) /* No more chars in this line, done. */
4152 break;
4153 if (buf[k] != '\t') { /* If it's not a tab */
4154 if (i >= LINBUFSIZ) /* Check for overflow */
4155 break;
4156 obuf[i++] = buf[k]; /* and then deposit it. */
4157 obuf[i] = NUL; /* Keep it null-terminated */
4158 continue;
4159 }
4160 z = 8 - (i % 8); /* It's a tab, expand it. */
4161 if (z == 0) z = 8;
4162 for (j = 0; j < z && i < LINBUFSIZ; j++) {
4163 #ifdef UNICODE
4164 if (ucs2 && !ucsorder)
4165 obuf[i++] = NUL;
4166 #endif /* UNICODE */
4167 obuf[i++] = ' ';
4168 #ifdef UNICODE
4169 if (ucs2 && ucsorder)
4170 obuf[i++] = NUL;
4171 #endif /* UNICODE */
4172 }
4173 obuf[i++] = NUL;
4174 obuf[i] = NUL;
4175 }
4176 obuf[width] = NUL; /* Now truncate at given width. */
4177 #ifdef COMMENT
4178 /* This doesn't work for UCS-2 because it contains NULs */
4179 ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
4180 #else
4181 memcpy((char *)buf,(char *)obuf,i); /* Copy it back */
4182 #endif /* COMMENT */
4183 len = (i > width) ? width : i; /* Spare us another strlen()... */
4184 }
4185 if (tailing) { /* If /TAIL:n... */
4186 k = lines % head; /* save this line in circular buffer */
4187 if (!counting) {
4188 if (tail[k]) free(tail[k]);
4189 tail[k] = malloc(len+2);
4190 if (!tail[k]) {
4191 printf("?Memory allocation failure\n");
4192 goto xdotype;
4193 }
4194 memcpy(tail[k],buf,len);
4195 tlen[k] = len;
4196 continue;
4197 }
4198 }
4199 if (counting) /* If only counting */
4200 continue; /* we're done with this line */
4201
4202 if (paging) { /* Displaying this line... */
4203 int u;
4204 u = len; /* Length in BYTES */
4205 if (ucs2) /* If outputting in UCS-2 */
4206 u /= 2; /* convert length to CHARACTERS */
4207 x = (u / cmd_cols) + 1; /* Crudely allow for wrap */
4208 if (cmd_rows > 0 && cmd_cols > 0)
4209 n += x; /* This assumes terminal will wrap */
4210 }
4211 #ifdef KUI
4212 if ( gui ) {
4213 int i;
4214 unsigned short * uch = (unsigned short *)buf;
4215 for ( i=0; i<len/2; i++)
4216 gui_text_popup_append(uch[i]);
4217 gui_text_popup_append(CR);
4218 gui_text_popup_append(LF);
4219 }
4220 else
4221 #endif /* KUI */
4222 typeline(buf,len,outcs,ofp); /* Print line, length based */
4223 #ifdef CK_TTGWSIZ
4224 debug(F101,"dotype n","",n);
4225 if (paging > 0 && ofp == stdout) { /* Pause at end of screen */
4226 if (cmd_rows > 0 && cmd_cols > 0) {
4227 if (n > cmd_rows - 3) {
4228 if (!askmore())
4229 goto xdotype;
4230 else
4231 n = 0;
4232 }
4233 }
4234 }
4235 #endif /* CK_TTGWSIZ */
4236 }
4237
4238 xdotype:
4239 if (counting) {
4240 fprintf(ofp,
4241 "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
4242 if (pat)
4243 fprintf(ofp,
4244 "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
4245 goto xxdotype;
4246 }
4247 if (tailing && tail) { /* Typing tail of file? */
4248 if (lines < head) { /* Yes, show the lines we saved */
4249 k = 0; /* Show all lines */
4250 } else { /* More lines than tail number */
4251 lines = k; /* Last line to show */
4252 k++; /* First line to show */
4253 if (k >= head)
4254 k = 0;
4255 }
4256 n = first; /* Output line counter */
4257 for (i = k ;; i++) { /* Loop thru circular buffer */
4258 #ifndef MAC
4259 if (typ_int) { /* Interrupted? */
4260 printf("^C...\n"); /* Print message */
4261 goto xxdotype;
4262 }
4263 #endif /* MAC */
4264 j = i % head; /* Index of this line */
4265 s = tail[j]; /* Point to line to display */
4266 if (!s) /* (shouldn't happen...) */
4267 break;
4268 if (paging) { /* Crudely allow for line wrap */
4269 x = tlen[j];
4270 if (ucs2) x /= 2;
4271 x = x / cmd_cols + 1;
4272 if (cmd_rows > 0 && cmd_cols > 0)
4273 n += x;
4274 }
4275 typeline(s,tlen[j],outcs,ofp); /* Display this line */
4276 if (paging && ofp == stdout) { /* Pause at end of screen */
4277 if (cmd_rows > 0 && cmd_cols > 0) {
4278 if (n > cmd_rows - 3) {
4279 if (!askmore())
4280 break;
4281 else
4282 n = 0;
4283 }
4284 }
4285 }
4286 tail[j] = NULL;
4287 free(s); /* Free the line */
4288 if (i % head == lines) /* When to stop */
4289 break;
4290 }
4291 free((char *)tail); /* Free the list */
4292 tail = NULL;
4293 if (tlen) free((char *)tlen);
4294 tlen = NULL;
4295 }
4296
4297 /* Come here when finished or on SIGINT */
4298
4299 xxdotype:
4300 #ifndef AMIGA
4301 #ifndef MAC
4302 signal(SIGINT,oldsig); /* Put old signal action back. */
4303 #endif /* MAC */
4304 #endif /* AMIGA */
4305 if (tailing && tail) {
4306 for (i = 0; i < head; i++) { /* Free each line. */
4307 if (tail[i])
4308 free(tail[i]);
4309 }
4310 free((char *)tail); /* Free list pointer */
4311 if (tlen)
4312 free((char *)tlen);
4313 }
4314 x = zclose(ZIFILE); /* Done, close the input file */
4315 if (ofp != stdout) { /* Close any output file */
4316 if (ofp) fclose(ofp);
4317 ofp = stdout;
4318 }
4319 binary = save; /* Restore text/binary mode */
4320 #ifdef UNICODE
4321 ucsbom = ucsbom_sav; /* Restore BOM usage */
4322 #endif /* UNICODE */
4323
4324 #ifdef KUI
4325 if ( gui )
4326 gui_text_popup_wait(-1); /* Wait for user to close the dialog */
4327 #endif /* KUI */
4328 return(rc);
4329 }
4330
4331 /* GREP command */
4332
4333 #define GREP_CASE 0 /* /CASE */
4334 #define GREP_COUN 1 /* /COUNT */
4335 #define GREP_DOTF 2 /* /DOTFILES */
4336 #define GREP_NAME 3 /* /NAMEONLY */
4337 #define GREP_NOBK 4 /* /NOBACKUP */
4338 #define GREP_NODO 5 /* /NODOTFILES */
4339 #define GREP_NOLI 6 /* /NOLIST */
4340 #define GREP_NOMA 7 /* /INVERT = /NOMATCH */
4341 #define GREP_NOPA 8 /* /NOPAGE */
4342 #define GREP_NUMS 9 /* /LINENUMBERS */
4343 #define GREP_PAGE 10 /* /PAGE */
4344 #define GREP_RECU 11 /* /RECURSIVE */
4345 #define GREP_TYPE 12 /* /TYPE: */
4346 #define GREP_OUTP 13 /* /OUTPUTFILE: */
4347 #define GREP_EXCP 14 /* /EXCEPT: */
4348 #define GREP_ARRA 15 /* /ARRAY: */
4349
4350 static struct keytab greptab[] = {
4351 { "/array", GREP_ARRA, CM_ARG },
4352 { "/count", GREP_COUN, CM_ARG },
4353 { "/dotfiles", GREP_DOTF, 0 },
4354 { "/except", GREP_EXCP, CM_ARG },
4355 { "/linenumbers", GREP_NUMS, 0 },
4356 { "/nameonly", GREP_NAME, 0 },
4357 { "/nobackupfiles",GREP_NOBK, 0 },
4358 { "/nocase", GREP_CASE, 0 },
4359 { "/nodotfiles", GREP_NODO, 0 },
4360 { "/nolist", GREP_NOLI, 0 },
4361 { "/nomatch", GREP_NOMA, 0 },
4362 { "/nopage", GREP_NOPA, 0 },
4363 { "/output", GREP_OUTP, CM_ARG },
4364 { "/page", GREP_PAGE, 0 },
4365 { "/quiet", GREP_NOLI, CM_INV },
4366 #ifdef RECURSIVE
4367 { "/recursive", GREP_RECU, 0 },
4368 #endif /* RECURSIVE */
4369 { "/type", GREP_TYPE, CM_ARG },
4370 { "", 0, 0 }
4371 };
4372 static int ngreptab = sizeof(greptab)/sizeof(struct keytab)-1;
4373
4374 static char * grep_except = NULL;
4375
4376 int
dogrep()4377 dogrep() {
4378 int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0;
4379 int fline = 0, sline = 0, wild = 0, len = 0;
4380 int xmode = -1, scan = 0;
4381 char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
4382 FILE * fp = NULL;
4383 #ifndef NOSPL
4384 char array = NUL;
4385 char ** ap = NULL;
4386 int arrayindex = 0;
4387 #endif /* NOSPL */
4388
4389 int /* Switch values and defaults */
4390 gr_coun = 0,
4391 gr_name = 0,
4392 gr_nobk = 0,
4393 gr_case = 1,
4394 gr_noli = 0,
4395 gr_noma = 0,
4396 gr_nums = 0,
4397 gr_excp = 0,
4398 gr_page = xaskmore;
4399
4400 struct FDB sw, fl;
4401
4402 g_matchdot = matchdot; /* Save global matchdot setting */
4403 outfile[0] = NUL;
4404 makestr(&grep_except,NULL);
4405
4406 if (ofp != stdout) { /* In case of previous interruption */
4407 if (ofp) fclose(ofp);
4408 ofp = stdout;
4409 }
4410 cmfdbi(&sw, /* First FDB - command switches */
4411 _CMKEY, /* fcode */
4412 "String or pattern to search for, or switch",
4413 "", /* default */
4414 "", /* addtl string data */
4415 ngreptab, /* addtl numeric data 1: tbl size */
4416 4, /* addtl numeric data 2: 4 = cmswi */
4417 xxstring, /* Processing function */
4418 greptab, /* Keyword table */
4419 &fl /* Pointer to next FDB */
4420 );
4421 cmfdbi(&fl, /* Anything that doesn't match */
4422 _CMFLD, /* fcode */
4423 "", /* hlpmsg */
4424 "", /* default */
4425 "", /* addtl string data */
4426 0, /* addtl numeric data 1 */
4427 0, /* addtl numeric data 2 */
4428 xxstring, /* xxstring */
4429 NULL,
4430 NULL
4431 );
4432 while (1) { /* Parse 0 or more switches */
4433 x = cmfdb(&sw); /* Parse something */
4434 if (x < 0)
4435 return(x);
4436 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
4437 break;
4438 c = cmgbrk();
4439 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4440 printf("?This switch does not take an argument\n");
4441 return(-9);
4442 }
4443 if ((cmresult.nresult != GREP_COUN) && !getval &&
4444 (cmgkwflgs() & CM_ARG)) {
4445 printf("?This switch requires an argument\n");
4446 return(-9);
4447 }
4448 switch (cmresult.nresult) {
4449 case GREP_COUN: {
4450 gr_coun++;
4451 if (getval) {
4452 if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
4453 return(x);
4454 makestr(&cv,s);
4455 }
4456 break;
4457 }
4458 case GREP_CASE: gr_case=0; break;
4459 case GREP_NAME: gr_name++; gr_noli=0; break;
4460 case GREP_NOBK: gr_nobk++; break;
4461 case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break;
4462 case GREP_NOMA: gr_noma++; break;
4463 case GREP_NOPA: gr_page=0; break;
4464 case GREP_NUMS: gr_nums++; gr_noli=0; break;
4465 case GREP_PAGE: gr_page++; gr_noli=0; break;
4466 case GREP_NODO:
4467 matchdot = 0;
4468 break;
4469 case GREP_DOTF:
4470 matchdot = 1;
4471 break;
4472 case GREP_ARRA: {
4473 char * s2;
4474 if (c != ':' && c != '=') {
4475 printf("?Array name required\n");
4476 return(-9);
4477 }
4478 if ((x = cmfld("Array name (a single letter will do)",
4479 "",
4480 &s,
4481 NULL
4482 )) < 0) {
4483 if (x == -3) {
4484 printf("?Array name required\n");
4485 return(-9);
4486 } else
4487 return(x);
4488 }
4489 if (!*s) {
4490 printf("?Array name required\n");
4491 return(-9);
4492 }
4493 s2 = s;
4494 if (*s == CMDQ) s++;
4495 if (*s == '&') s++;
4496 if (!isalpha(*s)) {
4497 printf("?Bad array name - \"%s\"\n",s2);
4498 return(-9);
4499 }
4500 array = *s++;
4501 if (isupper(array)) array = tolower(array);
4502 if (*s && (*s != '[' || *(s+1) != ']')) {
4503 printf("?Bad array name - \"%s\"\n",s2);
4504 return(-9);
4505 }
4506 gr_name = 1;
4507 break;
4508 }
4509 #ifdef RECURSIVE
4510 case GREP_RECU:
4511 recursive = 1;
4512 break;
4513 #endif /* RECURSIVE */
4514 case GREP_TYPE: {
4515 extern struct keytab txtbin[];
4516 if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
4517 return(x);
4518 if (x == 2) { /* ALL */
4519 xmode = -1;
4520 } else { /* TEXT or BINARY only */
4521 xmode = x;
4522 scan = 1;
4523 }
4524 break;
4525 }
4526 case GREP_OUTP: /* Send output to file */
4527 if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0)
4528 return(x);
4529 ckstrncpy(outfile,s,CKMAXPATH);
4530 break;
4531 case GREP_EXCP: /* Exception pattern */
4532 if (getval) {
4533 if ((x = cmfld("Exception pattern",
4534 "",
4535 &s,
4536 xxstring
4537 )) < 0)
4538 return(x);
4539 gr_excp++;
4540 makestr(&grep_except,s);
4541 }
4542 }
4543 }
4544 if (outfile[0]) {
4545 ofp = fopen(outfile,"w"); /* Open output file */
4546 if (!ofp) {
4547 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
4548 ofp = stdout;
4549 return(-9);
4550 }
4551 gr_page = 0;
4552 }
4553 s = cmresult.sresult;
4554 s = brstrip(s); /* Strip braces from pattern */
4555 if (!*s) {
4556 printf("?Pattern required\n");
4557 return(-9);
4558 }
4559 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save pattern */
4560 if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) {
4561 if (x == -3) {
4562 printf("?File specification required\n");
4563 x = -9;
4564 }
4565 return(x);
4566 }
4567 s = brstrip(s); /* Strip braces from filename */
4568 #ifndef ZXREWIND
4569 ckstrncpy(line,s,LINBUFSIZ);
4570 #endif /* ZXREWIND */
4571 if ((y = cmcfm()) < 0)
4572 return(y);
4573
4574 if (gr_page > -1)
4575 xaskmore = gr_page; /* Paging... */
4576
4577 p = tmpbuf; /* Point to pattern */
4578 #ifdef COMMENT
4579 /* Now this is done in ckmatch */
4580 if (*p == '^') { /* '^' anchors pattern to beginning */
4581 p++;
4582 } else if (*p != '*') { /* Otherwise prepend implied '*' */
4583 tmpbuf[0] = '*';
4584 p = tmpbuf;
4585 }
4586 x = strlen(p); /* Get length of result */
4587 if (x > 0 && x < TMPBUFSIZ) { /* '$' at end anchors pattern to end */
4588 if (p[x-1] == '$') {
4589 p[x-1] = NUL;
4590 } else if (p[x-1] != '*') {
4591 p[x] = '*';
4592 p[x+1] = NUL;
4593 }
4594 }
4595 #endif /* COMMENT */
4596 debug(F111,"grep pat",p,x);
4597
4598 #ifdef ZXREWIND
4599 fc = zxrewind(); /* Rewind the file list */
4600 #else
4601 {
4602 int flags = ZX_FILONLY; /* Expand file list */
4603 if (matchdot) flags |= ZX_MATCHDOT;
4604 if (recursive) flags |= ZX_RECURSE;
4605 fc = nzxpand(line,flags);
4606 }
4607 #endif /* ZXREWIND */
4608
4609 #ifndef NOSPL
4610 if (array) {
4611 int n, xx;
4612 n = (fc < 0) ? 0 : fc;
4613 if ((xx = dclarray(array,n)) < 0) {
4614 printf("?Array declaration failure\n");
4615 mc = 0;
4616 goto xgrep;
4617 }
4618 arrayindex = 0;
4619 ap = a_ptr[xx]; /* Pointer to list of elements */
4620 if (ap) /* Set element 0 to dimension */
4621 makestr(&(ap[0]),"0"); /* which so far is zero */
4622 if (n < 1) { /* No files matched, done. */
4623 mc = 0;
4624 goto xgrep;
4625 }
4626 }
4627 #endif /* NOSPL */
4628
4629 #ifdef UNIX
4630 sh_sort(mtchs,NULL,fc,0,0,filecase);
4631 #endif /* UNIX */
4632
4633 debug(F101,"grep cmd_rows","",cmd_rows);
4634 debug(F101,"grep cmd_cols","",cmd_cols);
4635
4636 while (1) { /* Loop for each file */
4637 znext(name); /* Get next file */
4638 if (!name[0]) /* No more, done */
4639 break;
4640 if (gr_nobk) /* Skipping backup files? */
4641 if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */
4642 continue; /* Yes, skip */
4643 if (scan) { /* /TYPE: given? */
4644 switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */
4645 case FT_BIN:
4646 if (xmode != 1)
4647 continue;
4648 break;
4649 case FT_TEXT:
4650 case FT_7BIT:
4651 case FT_8BIT:
4652 #ifdef UNICODE
4653 case FT_UTF8:
4654 case FT_UCS2:
4655 #endif /* UNICODE */
4656 if (xmode != 0)
4657 continue;
4658 }
4659 }
4660 fp = fopen(name,"r"); /* Open */
4661 if (!fp) /* Can't */
4662 continue; /* Skip */
4663 count = 0; /* Match count, this file */
4664 fline = 0; /* Line count, this file */
4665 while (1) { /* Loop for each line */
4666 if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */
4667 fclose(fp);
4668 fp = NULL;
4669 debug(F100,"GREP EOF","",0);
4670 break;
4671 }
4672 fline++; /* Count this line */
4673 line[LINBUFSIZ] = NUL; /* Make sure it's terminated */
4674 debug(F111,"GREP",line,fline);
4675 len = (int)strlen(line); /* Get length */
4676 while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
4677 line[--len] = NUL; /* Chop off terminators */
4678 match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
4679 if (match && gr_excp) {
4680 if (ckmatch(grep_except,line,gr_case,1+4))
4681 match = 0;
4682 }
4683 if (gr_noma) /* Invert match sense if requested */
4684 match = !match;
4685 if (match) { /* Have a matching line */
4686 mc++; /* Total match count */
4687 count++; /* Match count this file */
4688 if (gr_name) { /* Don't care how many lines match */
4689 fclose(fp); /* Close the file */
4690 fp = NULL; /* and quit the line-reading loop. */
4691 break;
4692 }
4693 if (gr_coun || gr_noli) /* Not listing each line */
4694 continue; /* so don't print anything now. */
4695 if (wild) { /* If searching multiple files */
4696 fprintf(ofp,"%s:",name); /* print filename. */
4697 len += (int)strlen(name) + 1;
4698 }
4699 if (gr_nums) { /* If line numbers wanted */
4700 char nbuf[32];
4701 len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
4702 fprintf(ofp,"%s",nbuf);
4703 }
4704 if (cmd_rows > 0 && cmd_cols > 0)
4705 sline += (len / cmd_cols) + 1;
4706 fprintf(ofp,"%s\n",line); /* Print the line. */
4707 if (sline > cmd_rows - 3) {
4708 if (!askmore()) goto xgrep; else sline = 0;
4709 }
4710 }
4711 }
4712 if (!gr_noli) { /* If not not listing... */
4713 x = 0;
4714 if (gr_coun) { /* Show match count only */
4715 fprintf(ofp,"%s:%d\n",name,count);
4716 x++;
4717 } else if (gr_name && count > 0) { /* Show name only */
4718 if (array) {
4719 if (ap) {
4720 makestr(&(ap[arrayindex++]),name);
4721 }
4722 } else {
4723 fprintf(ofp,"%s\n",name);
4724 x++;
4725 }
4726 }
4727 if (x > 0) {
4728 if (++sline > cmd_rows - 3) {
4729 if (!askmore()) goto xgrep; else sline = 0;
4730 }
4731 }
4732 }
4733 bigcount += count; /* Overall count */
4734 }
4735 xgrep:
4736 #ifndef NOSPL
4737 if (array) if (ap) makestr(&(ap[0]),ckitoa(arrayindex));
4738 if (gr_coun && cv) { /* /COUNT:blah */
4739 addmac(cv,ckitoa(bigcount)); /* set the variable */
4740 makestr(&cv,NULL); /* free this */
4741 }
4742 #endif /* NOSPL */
4743 if (fp) fclose(fp); /* close input file if still open */
4744 if (ofp != stdout) { /* Close any output file */
4745 if (ofp) fclose(ofp);
4746 ofp = stdout;
4747 }
4748 return(success = mc ? 1 : 0);
4749 }
4750
4751 /* System-independent directory */
4752
4753 static char ** dirlist = NULL;
4754 static int ndirlist = 0;
4755
4756 static VOID
freedirlist()4757 freedirlist() {
4758 if (dirlist) {
4759 int i;
4760 for (i = 0; i < ndirlist; i++) {
4761 if (dirlist[i])
4762 free(dirlist[i]);
4763 }
4764 free((char *)dirlist);
4765 dirlist = NULL;
4766 }
4767 ndirlist = 0;
4768 }
4769
4770 static struct keytab dirswtab[] = { /* DIRECTORY command switches */
4771 { "/after", DIR_AFT, CM_ARG },
4772 { "/all", DIR_ALL, 0 },
4773 #ifndef NOSPL
4774 { "/array", DIR_ARR, CM_ARG },
4775 #endif /* NOSPL */
4776 { "/ascending", DIR_ASC, 0 },
4777 { "/backup", DIR_BUP, 0 },
4778 { "/before", DIR_BEF, CM_ARG },
4779 { "/brief", DIR_BRF, 0 },
4780 { "/count", DIR_COU, CM_ARG },
4781 { "/descending", DIR_DSC, CM_INV },
4782 { "/directories", DIR_DIR, 0 },
4783 { "/dotfiles", DIR_DOT, 0 },
4784 { "/englishdate", DIR_DAT, 0 },
4785 { "/except", DIR_EXC, CM_ARG },
4786 { "/files", DIR_FIL, 0 },
4787 #ifdef CKSYMLINK
4788 { "/followlinks", DIR_LNK, 0 },
4789 #endif /* CKSYMLINK */
4790 { "/heading", DIR_HDG, 0 },
4791 { "/isodate", DIR_ISO, 0 },
4792 { "/larger-than", DIR_LAR, CM_ARG },
4793 { "/message", DIR_MSG, CM_ARG },
4794 { "/nobackupfiles",DIR_NOB, 0 },
4795 { "/nodotfiles", DIR_NOD, 0 },
4796 #ifdef CKSYMLINK
4797 { "/nofollowlinks",DIR_NLK, 0 },
4798 #endif /* CKSYMLINK */
4799 { "/noheading", DIR_NOH, 0 },
4800 #ifdef CKSYMLINK
4801 { "/nolinks", DIR_NOL, 0 },
4802 #endif /* CKSYMLINK */
4803 { "/nomessage", DIR_NOM, 0 },
4804 #ifdef CK_TTGWSIZ
4805 { "/nopage", DIR_NOP, 0 },
4806 #endif /* CK_TTGWSIZ */
4807 #ifdef RECURSIVE
4808 { "/norecursive", DIR_NOR, 0 },
4809 #else
4810 #ifdef VMS
4811 { "/norecursive", DIR_NOR, 0 },
4812 #else
4813 #ifdef datageneral
4814 { "/norecursive", DIR_NOR, 0 },
4815 #endif /* datageneral */
4816 #endif /* VMS */
4817 #endif /* RECURSIVE */
4818 { "/nosort", DIR_NOS, 0 },
4819 { "/not-after", DIR_NAF, CM_ARG },
4820 { "/not-before", DIR_NBF, CM_ARG },
4821 { "/not-since", DIR_NAF, CM_INV|CM_ARG },
4822 { "/noxfermode", DIR_NOT, 0 },
4823 { "/output", DIR_OUT, CM_ARG },
4824 #ifdef CK_TTGWSIZ
4825 { "/page", DIR_PAG, 0 },
4826 #endif /* CK_TTGWSIZ */
4827 #ifdef RECURSIVE
4828 { "/recursive", DIR_REC, 0 },
4829 #else
4830 #ifdef VMS
4831 { "/recursive", DIR_REC, 0 },
4832 #else
4833 #ifdef datageneral
4834 { "/recursive", DIR_REC, 0 },
4835 #endif /* datageneral */
4836 #endif /* VMS */
4837 #endif /* RECURSIVE */
4838 { "/reverse", DIR_DSC, 0 },
4839 { "/since", DIR_AFT, CM_ARG|CM_INV },
4840 { "/smaller-than",DIR_SMA, CM_ARG },
4841 { "/sort", DIR_SRT, CM_ARG },
4842 { "/summary", DIR_SUM, 0 },
4843 { "/top", DIR_TOP, CM_ARG },
4844 { "/type", DIR_BIN, CM_ARG },
4845 { "/xfermode", DIR_TYP, 0 },
4846 { "/verbose", DIR_VRB, 0 },
4847 { "",0,0 }
4848 };
4849 static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
4850
4851 static struct keytab dirsort[] = { /* DIRECTORY /SORT: options */
4852 { "date", DIRS_DT, 0 },
4853 { "name", DIRS_NM, 0 },
4854 { "size", DIRS_SZ, 0 }
4855 };
4856 static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
4857
4858 static struct keytab touchswtab[] = { /* TOUCH command switches */
4859 { "/after", DIR_AFT, CM_ARG },
4860 { "/all", DIR_ALL, 0 },
4861 { "/backup", DIR_BUP, 0 },
4862 { "/before", DIR_BEF, CM_ARG },
4863 { "/count", DIR_COU, CM_ARG },
4864 { "/directories", DIR_DIR, 0 },
4865 { "/dotfiles", DIR_DOT, 0 },
4866 { "/except", DIR_EXC, CM_ARG },
4867 { "/files", DIR_FIL, 0 },
4868 #ifdef CKSYMLINK
4869 { "/followlinks", DIR_LNK, 0 },
4870 #endif /* CKSYMLINK */
4871 { "/larger-than", DIR_LAR, CM_ARG },
4872 { "/list", DIR_VRB, 0 },
4873 { "/modtime", DIR_MOD, CM_ARG },
4874 { "/nobackupfiles",DIR_NOB, 0 },
4875 { "/nodotfiles", DIR_NOD, 0 },
4876 #ifdef CKSYMLINK
4877 { "/nofollowlinks",DIR_NLK, 0 },
4878 #endif /* CKSYMLINK */
4879 #ifdef CKSYMLINK
4880 { "/nolinks", DIR_NOL, 0 },
4881 #endif /* CKSYMLINK */
4882 #ifdef CK_TTGWSIZ
4883 #endif /* CK_TTGWSIZ */
4884 #ifdef RECURSIVE
4885 { "/norecursive", DIR_NOR, 0 },
4886 #else
4887 #ifdef VMS
4888 { "/norecursive", DIR_NOR, 0 },
4889 #else
4890 #ifdef datageneral
4891 { "/norecursive", DIR_NOR, 0 },
4892 #endif /* datageneral */
4893 #endif /* VMS */
4894 #endif /* RECURSIVE */
4895 { "/not-after", DIR_NAF, CM_ARG },
4896 { "/not-before", DIR_NBF, CM_ARG },
4897 { "/not-since", DIR_NAF, CM_INV|CM_ARG },
4898 #ifdef RECURSIVE
4899 { "/recursive", DIR_REC, 0 },
4900 #else
4901 #ifdef VMS
4902 { "/recursive", DIR_REC, 0 },
4903 #else
4904 #ifdef datageneral
4905 { "/recursive", DIR_REC, 0 },
4906 #endif /* datageneral */
4907 #endif /* VMS */
4908 #endif /* RECURSIVE */
4909 { "/simulate", DIR_SIM, 0 },
4910 { "/since", DIR_AFT, CM_ARG|CM_INV },
4911 { "/smaller-than",DIR_SMA, CM_ARG },
4912 { "/type", DIR_BIN, CM_ARG },
4913 { "/verbose", DIR_VRB, CM_INV },
4914 { "",0,0 }
4915 };
4916 static int ntouchswtab = (sizeof(touchswtab) / sizeof(struct keytab)) - 1;
4917
4918 static struct keytab changeswtab[] = { /* CHANGE command switches */
4919 { "/after", DIR_AFT, CM_ARG },
4920 { "/backup", DIR_BAK, CM_ARG },
4921 { "/before", DIR_BEF, CM_ARG },
4922 { "/case", 7777, CM_ARG },
4923 { "/count", DIR_COU, CM_ARG },
4924 { "/destination", DIR_DES, CM_ARG },
4925 { "/dotfiles", DIR_DOT, 0 },
4926 { "/except", DIR_EXC, CM_ARG },
4927 { "/larger-than", DIR_LAR, CM_ARG },
4928 { "/list", DIR_VRB, 0 },
4929 { "/modtime", DIR_MOD, CM_ARG },
4930 { "/nodotfiles", DIR_NOD, 0 },
4931 #ifdef RECURSIVE
4932 { "/norecursive", DIR_NOR, 0 },
4933 #endif /* RECURSIVE */
4934 { "/not-after", DIR_NAF, CM_ARG },
4935 { "/not-before", DIR_NBF, CM_ARG },
4936 { "/not-since", DIR_NAF, CM_INV|CM_ARG },
4937 #ifdef RECURSIVE
4938 { "/recursive", DIR_REC, 0 },
4939 #endif /* RECURSIVE */
4940 { "/simulate", DIR_SIM, 0 },
4941 { "/since", DIR_AFT, CM_ARG|CM_INV },
4942 { "/smaller-than",DIR_SMA, CM_ARG },
4943 { "/verbose", DIR_VRB, CM_INV },
4944 { "",0,0 }
4945 };
4946 static int nchangeswtab = (sizeof(changeswtab) / sizeof(struct keytab)) - 1;
4947
4948 #define CHMT_U 0 /* CHANGE command modtime options */
4949 #define CHMT_P 1
4950
4951 static struct keytab chmttab[] = {
4952 { "preserve", CHMT_P, 0 },
4953 { "update", CHMT_U, 0 }
4954 };
4955 static int nchmttab = 2;
4956
4957 static int dir_date = -1; /* Option defaults (-1 means none) */
4958 static int dir_page = -1;
4959 static int dir_verb = 1;
4960 static int dir_msg = -1;
4961 #ifdef VMS
4962 static int dir_sort = -1; /* Names are already sorted in VMS */
4963 static int dir_rvrs = -1;
4964 #else
4965 static int dir_sort = 1; /* Sort by default */
4966 static int dir_rvrs = 0; /* Not in reverse */
4967 #endif /* VMS */
4968 static int dir_skey = DIRS_NM; /* By name */
4969 #ifdef RECURSIVE
4970 static int dir_recu = -1;
4971 #endif /* RECURSIVE */
4972 static int dir_mode = -1;
4973 static int dir_show = -1; /* Show all files by default */
4974 int dir_dots = -1; /* Except dot files */
4975 int dir_back = 1;
4976 int dir_head = 0;
4977 static char * dirmsg = NULL;
4978 static int dirmsglen = 0;
4979
4980 #ifndef NOSHOW
4981 VOID
showdiropts()4982 showdiropts() {
4983 int x = 0;
4984 extern int optlines;
4985 prtopt(&optlines,"DIRECTORY");
4986 if (dir_show > 0) {
4987 prtopt(&optlines,(dir_show == 1) ? "/FILES" :
4988 ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
4989 x++;
4990 } else {
4991 prtopt(&optlines,"/ALL");
4992 x++;
4993 }
4994 if (dir_verb > -1) {
4995 prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
4996 x++;
4997 }
4998 if (dir_page > -1) {
4999 prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
5000 x++;
5001 }
5002 if (dir_date > -1) {
5003 prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
5004 x++;
5005 }
5006 if (dir_dots > -1) {
5007 prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
5008 x++;
5009 }
5010 if (dir_back > -1) {
5011 prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
5012 x++;
5013 }
5014 if (dir_head > -1) {
5015 prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
5016 x++;
5017 }
5018 #ifdef RECURSIVE
5019 if (dir_recu > -1) {
5020 prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
5021 x++;
5022 }
5023 #endif /* RECURSIVE */
5024 if (dir_mode > -1) {
5025 prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
5026 x++;
5027 }
5028 if (dir_sort == 0) {
5029 x++;
5030 prtopt(&optlines,"/NOSORT ");
5031 } else if (dir_sort > 0) {
5032 x++;
5033 if (dir_skey == DIRS_NM) s = "/SORT:NAME";
5034 else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
5035 else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
5036 prtopt(&optlines,s);
5037 }
5038 if (dir_rvrs > -1) {
5039 prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
5040 x++;
5041 }
5042 if (dir_msg > -1) {
5043 if (dir_msg == 0) {
5044 prtopt(&optlines,"/NOMESSAGE");
5045 } else {
5046 ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL);
5047 prtopt(&optlines,tmpbuf);
5048 }
5049 x++;
5050 }
5051 if (!x) prtopt(&optlines,"(no options set)");
5052 prtopt(&optlines,"");
5053 }
5054 #endif /* NOSHOW */
5055
5056 int
setdiropts()5057 setdiropts() { /* Set DIRECTORY option defaults */
5058 int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
5059 int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
5060 int getval;
5061 char c;
5062 while (1) {
5063 if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
5064 if (y == -3)
5065 break;
5066 else
5067 return(y);
5068 }
5069 c = cmgbrk();
5070 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5071 printf("?This switch does not take an argument\n");
5072 return(-9);
5073 }
5074 if (!getval && (cmgkwflgs() & CM_ARG)) {
5075 printf("?This switch requires an argument\n");
5076 return(-9);
5077 }
5078 switch (y) {
5079 case DIR_BRF: xv = 0; break;
5080 case DIR_VRB: xv = 1; break;
5081 case DIR_PAG: xp = 1; break;
5082 case DIR_NOP: xp = 0; break;
5083 case DIR_ISO: xd = 0; break;
5084 case DIR_DAT: xd = 1; break;
5085 case DIR_HDG: xh = 1; break;
5086 case DIR_NOH: xh = 0; break;
5087 case DIR_DOT: xf = 1; break;
5088 case DIR_NOD: xf = 0; break;
5089 case DIR_ALL: xa = 3; break;
5090 case DIR_DIR: xa = 2; break;
5091 case DIR_FIL: xa = 1; break;
5092 case DIR_SRT:
5093 x = DIRS_NM;
5094 if (getval)
5095 if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
5096 return(x);
5097 xk = x;
5098 xs = 1;
5099 break;
5100 case DIR_NOS: xs = 0; break;
5101 case DIR_ASC: xx = 0; break;
5102 case DIR_DSC: xx = 1; break;
5103 case DIR_REC: xr = 1; break;
5104 case DIR_NOR: xr = 0; break;
5105 case DIR_TYP: xm = 1; break;
5106 case DIR_NOT: xm = 0; break;
5107 case DIR_BUP: xb = 1; break;
5108 case DIR_NOB: xb = 0; break;
5109 case DIR_NOM: xg = 0; break;
5110 case DIR_MSG:
5111 if (getval)
5112 if ((x = cmfld("Message to append to each line",
5113 "",
5114 &s,
5115 xxstring
5116 )) < 0)
5117 return(x);
5118 xg = 1;
5119 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
5120 break;
5121 default:
5122 printf("?This option can not be set\n");
5123 return(-9);
5124 }
5125 }
5126 if ((x = cmcfm()) < 0) /* Get confirmation */
5127 return(x);
5128 if (xv > -1) dir_verb = xv; /* Confirmed, save defaults */
5129 if (xp > -1) dir_page = xp;
5130 if (xd > -1) dir_date = xd;
5131 if (xh > -1) dir_head = xh;
5132 if (xs > -1) dir_sort = xs;
5133 if (xk > -1) dir_skey = xk;
5134 if (xx > -1) dir_rvrs = xx;
5135 if (xf > -1) dir_dots = xf;
5136 if (xa > -1) dir_show = xa;
5137 if (xm > -1) dir_mode = xm;
5138 if (xb > -1) dir_back = xb;
5139 #ifdef RECURSIVE
5140 if (xr > -1) dir_recu = xr;
5141 #endif /* RECURSIVE */
5142 if (xg > -1) dir_msg = xg;
5143 if (xg > 0)
5144 makestr(&dirmsg,tmpbuf);
5145 return(success = 1);
5146 }
5147
5148 int
domydir(cx)5149 domydir(cx) int cx; { /* Internal DIRECTORY command */
5150 extern char *months[], *tempdir;
5151 #ifdef VMS
5152 _PROTOTYP( char * zrelname, (char *,char *) );
5153 char * cdp = NULL;
5154 #endif /* VMS */
5155 struct zattr xxstruct;
5156
5157 int chmtopt = CHMT_U;
5158 char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
5159 char linebuf[CKMAXPATH+CKMAXPATH+256];
5160 char string1[1024], string2[1024]; /* For CHANGE */
5161 char modtime[100];
5162 char * mstr = NULL, * dstr = NULL, * s2 = NULL, * cv = NULL;
5163 CK_OFF_T len = (CK_OFF_T)0, nbytes = (CK_OFF_T)0;
5164 CK_OFF_T minsize = (CK_OFF_T)-1, maxsize = (CK_OFF_T)-1;
5165 long ndirs = 0, nfiles = 0, nmatches = 0;
5166 int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0;
5167 int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
5168 int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
5169 int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
5170 int touch = 0;
5171 int change = 0; /* Doing CHANGE command */
5172 int chcase = 0; /* CHANGE case dependence */
5173 int s1len = 0; /* CHANGE string1 length */
5174 int s2len = 0; /* CHANGE string2 length */
5175 int fs = 0;
5176 int multiple = 0;
5177 int cmifn1 = 1, cmifn2 = 0;
5178 int dir_top = 0, dir_cou = 0;
5179 int dontshowlinks = 0;
5180 int dontfollowlinks = 0;
5181 int arrayindex = -1;
5182 int simulate = 0;
5183 struct FDB sw, fi, fl;
5184 char dbuf[256], xbuf[32];
5185 int reallysort = 0;
5186 int changeinplace = 0;
5187 int changebackup = 0;
5188 int changes = 0; /* Change counter per file */
5189 int totalchanges = 0; /* Change counter all files */
5190
5191 #ifndef NOSPL
5192 char array = NUL;
5193 char ** ap = NULL;
5194 #endif /* NOSPL */
5195 char
5196 * dir_aft = NULL,
5197 * dir_bef = NULL,
5198 * dir_naf = NULL,
5199 * dir_nbf = NULL,
5200 * dir_exc = NULL;
5201 char * xlist[16];
5202
5203 debug(F101,"domydir cx","",cx);
5204
5205 chgsourcedir[0] = NUL; /* CHANGE source directory */
5206 chgdestdir[0] = NUL; /* CHANGE destination directory */
5207 chgbackupdir[0] = NUL; /* CHANGE backup directory */
5208 changeinplace = 1; /* CHANGE'ing files in place */
5209 changebackup = 0; /* Backing up CHANGEd files */
5210 changes = 0;
5211 totalchanges = 0;
5212
5213 g_matchdot = matchdot; /* Save global matchdot setting */
5214 #ifdef COMMENT
5215 nolinks = 2; /* (it should already be 2) */
5216 #endif /* COMMENT */
5217 outfile[0] = NUL; /* No output file yet */
5218
5219 modtime[0] = '\0'; /* Initialize TOUCH /MODTIME */
5220
5221 if (ofp != stdout) { /* In case of previous interruption */
5222 if (ofp) fclose(ofp);
5223 ofp = stdout;
5224 }
5225 for (i = 0; i < 16; i++) xlist[i] = NULL;
5226
5227 dir_top = 0;
5228 name[0] = NUL;
5229 freedirlist(); /* In case not freed last time */
5230 page = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
5231 engdate = dir_date > -1 ? dir_date : 0;
5232 verbose = dir_verb > -1 ? dir_verb : 1;
5233 heading = dir_head > -1 ? dir_head : 0;
5234 xsort = dir_sort > -1 ? dir_sort : 0;
5235 sortby = dir_skey > -1 ? dir_skey : 0;
5236 reverse = dir_rvrs > -1 ? dir_rvrs : 0;
5237 msg = dir_msg > -1 ? dir_msg : 0;
5238 #ifdef UNIXOROSK
5239 if (dir_dots > -1) matchdot = dir_dots;
5240 #endif /* UNIXOROSK */
5241 xfermod = dir_mode > -1 ? dir_mode : 0;
5242 backup = dir_back > -1 ? dir_back : 1;
5243 #ifdef RECURSIVE
5244 recursive = dir_recu > -1 ? dir_recu : 0;
5245 #endif /* RECURSIVE */
5246 show = dir_show > -1 ? dir_show : 3;
5247
5248 diractive = 1; /* This is a DIRECTORY command */
5249
5250 switch (cx) {
5251 case XXWDIR: /* WDIRECTORY */
5252 debug(F100,"domydir WDIRECTORY","",0);
5253 reverse = 1; /* Reverse chronological order */
5254 xsort = 1;
5255 sortby = DIRS_DT;
5256 break;
5257 case XXHDIR: /* HDIRECTORY */
5258 debug(F100,"domydir HDIRECTORY","",0);
5259 reverse = 1; /* Reverse order by size */
5260 xsort = 1;
5261 sortby = DIRS_SZ;
5262 break;
5263 case XXTOUC:
5264 diractive = 0; /* This is NOT a DIRECTORY command */
5265 touch = 1;
5266 verbose = 0;
5267 break;
5268 case XXCHG: /* CHANGE 2013-04-18 */
5269 diractive = 0; /* This is NOT a DIRECTORY command */
5270 change = 1;
5271 verbose = 0;
5272 }
5273
5274 #ifdef CK_TTGWSIZ
5275 #ifdef OS2
5276 ttgcwsz(); /* Screen length for more-prompting */
5277 #else /* OS2 */
5278 /* Check whether window size changed */
5279 if (ttgwsiz() > 0) {
5280 if (tt_rows > 0 && tt_cols > 0) {
5281 cmd_rows = tt_rows;
5282 cmd_cols = tt_cols;
5283 }
5284 }
5285 #endif /* OS2 */
5286 #endif /* CK_TTGWSIZ */
5287
5288 cmifn1 = nolinks | 1; /* 1 = files or directories */
5289 cmifn2 = 0; /* 0 = not directories only */
5290
5291 again:
5292
5293 cmfdbi(&sw, /* First FDB - command switches */
5294 _CMKEY, /* fcode */
5295 "Enter or Return to confirm the command, or\n\
5296 file specification, or switch",
5297 "", /* default */
5298 "", /* addtl string data */
5299 touch ? ntouchswtab : (change ? nchangeswtab : ndirswtab),
5300 4, /* addtl numeric data 2: 4 = cmswi */
5301 xxstring, /* Processing function */
5302 touch ? touchswtab : (change ? changeswtab : dirswtab),
5303 &fi /* Pointer to next FDB */
5304 );
5305 cmfdbi(&fi, /* 2nd FDB - filespec to match */
5306 _CMIFI, /* fcode */
5307 "File specification", /* hlpmsg */
5308 #ifdef datageneral
5309 "+", /* Default filespec is wildcard */
5310 #else /* that matches all files... */
5311 #ifdef VMS
5312 "*.*",
5313 #else
5314 "*",
5315 #endif /* VMS */
5316 #endif /* datageneral */
5317 "", /* addtl string data */
5318 cmifn1,
5319 cmifn2, /* 1 = only dirs; 0 files or dirs */
5320 xxstring,
5321 NULL,
5322 &fl
5323 );
5324 cmfdbi(&fl, /* Anything that doesn't match */
5325 _CMFLD, /* fcode */
5326 "", /* hlpmsg */
5327 "", /* default */
5328 "", /* addtl string data */
5329 0, /* addtl numeric data 1 */
5330 0, /* addtl numeric data 2 */
5331 xxstring,
5332 NULL,
5333 NULL
5334 );
5335 while (1) { /* Parse 0 or more switches */
5336 x = cmfdb(&sw); /* Parse something */
5337 debug(F101,"domydir cmfdb","",x);
5338 if (x < 0)
5339 return(x);
5340 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
5341 break;
5342 c = cmgbrk();
5343 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5344 printf("?This switch does not take an argument\n");
5345 return(-9);
5346 }
5347 k = cmresult.nresult;
5348 if (!getval &&
5349 (cmgkwflgs() & CM_ARG) && k != DIR_TOP && k != DIR_COU) {
5350 printf("?This switch requires an argument\n");
5351 return(-9);
5352 }
5353 switch (k) {
5354 case DIR_COU: {
5355 dir_cou++;
5356 if (getval) {
5357 if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
5358 return(x);
5359 makestr(&cv,s);
5360 }
5361 break;
5362 }
5363 case DIR_BRF: verbose = 0; break;
5364 case DIR_VRB: verbose = 1; break;
5365 #ifdef CK_TTGWSIZ
5366 case DIR_PAG: page = 1; break;
5367 case DIR_NOP: page = 0; break;
5368 #endif /* CK_TTGWSIZ */
5369 case DIR_ISO: engdate = 0; break;
5370 case DIR_DAT: engdate = 1; break;
5371 case DIR_HDG: heading = 1; break;
5372 case DIR_NOH: heading = 0; break;
5373 #ifdef UNIXOROSK
5374 case DIR_DOT: matchdot = 1; break;
5375 case DIR_NOD: matchdot = 0; break;
5376 #endif /* UNIXOROSK */
5377 case DIR_ALL:
5378 show = 3;
5379 cmifn1 |= 1;
5380 cmifn2 = 0;
5381 goto again;
5382 case DIR_DIR:
5383 show = 2;
5384 cmifn1 |= 1;
5385 cmifn2 = 1;
5386 goto again;
5387 case DIR_FIL:
5388 show = 1;
5389 cmifn1 &= ~(1);
5390 cmifn2 = 0;
5391 goto again;
5392 case DIR_SRT:
5393 x = DIRS_NM;
5394 if (c == ':' || c == '=')
5395 if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
5396 return(x);
5397 xsort = 1;
5398 sortby = x;
5399 break;
5400
5401 case DIR_BUP: backup = 1; fs++; break;
5402 case DIR_NOB: backup = 0; fs++; break;
5403
5404 case DIR_NOS: xsort = 0; break;
5405 case DIR_ASC: reverse = 0; break;
5406 case DIR_DSC: reverse = 1; break;
5407 #ifdef RECURSIVE
5408 case DIR_REC: recursive = 1; diractive = 1; break;
5409 case DIR_NOR: recursive = 0; diractive = 0; break;
5410 #endif /* RECURSIVE */
5411 case DIR_TYP: xfermod = 1; break;
5412 case DIR_NOT: xfermod = 0; break;
5413
5414 #ifdef CKSYMLINK
5415 case DIR_LNK: /* Follow links */
5416 #ifdef COMMENT
5417 /* A command switch shouldn't be setting a global value! */
5418 nolinks = 0;
5419 #endif /* COMMENT */
5420 cmifn1 &= ~(2);
5421 dontfollowlinks = 0;
5422 goto again;
5423 case DIR_NLK: /* Don't follow links */
5424 #ifdef COMMENT
5425 nolinks = 2;
5426 #endif /* COMMENT */
5427 cmifn1 &= ~(2);
5428 dontfollowlinks = 1;
5429 goto again;
5430 case DIR_NOL: /* Don't show links at all */
5431 dontshowlinks = 1;
5432 goto again;
5433 #endif /* CKSYMLINK */
5434
5435 case DIR_NOM: msg = 0; break;
5436 case DIR_MSG:
5437 if (c == ':' || c == '=')
5438 if ((x = cmfld("Message to append to each line",
5439 "",
5440 &s,
5441 xxstring
5442 )) < 0)
5443 return(x);
5444 msg = 1;
5445 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
5446 break;
5447
5448 case DIR_SMA:
5449 case DIR_LAR: {
5450 CK_OFF_T y;
5451 if (!getval) break;
5452 if ((x = cmnumw("File size in bytes","0",10,&y,xxstring)) < 0)
5453 return(x);
5454 fs++;
5455 show = 1;
5456 switch (cmresult.nresult) {
5457 case DIR_SMA: minsize = y; break;
5458 case DIR_LAR: maxsize = y; break;
5459 }
5460 break;
5461 }
5462 case DIR_TOP:
5463 dir_top = 10;
5464 if (!getval) break;
5465 if ((x = cmnum("How many lines to show","10",10,&y,xxstring))< 0)
5466 return(x);
5467 dir_top = y;
5468 break;
5469
5470 #ifndef NOSPL
5471 case DIR_ARR:
5472 if (c != ':' && c != '=') {
5473 printf("?Array name required\n");
5474 return(-9);
5475 }
5476 if ((x = cmfld("Array name (a single letter will do)",
5477 "",
5478 &s,
5479 NULL
5480 )) < 0) {
5481 if (x == -3) {
5482 printf("?Array name required\n");
5483 return(-9);
5484 } else
5485 return(x);
5486 }
5487 if (!*s) {
5488 printf("?Array name required\n");
5489 return(-9);
5490 }
5491 s2 = s;
5492 if (*s == CMDQ) s++;
5493 if (*s == '&') s++;
5494 if (!isalpha(*s)) {
5495 printf("?Bad array name - \"%s\"\n",s2);
5496 return(-9);
5497 }
5498 array = *s++;
5499 if (isupper(array)) array = tolower(array);
5500 if (*s && (*s != '[' || *(s+1) != ']')) {
5501 printf("?Bad array name - \"%s\"\n",s2);
5502 return(-9);
5503 }
5504 break;
5505 #endif /* NOSPL */
5506 case DIR_AFT:
5507 case DIR_BEF:
5508 case DIR_NAF:
5509 case DIR_NBF:
5510 if (!getval) break;
5511 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
5512 if (x == -3) {
5513 printf("?Date-time required\n");
5514 rc = -9;
5515 } else
5516 rc = x;
5517 goto xdomydir;
5518 }
5519 fs++;
5520 switch (k) {
5521 case DIR_AFT: makestr(&dir_aft,s); break;
5522 case DIR_BEF: makestr(&dir_bef,s); break;
5523 case DIR_NAF: makestr(&dir_naf,s); break;
5524 case DIR_NBF: makestr(&dir_nbf,s); break;
5525 }
5526 break;
5527 case DIR_EXC:
5528 if (!getval) break;
5529 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5530 if (x == -3) {
5531 printf("?Pattern required\n");
5532 rc = -9;
5533 } else
5534 rc = x;
5535 goto xdomydir;
5536 }
5537 fs++;
5538 makestr(&dir_exc,s);
5539 break;
5540
5541 case DIR_SUM:
5542 summary = 1;
5543 break;
5544
5545 case DIR_BIN: {
5546 extern struct keytab txtbin[];
5547 extern int xfiletype;
5548 if (!getval) break;
5549 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) {
5550 rc = x;
5551 goto xdomydir;
5552 }
5553 if (x == 2) {
5554 xfiletype = -1;
5555 } else {
5556 xfiletype = x;
5557 fs = 1;
5558 }
5559 break;
5560 }
5561 case DIR_OUT:
5562 if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0)
5563 return(x);
5564 ckstrncpy(outfile,s,CKMAXPATH+1);
5565 break;
5566
5567 case DIR_SIM: /* TOUCH or CHANGE /SIMULATE */
5568 simulate = 1;
5569 break;
5570
5571 case 7777: /* CASE: (CHANGE only) */
5572 if (change) {
5573 if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5574 return(x);
5575 chcase = x;
5576 }
5577 break;
5578
5579 case DIR_MOD: /* TOUCH or CHANGE /MODTIME: */
5580 if (change) {
5581 if ((x = cmkey(chmttab,nchmttab,"","update",xxstring)) < 0)
5582 return(x);
5583 chmtopt = x;
5584 break;
5585 }
5586 if ((x = cmdate("File modification date-time",
5587 "now",&s,0,xxstring)) < 0)
5588 return(x);
5589 ckstrncpy(modtime,brstrip(s),100);
5590 break;
5591
5592 case DIR_DES: /* CHANGE /DESTINATION:dirname */
5593 case DIR_BAK: /* CHANGE /BACKUP:dirname */
5594 if (change) {
5595 int x;
5596 char * whatdir = chgdestdir;
5597 char * hmsg = "Directory for changed files";
5598
5599 if (k == DIR_BAK) {
5600 hmsg = "Directory for backing up original files";
5601 whatdir = chgbackupdir;
5602 }
5603 x = cmdir(hmsg,"",&s,xxstring);
5604 if (x < 0) {
5605 if (x == -3) {
5606 printf("?Parse error\n");
5607 return(-9);
5608 }
5609 return(x);
5610 }
5611 x = isdir(s); /* this is overkill but... */
5612 if (x < 0) {
5613 if (x == -3) {
5614 printf("?Directory name required\n");
5615 return(-9);
5616 }
5617 return(x);
5618 }
5619 ckstrncpy(whatdir,s,MAXPATHLEN);
5620 if (!isdir(whatdir)) { /* Double overkill */
5621 printf("?%s is not a directory name\n",whatdir);
5622 return(-9);
5623 }
5624 switch (k) {
5625 case DIR_DES: /* DESTINATION switch given */
5626 changeinplace = 0; /* Making new files */
5627 break;
5628 case DIR_BAK: /* BACKUP switch given */
5629 changebackup = 1; /* Backup up original files */
5630 break;
5631 }
5632 }
5633 break;
5634
5635 default:
5636 printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
5637 goto xdomydir;
5638 }
5639 }
5640 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
5641
5642 /* ^^^ START MULTIPLE */
5643
5644 while (!touch && !change) { /* Multiple filespecs only for DIR */
5645 x = cmfld("Another filespec or Enter","",&s,xxstring);
5646 if (x == -3)
5647 break;
5648 if (x < 0)
5649 return(x);
5650 ckstrncat(line,",",LINBUFSIZ);
5651 ckstrncat(line,s,LINBUFSIZ);
5652 multiple++;
5653 }
5654 ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL);
5655 ckstrncpy(line,tmpbuf,LINBUFSIZ);
5656 cmresult.nresult = 1;
5657 cmresult.fcode = _CMIFI;
5658
5659 /* ^^^ END MULTIPLE */
5660
5661 ckstrncpy(name,line,MAXPATHLEN);
5662
5663 if (change) { /* Finish parsing CHANGE command */
5664 debug(F110,"CHANGE source file",line,0);
5665 x = cmfld("Text to be changed","",&s,xxstring);
5666 if (x < 0) {
5667 if (x == -3) {
5668 printf("?You must specify the text to be changed\n");
5669 return(-9);
5670 } else {
5671 return(x);
5672 }
5673 }
5674 s = brstrip(s);
5675 s1len = ckstrncpy(string1,s,1024);
5676 debug(F110,"CHANGE string1",string1,0);
5677
5678 x = cmfld("Text to change it to","",&s2,xxstring);
5679 if (x < 0 && x != -3) return(x);
5680 s2 = brstrip(s2);
5681 s2len = ckstrncpy(string2,s2,1024);
5682 debug(F110,"CHANGE string2",string2,0);
5683 }
5684 if ((x = cmcfm()) < 0) /* Get confirmation */
5685 return(x);
5686 /*
5687 Command is TOUCH and file doesn't exist.
5688 */
5689 if (touch) { /* TOUCH */
5690 if ((cmresult.fcode == _CMIFI && zchki(s) == (CK_OFF_T)-1)) {
5691 FILE * fp;
5692 s = brstrip(s);
5693 if (!iswild(s)) {
5694 /* Given date-time, if any, else current date-time */
5695 dstr = ckcvtdate(modtime[0] ? modtime : "",0);
5696 xxstruct.date.val = dstr;
5697 xxstruct.date.len = (int)strlen(xxstruct.date.val);
5698 xxstruct.lprotect.len = 0;
5699 xxstruct.gprotect.len = 0;
5700 #ifdef UNIX
5701 if (s[0] == '~')
5702 s = tilde_expand(s);
5703 #endif /* UNIX */
5704 /* the IF condition was added 2013-04-15 */
5705
5706 if (zchki(s) < 0) { /* If file doesn't already exist... */
5707 fp = fopen(s,"w"); /* Create it */
5708 if (!fp) {
5709 printf("?TOUCH %s: %s\n",s,ck_errstr());
5710 rc = -9;
5711 goto xdomydir;
5712 }
5713 fclose(fp);
5714 }
5715 debug(F110,"TOUCH CREATE NONEXISTENT",s,0);
5716 if (zstime(s,&xxstruct,0) < 0) {
5717 debug(F110,"TOUCH ZSTIME FAILED",s,0);
5718 printf("?TOUCH %s: %s\n",name,ck_errstr());
5719 rc = -9;
5720 goto xdomydir;
5721 }
5722 debug(F110,"TOUCH ZSTIME OK",xxstruct.date.val,0);
5723 multiple++; /* Force new directory scan */
5724 }
5725 }
5726 } else
5727
5728 if (cmresult.fcode != _CMIFI) { /* Nothing matched */
5729 /*
5730 Note - this never gets executed because after the "begin
5731 multiple" hack above, the result is always _CMIFI).
5732 */
5733 char * m;
5734 if (*s == '/')
5735 #ifdef UNIXOROSK
5736 m = "does not match switch or name of accessible file";
5737 #else
5738 #ifdef OS2
5739 m = "does not match switch or name of accessible file";
5740 #else
5741 m = "no switches match";
5742 #endif /* OS2 */
5743 #endif /* UNIXOROSX */
5744 else
5745 m = "not found or not accessible";
5746 printf("\"%s\" - %s\n",s,m);
5747 rc = -9;
5748 goto xdomydir;
5749 }
5750 #ifdef COMMENT
5751 /* This can't be right because it's based on _CMCFM */
5752 wild = cmresult.nresult; /* Wildcard was given? */
5753 debug(F111,"domydir cmifi2",s,wild);
5754 #else
5755 wild = 0;
5756 #endif /* COMMENT */
5757
5758 if (outfile[0]) { /* If an output file was specified */
5759 ofp = fopen(outfile,"w"); /* open it */
5760 if (!ofp) {
5761 printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
5762 ofp = stdout;
5763 return(-9);
5764 }
5765 page = 0;
5766 }
5767
5768 #ifdef OS2
5769 if (!wild) {
5770 if (zchki(s) == -2) { /* Found a directory */
5771 p = s + (int)strlen(s) - 1; /* Yes */
5772 if (*p == '\\' || *p == '/')
5773 strcat(s, "*");
5774 else if (*p == ':')
5775 strcat(s, "./*");
5776 else
5777 strcat(s, "/*");
5778 wild = 1; /* Now it's wild */
5779 }
5780 }
5781 #else
5782 if (!wild) if (isdir(s)) { /* Is it a directory? */
5783 p = s + (int)strlen(s) - 1; /* Yes */
5784 #ifdef VMS
5785 {
5786 /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
5787 char buf[CKMAXPATH+1];
5788 debug(F000,"domydir directory 0",s,*p);
5789 if (cvtdir(s,buf,CKMAXPATH) > 0)
5790 ckstrncpy(line,buf,LINBUFSIZ);
5791 }
5792 #endif /* VMS */
5793 debug(F000,"domydir directory 1",s,*p);
5794 #ifdef VMS
5795 if (*p == ']' || *p == '>' || *p == ':')
5796 strcat(s, "*.*");
5797 #else
5798 #ifdef datageneral
5799 if (*p == ':')
5800 strcat(s, "+");
5801 else
5802 strcat(s, ":+");
5803 #else
5804 #ifdef STRATUS
5805 if (*p == '>')
5806 strcat(s, "*");
5807 else
5808 strcat(s, ">*");
5809 #endif /* STRATUS */
5810 #endif /* datageneral */
5811 #endif /* VMS */
5812 wild = 1; /* Now it's wild */
5813 debug(F000,"domydir directory 2",s,*p);
5814 }
5815 #endif /* OS2 */
5816
5817 #ifdef ZXREWIND
5818 /* cmifi() already called nzxpand so we can just re-use the same list. */
5819 if (!multiple) {
5820 x = zxrewind(); /* Rewind the list */
5821 debug(F111,"domydir zxrewind",s,x);
5822 } else {
5823 #endif /* ZXREWIND */
5824 /*
5825 In case we gave multiple filespecs they are now in {a,b,c} list format.
5826 Which is a valid wildcard. We pass it to nzxpand() to get back the list
5827 of files that match. This is fine for DIRECTORY but it's not fine for
5828 TOUCH because we want TOUCH to see those names so it can create the files.
5829 So for now at least, if TOUCH is to be used to create files -- as opposed
5830 to changing the timestamps of existing files -- it can only do one file
5831 at a time.
5832 */
5833 nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
5834 (show == ZX_FILONLY ? ZX_FILONLY : 0);
5835 if (matchdot) nzxopts |= ZX_MATCHDOT;
5836 if (recursive) nzxopts |= ZX_RECURSE;
5837 x = nzxpand(s,nzxopts); /* Expand file list */
5838 debug(F111,"domydir nzxpand",s,x);
5839 #ifdef ZXREWIND
5840 }
5841 #endif /* ZXREWIND */
5842
5843 #ifndef NOSPL
5844 if (array) {
5845 int n, xx;
5846 n = (x < 0) ? 0 : x;
5847 if ((xx = dclarray(array,n)) < 0) {
5848 printf("?Array declaration failure\n");
5849 rc = -9;
5850 goto xdomydir;
5851 }
5852 arrayindex = xx;
5853 ap = a_ptr[xx]; /* Pointer to list of elements */
5854 if (ap) /* Set element 0 to dimension */
5855 makestr(&(ap[0]),"0"); /* which so far is zero */
5856 if (n < 1) { /* No files matched, done. */
5857 rc = 0;
5858 goto xdomydir;
5859 }
5860 } else
5861 #endif /* NOSPL */
5862 if (!touch && x < 1) {
5863 #ifdef CKROOT
5864 extern int ckrooterr;
5865 if (ckrooterr)
5866 printf("?Off limits: %s\n",s);
5867 else
5868 #endif /* CKROOT */
5869 if (x == 0 && isdir(s))
5870 printf("?Empty directory - \"%s\"\n", s);
5871 else
5872 printf("?%s %s match - \"%s\"\n",
5873 (x == 0) ? "No" : "Too many",
5874 (show == 2) ? "directories" : "files",
5875 brstrip(s)
5876 );
5877 rc = -9;
5878 goto xdomydir;
5879 }
5880 nx = x; /* Remember how many files */
5881 reallysort = xsort;
5882 if (nx < 2) reallysort = 0; /* Skip sorting if none or one */
5883 xsort = 1; /* 2013-12-06 but do everything else */
5884
5885 if (msg) {
5886 makestr(&dirmsg,tmpbuf);
5887 dirmsglen = strlen(tmpbuf);
5888 }
5889
5890 #ifdef VMS
5891 cdp = zgtdir(); /* Get current directory */
5892 debug(F110,"domydir VMS zgtdir",cdp,0);
5893 #endif /* VMS */
5894
5895 if (xsort && verbose) { /* If sorting, allocate space */
5896 if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
5897 if (!quiet) {
5898 printf("* Warning: Failure to allocate memory for sorting.\n");
5899 printf("* Will proceed without sorting...\n");
5900 }
5901 xsort = 0;
5902 }
5903 debug(F101,"domydir sort malloc","",xsort);
5904 }
5905
5906 /* Display the listing */
5907
5908 #ifndef NOSPL
5909 if (array) /* Storing instead of printing */
5910 heading = 0;
5911 #endif /* NOSPL */
5912
5913 if (heading) { /* If /HEADING print heading */
5914 zfnqfp(s,TMPBUFSIZ,tmpbuf);
5915 fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf);
5916 n += 3;
5917 }
5918 if (page > -1) /* Paging */
5919 xaskmore = page;
5920
5921 if (dir_exc) /* Have exception list? */
5922 makelist(dir_exc,xlist,16); /* Yes, convert to array */
5923
5924 if (!verbose && !touch && !change) { /* /BRIEF */
5925 if (outfile[0]) { /* To file */
5926 int k = 0;
5927 znext(name);
5928 while (name[0]) { /* One line per file */
5929 k++;
5930 if (fs) if (fileselect(name,
5931 dir_aft,dir_bef,dir_naf,dir_nbf,
5932 minsize,maxsize,!backup,16,xlist) < 1) {
5933 znext(name);
5934 continue;
5935 }
5936 fprintf(ofp,"%s\n",name);
5937 znext(name);
5938 }
5939 if (heading)
5940 fprintf(ofp,"Files: %d\n\n",k);
5941 rc = 1;
5942 goto xdomydir;
5943 } else {
5944 rc = xfilhelp(x,"","",n,0,1,
5945 dir_aft,dir_bef,dir_naf,dir_nbf,
5946 minsize,maxsize,!backup,16,xlist);
5947 if (rc < 0)
5948 goto xdomydir;
5949 if (heading && rc > 0)
5950 fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */
5951 rc = 1;
5952 goto xdomydir;
5953 }
5954 }
5955 ndirs = nfiles = 0L; /* Initialize counters */
5956 nbytes = (CK_OFF_T)0;
5957
5958 if (change) { /* CHANGE - check for conflicts */
5959 struct zfnfp * fp;
5960 char dbuf[MAXPATHLEN+1];
5961 char bbuf[MAXPATHLEN+1];
5962
5963 fp = zfnqfp(name,TMPBUFSIZ,chgsourcedir); /* Source directory path */
5964 if (fp) {
5965 chgsourcedir[fp->fname - fp->fpath] = NUL;
5966 debug(F110,"CHANGE source directory",chgsourcedir,0);
5967 if (chgdestdir[0]) {
5968 debug(F110,"CHANGE destination directory",chgdestdir,0);
5969 zfnqfp(chgdestdir,TMPBUFSIZ,dbuf);
5970 debug(F110,"CHANGE destination directory",dbuf,0);
5971 if (!strcmp(dbuf,chgsourcedir)) {
5972 printf(
5973 "?Destination and source directories are the same\n");
5974 success = 0;
5975 goto xdomydir;
5976 }
5977 }
5978 if (chgbackupdir[0]) {
5979 debug(F110,"CHANGE backup directory",chgbackupdir,0);
5980 zfnqfp(chgbackupdir,TMPBUFSIZ,bbuf);
5981 debug(F110,"CHANGE backup directory",bbuf,0);
5982 if (!strcmp(bbuf,chgsourcedir)) {
5983 printf("?Backup and source directories are the same\n");
5984 success = 0;
5985 goto xdomydir;
5986 }
5987 }
5988 if (chgbackupdir[0] && chgdestdir[0]) {
5989 if (!strcmp(bbuf,dbuf)) {
5990 printf(
5991 "?Backup and destination directories are the same\n");
5992 success = 0;
5993 goto xdomydir;
5994 }
5995 }
5996 }
5997 }
5998 diractive = 1; /* DIRECTORY command is active */
5999 znext(name); /* Get next file */
6000 while (name[0]) { /* Loop for each file */
6001 if (fs) if (fileselect(name,
6002 dir_aft,dir_bef,dir_naf,dir_nbf,
6003 minsize,maxsize,!backup,16,xlist) < 1) {
6004 znext(name);
6005 continue;
6006 }
6007 len = zgetfs(name); /* Get file length */
6008 debug(F111,"domydir loop zgetfs",name,len);
6009 #ifdef VMSORUNIX
6010 itsadir = zgfs_dir; /* See if it's a directory */
6011 #else
6012 itsadir = (len == (CK_OFF_T)-2 || isdir(name));
6013 #endif /* VMSOUNIX */
6014 debug(F111,"domydir itsadir",name,itsadir);
6015 changes = 0;
6016 if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
6017 znext(name);
6018 continue;
6019 }
6020 /* Get here when we know we have selected this file */
6021
6022 nmatches++;
6023 if (itsadir) { /* Accumulate totals for summary */
6024 ndirs++;
6025 } else {
6026 nfiles++;
6027 nbytes += len;
6028 }
6029 dstr = NULL; /* File date-time string */
6030
6031 /* BEGIN CHANGE command */
6032
6033 if (cx == XXCHG) { /* Command was CHANGE, not DIRECTORY */
6034 FILE * ifp = NULL; /* Input file pointer */
6035 FILE * ofp = NULL; /* Output (temporary) file pointer */
6036 FILE * bfp = NULL; /* Backup file pointer */
6037 char backupfile[MAXPATHLEN+1]; /* Backup file */
6038 char tmpfile[MAXPATHLEN]; /* Buffer for filename */
6039 char * tdp = tmpfile; /* Temporary directory path */
6040 int linebufsiz = 24575; /* Buf size for reading file lines */
6041 char * linebuf = NULL; /* Input file buffer */
6042 char * lbp = NULL; /* and pointer to it */
6043 char * newbuf = NULL; /* Output file buffer */
6044 char * nbp = NULL; /* and pointer */
6045 int bufleft = 0; /* Space left in newbuf */
6046 int i, j, k, x, y; /* Workers */
6047 int failed = 0; /* Search string not found */
6048 char c1, c2; /* Char for quick compare */
6049
6050 changes = 0; /* Change counter */
6051 k = 0;
6052 x = scanfile(name,NULL,nscanfile) ;
6053 debug(F111,"domydir CHANGE scanfile",name,x);
6054 switch (x) { /* Is it a text file? */
6055 case FT_7BIT: k++; break;
6056 case FT_UTF8: k++; break;
6057 case FT_UCS2: k++; break;
6058 case FT_8BIT: k++; break;
6059 case FT_TEXT: k++; break;
6060 }
6061 if (!k) {
6062 if (verbose)
6063 printf("%s: Skipped (not a text file)\n", name);
6064 znext(name);
6065 continue;
6066 }
6067 debug(F101,"CHANGE changeinplace","",changeinplace);
6068
6069 if (changeinplace) { /* CHANGing in place? */
6070 int x = 0;
6071 if (!tempdir) { /* Need a temporary directory */
6072 x++;
6073 } else if (!*tempdir) {
6074 x++;
6075 }
6076 /*
6077 It might make more sense to fall back on the current directory, or the
6078 directory specified in the filespec, because that one has to be writeable or
6079 the files could not be changed.
6080 */
6081 if (x) {
6082 printf(
6083 "?Temporary directory not defined, use SET TEMP-DIRECTORY to define one.\n"
6084 );
6085 success = 0;
6086 goto xdomydir;
6087 }
6088 ckstrncpy(tmpfile,tempdir,MAXPATHLEN); /* Temp directory */
6089 ckstrncat(tmpfile,"__x",MAXPATHLEN); /* Temp filespec */
6090 if (simulate) {
6091 /* Too much */
6092 /* printf("Would create temp file %s\n",tmpfile); */
6093 } else {
6094 ofp = fopen(tmpfile,"w"); /* Open temporary file */
6095 debug(F110,"CHANGE in place tmpfile",tmpfile,0);
6096 if (!ofp) {
6097 printf("?Can't open temporary file %s: %s\n",
6098 tmpfile,ck_errstr());
6099 success = 0;
6100 goto xdomydir;
6101 }
6102 }
6103 } else { /* Making a new copy of the file */
6104 char * p = name, * p2 = NULL;
6105 debug(F110,"CHANGE chgdestdir",chgdestdir,0);
6106 ckstrncpy(tmpfile,chgdestdir,MAXPATHLEN);
6107 debug(F110,"CHANGE tmpfile",tmpfile,0);
6108 while (*p++) { if (ISDIRSEP(*p)) p2 = p; } /* Just the name */
6109 if (!p2) { /* name had no slashes in it */
6110 p2 = name;
6111 ckstrncat(tmpfile,STRDIRSEP,MAXPATHLEN);
6112 }
6113 debug(F110,"CHANGE name",p2,0);
6114 ckstrncat(tmpfile,p2,MAXPATHLEN);
6115 debug(F110,"CHANGE final tmpfile",tmpfile,0);
6116 if (simulate) {
6117 printf("Would create new file %s\n",tmpfile);
6118 } else {
6119 debug(F110,"CHANGE /dest tmpfile",tmpfile,0);
6120 ofp = fopen(tmpfile,"w"); /* Open temporary file */
6121 if (!ofp) {
6122 printf("?Can't open destination file %s: %s\n",
6123 tmpfile,ck_errstr());
6124 success = 0;
6125 goto xdomydir;
6126 }
6127 }
6128 }
6129 if (changebackup) { /* Backing up original file? */
6130 char * p = name, * p2 = NULL;
6131 ckstrncpy(backupfile,chgbackupdir,MAXPATHLEN);
6132 debug(F111,"CHANGE backupfile",backupfile,1);
6133 while (*p++) { if (ISDIRSEP(*p)) p2 = p; } /* Just the name */
6134 if (!p2) { /* name had no slashes in it */
6135 p2 = name;
6136 ckstrncat(backupfile,STRDIRSEP,MAXPATHLEN);
6137 }
6138 debug(F111,"CHANGE backupfile",backupfile,2);
6139 ckstrncat(backupfile,p2,MAXPATHLEN);
6140 debug(F111,"CHANGE backupfile",backupfile,3);
6141 if (simulate) {
6142 printf("Would back up original file to %s\n",
6143 backupfile);
6144 } else {
6145 bfp = fopen(backupfile,"w"); /* Open temporary file */
6146 if (!bfp) {
6147 printf("?Can't open backup file %s: %s\n",
6148 backupfile,ck_errstr());
6149 success = 0;
6150 goto xdomydir;
6151 }
6152 }
6153 }
6154 if ((ifp = fopen(name,"r")) == NULL) { /* Open input file */
6155 printf("?Can't open file %s: %s\n",s,ck_errstr());
6156 fclose(ofp);
6157 success = 0;
6158 goto xdomydir;
6159 }
6160 /* Get timestamp of original file */
6161 debug(F101,"CHANGE timestamp changebackup","",changebackup);
6162 if (chmtopt == CHMT_P || changebackup) {
6163 debug(F110,"CHANGE file timestamp name",name,0);
6164 dstr = zfcdat(name);
6165 if (!dstr) dstr = "";
6166 if (!*dstr) printf("WARNING: can't get date for %s\n",name);
6167 debug(F110,"CHANGE file timestamp dstr",dstr,0);
6168 xxstruct.date.val = dstr; /* change file's modtime */
6169 xxstruct.date.len = (int)strlen(xxstruct.date.val);
6170 xxstruct.lprotect.len = 0;
6171 xxstruct.gprotect.len = 0;
6172 }
6173 linebuf = (char *) malloc(linebufsiz+1); /* Malloc a line buffer */
6174 if (!linebuf) {
6175 printf("?Memory allocation failure\n");
6176 fclose(ofp);
6177 fclose(ifp);
6178 if (bfp) fclose(bfp);
6179 success = 0;
6180 goto xdomydir;
6181 }
6182 newbuf = (char *) malloc(linebufsiz+1); /* Buffer for copy */
6183 if (!newbuf) {
6184 free(linebuf);
6185 printf("?Memory allocation failure\n");
6186 fclose(ofp);
6187 fclose(ifp);
6188 if (bfp) fclose(bfp);
6189 success = 0;
6190 goto xdomydir;
6191 }
6192 /* Loop through lines of each original file... */
6193
6194 while (fgets(linebuf, linebufsiz, ifp)) { /* Read a line */
6195 if (changebackup && !simulate) {
6196 if (fputs(linebuf, bfp) == EOF) { /* Backing up */
6197 printf("?%s: Write failed - %s\n",
6198 backupfile,ck_errstr());
6199 failed++;
6200 break;
6201 }
6202 }
6203 nbp = newbuf;
6204 lbp = linebuf;
6205 bufleft = linebufsiz; /* Space left in newbuf */
6206 x = ckindex(string1,lbp,0,0,chcase);
6207 if (x == 0) { /* Nothing to replace */
6208 if (!simulate) {
6209 if (fputs(lbp, ofp) == EOF) {
6210 printf("?%s: Write failed - %s\n",
6211 tmpfile,ck_errstr());
6212 failed++;
6213 break;
6214 }
6215 }
6216 } else while (1) { /* One or maybe more occurrences */
6217 changes++; /* Count this change */
6218 totalchanges++; /* Increment total changes */
6219 j = x + s2len - 1; /* Size of addition to newbuf */
6220 bufleft -= j; /* Remaining space in newbuf after */
6221 if (bufleft > j) { /* If space enough */
6222 char c;
6223 c = lbp[x];
6224 lbp[x] = NUL; /* Terminate for strncpy */
6225 strncpy(nbp,lbp,bufleft); /* Copy this piece */
6226 lbp[x] = c;
6227 nbp += (x - 1); /* adjust destination pointer */
6228 strncpy(nbp,string2,bufleft); /* replacement string */
6229 nbp += s2len; /* and adjust destination pointer */
6230 } else { /* Otherwise fail. */
6231 failed++;
6232 printf("?%s: Write failed - %s\n",tmpfile,ck_errstr());
6233 break;
6234 }
6235 lbp += x + s1len - 1; /* Adjust source pointer */
6236 x = ckindex(string1,lbp,0,0,chcase); /* Get next */
6237 if (!x) { /* No more string1's found in this line */
6238 if (!simulate) { /* Write changes */
6239 if (fputs(newbuf, ofp) == EOF) {
6240 printf("?%s: Write failed - %s\n",
6241 tmpfile,ck_errstr());
6242 failed++;
6243 break;
6244 }
6245 if (*lbp) { /* And write out last chunk if any */
6246 if (fputs(lbp, ofp) == EOF) {
6247 printf("?%s: Write failed - %s\n",
6248 tmpfile,ck_errstr());
6249 failed++;
6250 break;
6251 }
6252 }
6253 }
6254 break;
6255 }
6256 }
6257 }
6258 fclose(ifp); /* End... close files */
6259 if (!simulate) {
6260 if (bfp) fclose(bfp);
6261 fclose(ofp);
6262 }
6263 bfp = ifp = ofp = NULL;
6264 free(linebuf); /* and free buffers */
6265 free(newbuf);
6266 if (simulate) { /* Simulation run */
6267 if (failed) {
6268 printf("Would fail: %s\n",name);
6269 } else if (changes) {
6270 printf("Would change: %s\n",name);
6271 } else if (verbose) {
6272 printf("Would not change: %s\n",name);
6273 }
6274 zdelet(tmpfile);
6275 } else if (!failed) { /* Really changing */
6276 char * result = name;
6277 if (changes) { /* If changes were made */
6278 if (changeinplace) { /* Changing in place... */
6279 x = zrename(tmpfile,name); /* Replace original file */
6280 if (x < 0) {
6281 printf("?Rename temporary file %s to %s failed",
6282 tmpfile, name);
6283 zdelet(tmpfile); /* delete temporary file */
6284 success = 0;
6285 goto xdomydir;
6286 }
6287 } else { /* Making new file... */
6288 result = tmpfile;
6289 }
6290 if (chmtopt == CHMT_P) { /* If preserving file dates */
6291 debug(F110,"Setting modtime",result,0);
6292 if (zstime(result,&xxstruct,0) < 0) {
6293 printf("?Error \
6294 preserving original modtime: %s %s\n",
6295 result,
6296 ck_errstr()
6297 );
6298 rc = -9;
6299 goto xdomydir;
6300 }
6301 }
6302 /* Change modtime of backup file unconditionally */
6303 debug(F111,"CHANGE modtime",backupfile,changebackup);
6304 if (changebackup) {
6305 if (zstime(backupfile,&xxstruct,0) < 0) {
6306 printf("?Modtime error on backup file: %s\n",
6307 backupfile,
6308 ck_errstr()
6309 );
6310 rc = -9;
6311 goto xdomydir;
6312 }
6313 }
6314 if (verbose)
6315 printf("Changed %s: %s -> %s\n",result,string1,string2);
6316 } else if (changeinplace) {
6317 zdelet(tmpfile); /* Delete temporary file */
6318 if (changebackup) zdelet(backupfile); /* and backup */
6319 }
6320 }
6321 if (znext(name)) /* Get next file */
6322 continue;
6323 success = 1; /* If none we're finished */
6324 goto xdomydir;
6325 }
6326
6327 /* TOUCH command... */
6328
6329 if (cx == XXTOUC) { /* Command was TOUCH, not DIRECTORY */
6330 /* Given date-time, if any, else current date-time */
6331 debug(F110,"TOUCH dstr before",dstr,0);
6332 dstr = ckcvtdate(modtime[0] ? modtime : "",0);
6333 debug(F110,"TOUCH dstr after",dstr,0);
6334 xxstruct.date.val = dstr;
6335 xxstruct.date.len = (int)strlen(xxstruct.date.val);
6336 xxstruct.lprotect.len = 0;
6337 xxstruct.gprotect.len = 0;
6338 if (simulate) {
6339 printf(" %s (%s)\n",name,dstr);
6340 } else {
6341 if (zstime(name,&xxstruct,0) < 0) {
6342 printf("?TOUCH %s: %s\n",name,ck_errstr());
6343 rc = -9;
6344 goto xdomydir;
6345 }
6346 }
6347 if (!verbose || simulate) { /* No listing so just go back */
6348 znext(name); /* and do next file. */
6349 continue;
6350 }
6351 }
6352 if (summary) { /* Summary only, no detail */
6353 znext(name);
6354 continue;
6355 }
6356 /*
6357 NOTE: The sprintf's in this routine should be safe. They involve
6358 permission strings, date/time strings, and filenames, all of which have
6359 known maximum lengths; none of these items is input from users. The
6360 destination buffers are large enough to hold maximum sizes for any and
6361 all items. NOTE 2: If command was TOUCH, dstr was already set just
6362 above.
6363 */
6364 if (!dstr) { /* Get file's modification date/time */
6365 dstr = zfcdat(name);
6366 debug(F111,"domydir zcfdat",dstr,0);
6367 }
6368 if (!dstr) dstr = "";
6369 {
6370 /*
6371 Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings
6372 about possible out-of-bounds dstr[] array refs do not apply. This block of
6373 code is to stifle the warnings and also allows for any out-of-spec
6374 zfcdat() implementations.
6375 */
6376 int x;
6377 char * p = "00000000 00:00:00";
6378 x = ckstrncpy(xbuf,dstr,32);
6379 if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x);
6380 dstr = xbuf;
6381 }
6382 if (engdate) { /* English date requested? */
6383 short month, day, year, hour, minute, seconds;
6384 month = (dstr[4]-48)*10 + (dstr[5]-48);
6385 mstr = (month > 0 && month <= 12) ? months[month-1] : "xxx";
6386 day = (dstr[6]-48)*10 + (dstr[7]-48);
6387 year = (((dstr[0]-48)*10 +
6388 (dstr[1]-48))*10 +
6389 (dstr[2]-48))*10 +
6390 (dstr[3]-48);
6391 hour = (dstr[9]-48)*10 + (dstr[10]-48);
6392 minute = (dstr[12]-48)*10 + (dstr[13]-48);
6393 seconds = (dstr[15]-48)*10 + (dstr[16]-48);
6394 sprintf(dbuf, /* SAFE */
6395 "%2d-%s-%4d %02d:%02d:%02d",
6396 day,mstr,year,hour,minute,seconds
6397 );
6398 dstr = dbuf;
6399 } else { /* ISO date */
6400 dbuf[0] = dstr[0]; /* yyyy */
6401 dbuf[1] = dstr[1];
6402 dbuf[2] = dstr[2];
6403 dbuf[3] = dstr[3];
6404 dbuf[4] = '-';
6405 dbuf[5] = dstr[4]; /* mm (numeric) */
6406 dbuf[6] = dstr[5];
6407 dbuf[7] = '-';
6408 dbuf[8] = dstr[6]; /* dd */
6409 dbuf[9] = dstr[7];
6410 strcpy(dbuf+10,dstr+8); /* hh:mm:ss */
6411 dstr = dbuf;
6412 }
6413 dlen = strlen(dbuf); /* Length of date */
6414 name[CKMAXPATH] = NUL;
6415 #ifdef CK_PERMS
6416 #ifdef VMSORUNIX
6417 p = ziperm(name); /* Get permissions */
6418 debug(F110,"ziperm perms",p,0);
6419 #else
6420 p = zgperm(name);
6421 debug(F110,"zgperm perms",p,0);
6422 #endif /* VMSORUNIX */
6423 #else
6424 p = NULL;
6425 debug(F110,"NULL perms",p,0);
6426 #endif /* CK_PERMS */
6427
6428 #ifdef VMS
6429 /* Get relative name to save space -- VMS fullnames are long... */
6430 ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
6431 #endif /* VMS */
6432
6433 if (itsadir && len < (CK_OFF_T)0) { /* Directory */
6434 #ifdef VMS
6435 sprintf(linebuf,"%-22s%-10s %s %s",p,"<DIR>",dstr,name);
6436 #else
6437 if (p)
6438 sprintf(linebuf,"%10s%-10s %s %s",p,"<DIR>",dstr,name);
6439 else
6440 sprintf(linebuf,"%-10s %s %s", "<DIR>", dstr, name);
6441 #endif /* VMS */
6442 } else { /* Regular file */
6443 #ifdef VMS
6444 sprintf(linebuf,"%-22s%10s %s %s", p, ckfstoa(len), dstr, name);
6445 #else
6446 if (p)
6447 sprintf(linebuf,"%10s%10s %s %s", p, ckfstoa(len), dstr, name);
6448 else
6449 sprintf(linebuf,"%10s %s %s", ckfstoa(len), dstr, name);
6450 #endif /* VMS */
6451 }
6452 #ifdef UNIX
6453 #ifdef CKSYMLINK
6454 if (zgfs_link) { /* If it's a symlink */
6455 if (dontshowlinks) { /* If /NOLINKS don't show it */
6456 znext(name);
6457 continue;
6458 }
6459 }
6460 if (zgfs_link && !dontfollowlinks) { /* Symlink and following links */
6461 int n, m; /* Show what the link points to */
6462 extern char linkname[];
6463 n = strlen(linebuf);
6464 m = strlen(linkname) + n;
6465 if (m < CKMAXPATH + 58)
6466 strcpy(linebuf+n, " -> "); /* safe (checked) */
6467 if (m + 4 < CKMAXPATH - 58)
6468 strcpy(linebuf+n+4, linkname); /* safe (checked) */
6469 } else
6470 #endif /* CKSYMLINK */
6471 #endif /* UNIX */
6472 if (xfermod) { /* Show transfer mode */
6473 int i, x, y;
6474 char * s = "";
6475 y = -1;
6476 x = scanfile(name,&y,nscanfile);
6477 switch (x) {
6478 case FT_TEXT: s = " (T)"; break;
6479 case FT_7BIT: s = " (T)(7BIT)"; break;
6480 case FT_8BIT: s = " (T)(8BIT)"; break;
6481 #ifdef UNICODE
6482 case FT_UTF8: s = " (T)(UTF8)"; break;
6483 case FT_UCS2:
6484 s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)";
6485 break;
6486 #endif /* UNICODE */
6487 case FT_BIN: s = " (B)"; break;
6488 }
6489 if (!*s) {
6490 s = binary ? " (B)" : " (T)";
6491 }
6492 if (*s) {
6493 int n;
6494 n = strlen(linebuf);
6495 if (n + 4 < CKMAXPATH - 58)
6496 strcpy(linebuf+n, s); /* safe (checked) */
6497 }
6498 }
6499 if (msg && dirmsg) {
6500 int n;
6501 n = strlen(linebuf);
6502 if (n + dirmsglen + 2 < CKMAXPATH)
6503 sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */
6504 }
6505 if (xsort) { /* Sorting - save line */
6506 i = strlen(linebuf);
6507 if ((ndirlist >= nx) ||
6508 !(dirlist[ndirlist] = (char *)malloc(i+1))) {
6509 printf("?Memory allocation error - try /NOSORT\n");
6510 rc = -9;
6511 goto xdomydir;
6512 }
6513 strcpy(dirlist[ndirlist],linebuf); /* safe */
6514 ndirlist++;
6515 }
6516 znext(name); /* Peek ahead to next file */
6517 if (!xsort) {
6518 if (!touch || (touch && verbose))
6519 fprintf(ofp,"%s\n",linebuf);
6520 if (page && (name[0] || heading)) { /* If /PAGE */
6521 if (cmd_cols > 0) {
6522 int x = strlen(linebuf);
6523 int y;
6524 y = (x % cmd_cols) ? 1 : 0;
6525 n += x / cmd_cols + y;
6526 } else {
6527 n++;
6528 }
6529 #ifdef CK_TTGWSIZ
6530 if (n > (cmd_rows - 3)) { /* Do more-prompting */
6531 if (!askmore()) {
6532 rc = 0;
6533 goto xdomydir;
6534 } else
6535 n = 0;
6536 }
6537 #endif /* CK_TTGWSIZ */
6538 }
6539 }
6540 }
6541 if (xsort) {
6542 int namepos;
6543 skey = 0;
6544 #ifdef VMS
6545 namepos = dlen + 35;
6546 switch (sortby) {
6547 case DIRS_NM: skey = namepos; break;
6548 case DIRS_DT: skey = 33; break;
6549 case DIRS_SZ: skey = 21;
6550 }
6551 #else
6552 if (p) {
6553 namepos = dlen + 24;
6554 switch (sortby) {
6555 case DIRS_NM: skey = namepos; break;
6556 case DIRS_DT: skey = 22; break;
6557 case DIRS_SZ: skey = 10;
6558 }
6559 } else {
6560 namepos = dlen + 14;
6561 switch (sortby) {
6562 case DIRS_NM: skey = namepos; break;
6563 case DIRS_DT: skey = 12; break;
6564 case DIRS_SZ: skey = 0;
6565 }
6566 }
6567 #endif /* VMS */
6568 if (reallysort) sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
6569 if (dir_top > 0 && dir_top < ndirlist)
6570 ndirlist = dir_top;
6571 for (i = 0; i < ndirlist; i++) {
6572 #ifndef NOSPL
6573 /* Storing result filenames in an array... */
6574 if (array) {
6575 char * name;
6576 name = dirlist[i] + namepos;
6577 debug(F111,"domydir array",name,nfiles);
6578 if (ap)
6579 makestr(&(ap[i+1]),name);
6580 continue;
6581 }
6582 #endif /* NOSPL */
6583 /* Printing the result filenames, size, date, etc... */
6584 fprintf(ofp,"%s\n",dirlist[i]);
6585 if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */
6586 if (cmd_cols > 0) {
6587 int x = strlen(dirlist[i]);
6588 int y;
6589 y = (x % cmd_cols) ? 1 : 0;
6590 n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
6591 } else {
6592 n++;
6593 }
6594 #ifdef CK_TTGWSIZ
6595 if (n > (cmd_rows - 3)) { /* Do more-prompting */
6596 if (!askmore()) {
6597 rc = 0;
6598 goto xdomydir;
6599 } else
6600 n = 0;
6601 }
6602 #endif /* CK_TTGWSIZ */
6603 }
6604 }
6605 #ifndef NOSPL
6606 if (array) {
6607 if (ap)
6608 makestr(&(ap[0]),ckitoa(ndirlist));
6609 rc = 1;
6610 goto xdomydir;
6611 }
6612 #endif /* NOSPL */
6613 }
6614 if (heading || summary) {
6615 #ifdef CKFLOAT
6616 CKFLOAT gm;
6617 #endif /* CKFLOAT */
6618 fprintf(ofp,"\n%ld director%s, %ld file%s, %s byte%s",
6619 ndirs,
6620 (ndirs == 1) ? "y" : "ies",
6621 nfiles,
6622 (nfiles == 1) ? "" : "s",
6623 ckfstoa(nbytes),
6624 (nbytes == 1) ? "" : "s"
6625 );
6626 #ifdef CKFLOAT
6627 gm = ((CKFLOAT) nbytes ) / 1000000.0;
6628 if (gm > 1000.0)
6629 fprintf(ofp," (%0.2fGB)",(gm / 1000.0));
6630 else if (gm >= 0.01)
6631 fprintf(ofp," (%0.2fMB)",gm);
6632 #endif /* CKFLOAD */
6633 fprintf(ofp,"\n\n");
6634 } else if (dir_cou && !cv) {
6635 fprintf(ofp,"\n Files: %ld\n\n",nfiles);
6636 }
6637 xdomydir:
6638 #ifndef NOSPL
6639 if (dir_cou && cv) { /* /COUNT:var */
6640 int n;
6641 n = totalchanges; /* Number of changes for CHANGE */
6642 if (cx != XXCHG) /* Number for files for DIRECTORY */
6643 n = nfiles;
6644 addmac(cv,ckitoa(n)); /* set the variable */
6645 makestr(&cv,NULL); /* free this */
6646 }
6647 if (ap) { /* If we have a result array */
6648 if (a_dim[arrayindex] > nmatches) /* but it was not filled */
6649 a_dim[arrayindex] = nmatches; /* adjust dimension */
6650 }
6651 #endif /* NOSPL */
6652 if (g_matchdot > -1) {
6653 matchdot = g_matchdot; /* Restore these... */
6654 g_matchdot = -1;
6655 }
6656 freedirlist();
6657 if (ofp != stdout) { /* Close any output file */
6658 if (ofp) fclose(ofp);
6659 ofp = stdout;
6660 }
6661 if (rc > 0)
6662 success = 1;
6663 return(rc);
6664 }
6665
6666 int
dodir(cx)6667 dodir(cx) int cx; { /* Do the DIRECTORY command */
6668 char *dc , *msg;
6669
6670 #ifdef OS2
6671 return(domydir(cx));
6672 #else /* OS2 */
6673 if (nopush
6674 #ifdef DOMYDIR /* Builds that domydir() by default */
6675 || (cx == XXDIR || cx == XXLDIR || cx == XXWDIR ||
6676 cx == XXHDIR || cx == XXTOUC || cx == XXCHG )
6677 #endif /* DOMYDIR */
6678 )
6679 return(domydir(cx)); /* Built-in directory command */
6680
6681 /* Use the system's directory command. */
6682
6683 msg = (cx == XXLS) ?
6684 "Arguments for ls" :
6685 "Directory and/or file specification";
6686 if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
6687 return(x);
6688
6689 ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy the filespec */
6690 s = tmpbuf;
6691
6692 if ((y = cmcfm()) < 0) return(y);
6693
6694 lp = line;
6695 if (!(dc = getenv("CK_DIR")))
6696 dc = DIRCMD;
6697 ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL);
6698 debug(F110,"DIR",line,0);
6699 #ifdef VMS
6700 conres();
6701 #endif /* VMS */
6702 x = zshcmd(line);
6703 #ifdef VMS
6704 concb((char)escape);
6705 #endif /* VMS */
6706 return(success = (x < 1) ? 0 : 1);
6707 #endif /* OS2 */
6708 }
6709
6710 #ifndef NOSERVER
6711 #ifndef NOFRILLS
6712 /* Do the ENABLE and DISABLE commands */
6713
6714 int
doenable(y,x)6715 doenable(y,x) int y, x; {
6716 #ifdef CK_LOGIN
6717 if (isguest) /* IKSD: Don't let guests */
6718 return(0); /* enable anything that's disabled */
6719 #endif /* CK_LOGIN */
6720 switch (x) {
6721 case EN_ALL:
6722 en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
6723 en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
6724 if (!inserver)
6725 en_who = en_mai = en_pri = y;
6726 en_mkd = en_rmd = y;
6727 en_xit = y;
6728 #ifndef datageneral
6729 en_bye = y;
6730 #endif /* datageneral */
6731 #ifndef NOPUSH
6732 if (!nopush && !inserver)
6733 en_hos = y;
6734 #endif /* NOPUSH */
6735 #ifndef NOSPL
6736 en_asg = en_que = y;
6737 #endif /* NOSPL */
6738 break;
6739
6740 case EN_BYE:
6741 #ifndef datageneral
6742 /*
6743 In Data General AOS/VS Kermit can't log out its superior process.
6744 */
6745 en_bye = y;
6746 #endif /* datageneral */
6747 break;
6748 case EN_CPY:
6749 en_cpy = y;
6750 break;
6751 case EN_CWD:
6752 en_cwd = y;
6753 #ifdef IKSD
6754 if (inserver && y == 0) {
6755 fnrpath = PATH_OFF;
6756 fnspath = PATH_OFF;
6757 }
6758 #endif /* IKSD */
6759 break;
6760 case EN_DEL: /* Deleting of files */
6761 en_del = y;
6762 break;
6763 case EN_DIR:
6764 en_dir = y;
6765 break;
6766 case EN_FIN:
6767 en_fin = y;
6768 break;
6769 case EN_GET:
6770 en_get = y;
6771 break;
6772 #ifndef NOPUSH
6773 case EN_HOS:
6774 if (!nopush)
6775 en_hos = y;
6776 break;
6777 #endif /* NOPUSH */
6778 case EN_REN:
6779 en_ren = y;
6780 break;
6781 case EN_SEN:
6782 en_sen = y;
6783 break;
6784 case EN_SET:
6785 en_set = y;
6786 break;
6787 case EN_SPA:
6788 en_spa = y;
6789 break;
6790 case EN_TYP:
6791 en_typ = y;
6792 break;
6793 case EN_WHO:
6794 en_who = y;
6795 break;
6796 #ifndef NOSPL
6797 case EN_ASG:
6798 en_asg = y;
6799 break;
6800 case EN_QUE:
6801 en_que = y;
6802 break;
6803 #endif /* NOSPL */
6804 case EN_RET:
6805 en_del = y;
6806 break;
6807 case EN_MAI:
6808 #ifdef CK_LOGIN
6809 if (isguest && y) {
6810 printf("?Sorry, not valid for guests\n");
6811 return(-9);
6812 }
6813 #endif /* CK_LOGIN */
6814 en_mai = y;
6815 break;
6816 case EN_PRI:
6817 #ifdef CK_LOGIN
6818 if (isguest && y) {
6819 printf("?Sorry, not valid for guests\n");
6820 return(-9);
6821 }
6822 #endif /* CK_LOGIN */
6823 en_pri = y;
6824 break;
6825 case EN_MKD:
6826 en_mkd = y;
6827 break;
6828 case EN_RMD:
6829 en_rmd = y;
6830 break;
6831 case EN_XIT:
6832 en_xit = y;
6833 break;
6834 case EN_ENA:
6835 if (((y & 1) && !(en_ena & 1)) ||
6836 ((y & 2) && !(en_ena & 2))) {
6837 printf("?Sorry, DISABLE ENABLE can not be undone\n");
6838 return(-9);
6839 } else {
6840 en_ena = y;
6841 break;
6842 }
6843 default:
6844 return(-2);
6845 }
6846 return(1);
6847 }
6848 #endif /* NOFRILLS */
6849 #endif /* NOSERVER */
6850
6851 #ifndef NOFRILLS
6852
6853 static int del_lis = 0;
6854 static int del_dot = 0;
6855 static int del_hdg = 0;
6856 static int del_pag = -1;
6857 static int del_ask = 0;
6858
6859 #ifndef NOSHOW
6860 VOID
showdelopts()6861 showdelopts() {
6862 int x = 0;
6863 extern int optlines;
6864 prtopt(&optlines,"");
6865 prtopt(&optlines,"DELETE");
6866 if (del_ask > -1) {
6867 prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
6868 x++;
6869 }
6870 #ifdef UNIXOROSK
6871 if (del_dot > -1) {
6872 prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
6873 x++;
6874 }
6875 #endif /* UNIXOROSK */
6876 if (del_lis > -1) {
6877 prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
6878 x++;
6879 }
6880 if (del_hdg > -1) {
6881 prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
6882 x++;
6883 }
6884 #ifndef CK_TTGWSIZ
6885 if (del_pag > -1) {
6886 prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
6887 x++;
6888 }
6889 #endif /* CK_TTGWSIZ */
6890 if (!x) prtopt(&optlines,"(no options set)");
6891 prtopt(&optlines,"");
6892 }
6893 #endif /* NOSHOW */
6894
6895
6896 int
setdelopts()6897 setdelopts() {
6898 int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
6899 int getval = 0;
6900 char c;
6901 while (1) {
6902 if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
6903 if (y == -3)
6904 break;
6905 else
6906 return(y);
6907 }
6908 c = cmgbrk();
6909 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
6910 printf("?This switch does not take an argument\n");
6911 return(-9);
6912 }
6913 if (!getval && (cmgkwflgs() & CM_ARG)) {
6914 printf("?This switch requires an argument\n");
6915 return(-9);
6916 }
6917 switch (y) {
6918 case DEL_DOT:
6919 x_dot = 1;
6920 break;
6921 case DEL_NOD:
6922 x_dot = 0;
6923 break;
6924 case DEL_HDG:
6925 x_hdg = 1;
6926 break;
6927 case DEL_LIS:
6928 x_lis = 1;
6929 break;
6930 case DEL_NOL:
6931 x_lis = 0;
6932 break;
6933 #ifndef CK_TTGWSIZ
6934 case DEL_PAG:
6935 x_pag = 1;
6936 break;
6937 case DEL_NOP:
6938 x_pag = 0;
6939 break;
6940 #endif /* CK_TTGWSIZ */
6941 case DEL_QUI:
6942 x_lis = 0;
6943 break;
6944 case DEL_VRB:
6945 x_lis = 1;
6946 break;
6947 case DEL_ASK:
6948 x_ask = 1;
6949 break;
6950 case DEL_NAS:
6951 x_ask = 0;
6952 break;
6953 default:
6954 printf("?Sorry, this option can not be set\n");
6955 return(-9);
6956 }
6957 }
6958 if ((x = cmcfm()) < 0) /* Get confirmation */
6959 return(x);
6960 if (x_pag > -1) del_pag = x_pag;
6961 if (x_dot > -1) del_dot = x_dot;
6962 if (x_hdg > -1) del_hdg = x_hdg;
6963 if (x_lis > -1) del_lis = x_lis;
6964 if (x_ask > -1) del_ask = x_ask;
6965 return(success = 1);
6966 }
6967
6968 #ifdef OS2
6969 static char ** xmtchs = NULL;
6970 static int xmtchn = 0;
6971 #endif /* OS2 */
6972
6973 int
dodel()6974 dodel() { /* DELETE */
6975 int i, j, k, x;
6976 int fs = 0; /* Need to call fileselect() */
6977 int len = 0;
6978 int bad = 0;
6979 int getval = 0, asking = 0;
6980 int simulate = 0, rc = 0;
6981 CK_OFF_T minsize = -1L, maxsize = -1L;
6982 int havename = 0, confirmed = 0;
6983 int qflag = 0;
6984 int summary = 0;
6985 int deldirs = 0;
6986 int deltree = 0;
6987 int itsadir = 0;
6988 int argisdir = 0;
6989 int xmode = -1, scan = 0, skip = 0;
6990 #ifdef COMMENT
6991 int pass = 0;
6992 #endif /* COMMENT */
6993 char c;
6994 char * deldef = "";
6995 char safebuf[CKMAXPATH+1];
6996 struct FDB sw, fi, fl;
6997 char
6998 * del_aft = NULL,
6999 * del_bef = NULL,
7000 * del_naf = NULL,
7001 * del_nbf = NULL,
7002 * del_exc = NULL;
7003 int
7004 x_lis = 0,
7005 /* x_dot = -1, */
7006 x_hdg = 0;
7007
7008 char * dxlist[8];
7009
7010 for (i = 0; i < 8; i++) dxlist[i] = NULL;
7011
7012 g_matchdot = matchdot;
7013
7014 if (del_lis > -1) x_lis = del_lis;
7015 if (del_dot > -1) matchdot = del_dot;
7016 if (del_hdg > -1) x_hdg = del_hdg;
7017 if (del_pag > -1) xaskmore = del_pag;
7018 if (del_ask > -1) asking = del_ask;
7019
7020 diractive = 1;
7021 nolinks = 2; /* By default don't follow links */
7022
7023 cmfdbi(&sw, /* First FDB - command switches */
7024 _CMKEY, /* fcode */
7025 "File specification;\n or switch",
7026 "", /* default */
7027 "", /* addtl string data */
7028 ndeltab, /* addtl numeric data 1: tbl size */
7029 4, /* addtl numeric data 2: 4 = cmswi */
7030 xxstring, /* Processing function */
7031 deltab, /* Keyword table */
7032 &fi /* Pointer to next FDB */
7033 );
7034 cmfdbi(&fl, /* Anything that doesn't match */
7035 _CMFLD, /* fcode */
7036 "", /* hlpmsg */
7037 "", /* default */
7038 "", /* addtl string data */
7039 0, /* addtl numeric data 1 */
7040 0, /* addtl numeric data 2 */
7041 xxstring,
7042 NULL,
7043 NULL
7044 );
7045 again:
7046 cmfdbi(&fi, /* 2nd FDB - file to delete */
7047 _CMIFI, /* fcode */
7048 "File(s) to delete", /* hlpmsg */
7049 deldef, /* default */
7050 "", /* addtl string data */
7051 nolinks | deldirs, /* 0 = files, 1 = files or dirs */
7052 0, /* 1 = dirs only */
7053 xxstring,
7054 NULL,
7055 &fl
7056 );
7057 while (!havename && !confirmed) {
7058 x = cmfdb(&sw); /* Parse something */
7059 if (x < 0) { /* Error */
7060 if (x == -3)
7061 break;
7062 if (x == -2 || x == -9)
7063 printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
7064 return(x);
7065 }
7066 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
7067 break;
7068 c = cmgbrk(); /* Get break character */
7069 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
7070 printf("?This switch does not take an argument\n");
7071 rc = -9;
7072 goto xdelete;
7073 }
7074 if (!getval && (cmgkwflgs() & CM_ARG)) {
7075 printf("?This switch requires an argument\n");
7076 rc = -9;
7077 goto xdelete;
7078 }
7079 switch (k = cmresult.nresult) {
7080 case DEL_AFT:
7081 case DEL_BEF:
7082 case DEL_NAF:
7083 case DEL_NBF:
7084 if (!getval) break;
7085 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
7086 if (x == -3) {
7087 printf("?Date-time required\n");
7088 x = -9;
7089 } else
7090 rc = x;
7091 goto xdelete;
7092 }
7093 fs++;
7094 deltree = 0;
7095 switch (k) {
7096 case DEL_AFT: makestr(&del_aft,s); break;
7097 case DEL_BEF: makestr(&del_bef,s); break;
7098 case DEL_NAF: makestr(&del_naf,s); break;
7099 case DEL_NBF: makestr(&del_nbf,s); break;
7100 }
7101 break;
7102 case DEL_DOT:
7103 matchdot = 1;
7104 break;
7105 case DEL_NOD:
7106 matchdot = 0;
7107 break;
7108 case DEL_ALL:
7109 fs = 0;
7110 #ifdef VMS
7111 deldef = "*.*"; /* UNIX, Windows, OS/2 */
7112 #else
7113 #ifdef datageneral
7114 deldef = "+"; /* AOS/VS */
7115 #else
7116 deldef = "*"; /* UNIX, Windows, OS/2, VMS... */
7117 #endif /* datageneral */
7118 #endif /* VMS */
7119 deltree = 1;
7120 nolinks = 2;
7121 matchdot = 1;
7122 recursive = 1; /* Fall through purposely... */
7123 case DEL_DIR:
7124 deldirs = 1;
7125 goto again;
7126 case DEL_EXC:
7127 if (!getval) break;
7128 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
7129 if (x == -3) {
7130 printf("?Pattern required\n");
7131 x = -9;
7132 } else
7133 rc = x;
7134 goto xdelete;
7135 }
7136 fs++;
7137 deltree = 0;
7138 makestr(&del_exc,s);
7139 break;
7140 case DEL_HDG:
7141 x_hdg = 1;
7142 break;
7143 #ifdef RECURSIVE
7144 case DEL_REC:
7145 recursive = 1;
7146 break;
7147 #endif /* RECURSIVE */
7148 case DEL_LIS:
7149 x_lis = 1;
7150 break;
7151 case DEL_SUM:
7152 summary = 1;
7153 x_lis = 0;
7154 x_hdg = 1;
7155 break;
7156 case DEL_NOL:
7157 x_lis = 0;
7158 break;
7159 #ifndef CK_TTGWSIZ
7160 case DEL_PAG:
7161 xaskmore = 1;
7162 break;
7163 case DEL_NOP:
7164 xaskmore = 0;
7165 break;
7166 #endif /* CK_TTGWSIZ */
7167 case DEL_QUI:
7168 qflag = 1;
7169 x_lis = 0;
7170 break;
7171 case DEL_VRB:
7172 x_lis = 1;
7173 break;
7174
7175 case DEL_SMA:
7176 case DEL_LAR:
7177 if (!getval) break;
7178 if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
7179 return(x);
7180 fs++;
7181 deltree = 0;
7182 switch (cmresult.nresult) {
7183 case DEL_SMA: minsize = y; break;
7184 case DEL_LAR: maxsize = y; break;
7185 }
7186 break;
7187
7188 case DEL_SIM:
7189 simulate = 1;
7190 x_lis = 1;
7191 break;
7192 case DEL_ASK:
7193 asking = 1;
7194 break;
7195 case DEL_NAS:
7196 asking = 0;
7197 break;
7198 case DEL_TYP: {
7199 extern struct keytab txtbin[];
7200 if (!getval) break;
7201 if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
7202 return(x);
7203 if (x == 2) { /* ALL */
7204 xmode = -1;
7205 } else { /* TEXT or BINARY only */
7206 xmode = x;
7207 scan = 1;
7208 }
7209 break;
7210 }
7211 default:
7212 printf("?Not implemented yet - \"%s\"\n",atmbuf);
7213 return(-9);
7214 }
7215 }
7216 if (qflag && (cmresult.fcode == _CMFLD)) {
7217 if ((x = cmcfm()) < 0)
7218 return(x);
7219 else
7220 return(success = 0);
7221 }
7222 if (cmresult.fcode != _CMIFI) {
7223 if (*atmbuf) {
7224 int x;
7225 if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
7226 printf("?No files match: %s\n",brstrip(atmbuf));
7227 else if ((x = zchki(atmbuf)) == -1)
7228 printf("?File not found: %s\n",brstrip(atmbuf));
7229 else if (x == -2)
7230 printf("?Not a regular file: %s\n",atmbuf);
7231 else
7232 /* printf("?Not a deletable file: %s\n",atmbuf); */
7233 goto tryanyway;
7234 } else {
7235 printf("?A file specification is required\n");
7236 }
7237 return(-9);
7238 }
7239 tryanyway:
7240 ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
7241 if (deldirs) {
7242 ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH);
7243 #ifdef VMSORUNIX
7244 len = zgetfs(tmpbuf); /* Is it a directory name? */
7245 argisdir = zgfs_dir; /* Then because of how zxpand() */
7246 if (argisdir && zgfs_link) /* works, we have to add it to */
7247 argisdir = 0; /* the list. */
7248 if (itsadir)
7249 len = -2;
7250 #else
7251 len = zchki(tmpbuf);
7252 if (len < 0)
7253 argisdir = isdir(tmpbuf);
7254 #endif /* VMSORUNIX */
7255 }
7256 debug(F110,"DELETE file",tmpbuf,0);
7257 if ((x = cmcfm()) < 0)
7258 return(x);
7259
7260 #ifdef IKSD
7261 #ifdef CK_LOGIN
7262 if (inserver && isguest) {
7263 printf("?Sorry, DELETE unavailable to guests\n");
7264 return(-9);
7265 }
7266 #endif /* CK_LOGIN */
7267 #endif /* IKSD */
7268
7269 #ifndef OS2ORUNIX
7270 if (simulate) {
7271 printf("?Sorry, /SIMULATE not implemented on this platform\n");
7272 return(-9);
7273 }
7274 #endif /* OS2ORUNIX */
7275
7276 #ifdef COMMENT
7277 /* (not needed) */
7278 if (!iswild(tmpbuf)) {
7279 char *m;
7280 errno = 0;
7281 x = zchki(tmpbuf);
7282 if (x < 0) {
7283 switch (x) {
7284 case -2: m = "Not a regular file"; break;
7285 case -1: m = "File not found or not accessible"; break;
7286 default: m = errno ? ck_errstr() : "Can't delete";
7287 }
7288 printf("?%s: \"%s\"\n",m,tmpbuf);
7289 return(-9);
7290 }
7291 }
7292 #endif /* COMMENT */
7293
7294 makelist(del_exc,dxlist,8);
7295
7296 /* tmpbuf[] has the name - now do any needed conversions on it */
7297
7298 #ifdef OS2
7299 { /* Lower level functions change / to \, not good for CMD.EXE. */
7300 char *p = tmpbuf;
7301 while (*p) { /* Change them back to \ */
7302 if (*p == '/') *p = '\\';
7303 p++;
7304 }
7305 }
7306 #endif /* OS2 */
7307
7308 #ifdef VMS
7309 if (iswild(tmpbuf)) {
7310 #ifdef COMMENT
7311 /* Does not handle '.' as version separator */
7312 char *p = tmpbuf;
7313 x = 0;
7314 while (*p) {
7315 if (*p == ';') {
7316 x = 1;
7317 break;
7318 } else
7319 p++;
7320 }
7321 if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ);
7322 #else
7323 j = 0; x = 0; /* for end_dot and number of dots */
7324 i = strlen(tmpbuf);
7325 if (tmpbuf[i] == ';') {
7326 ckstrncat(tmpbuf,"0",TMPBUFSIZ);
7327 } else {
7328 if (tmpbuf[i--] == '.')
7329 j++;
7330 for (; i >= 0; i--) {
7331 if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
7332 tmpbuf[i] == ']' || tmpbuf[i] == '>')
7333 break;
7334 else if (tmpbuf[i] == '.')
7335 x++;
7336 }
7337 if (tmpbuf[i] != ';') { /* dot may have been used */
7338 if (j) { /* last char is dot */
7339 if (x) /* second is version separator */
7340 ckstrncat(tmpbuf,"0",TMPBUFSIZ);
7341 else /* 'foo.' */
7342 ckstrncat(tmpbuf,";0",TMPBUFSIZ);
7343 } else if (x == 1) /* lacking a version separator */
7344 ckstrncat(tmpbuf,";0",TMPBUFSIZ);
7345 else if (x == 0) /* x == 2 has a version */
7346 ckstrncat(tmpbuf,".*;0",TMPBUFSIZ);
7347 }
7348 }
7349 #endif /* COMMENT */
7350 }
7351 #endif /* VMS */
7352
7353 debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
7354
7355 #ifndef OS2ORUNIX /* No built-in DELETE code... */
7356 /* Construct system command. */
7357 ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL);
7358 #else
7359 #ifdef VMS
7360 if (asking) { /* Maybe overwrite in VMS */
7361 if (x_lis) /* if options are needed... */
7362 ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL);
7363 else
7364 ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL);
7365 } else if (x_lis)
7366 ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL);
7367 conres();
7368 #endif /* VMS */
7369
7370 debug(F110,"dodel line",line,0);
7371 #endif /* OS2ORUNIX */
7372
7373 #ifdef MAC
7374 success = (zdelet(tmpbuf) == 0);
7375
7376 #else /* !MAC ... */
7377
7378 #ifdef OS2ORUNIX
7379 {
7380 int filespace = 0;
7381 int count = 0;
7382 int lines = 0;
7383 int n = 0;
7384
7385 s = tmpbuf;
7386
7387 #ifdef CK_TTGWSIZ
7388 #ifdef OS2
7389 ttgcwsz();
7390 #else /* OS2 */
7391 /* Check whether window size changed */
7392 if (ttgwsiz() > 0) {
7393 if (tt_rows > 0 && tt_cols > 0) {
7394 cmd_rows = tt_rows;
7395 cmd_cols = tt_cols;
7396 }
7397 }
7398 #endif /* OS2 */
7399 #endif /* CK_TTGWSIZ */
7400
7401 if (x_hdg > 0 && !summary) {
7402 printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
7403 n += 2;
7404 }
7405 #ifdef ZXREWIND
7406 z = zxrewind(); /* Rewind file list */
7407 #else
7408 if (!deldirs)
7409 nzxopts = ZX_FILONLY;
7410 if (recursive) nzxopts |= ZX_RECURSE;
7411 if (matchdot) nzxopts |= ZX_MATCHDOT;
7412 errno = 0;
7413 z = nzxpand(s,nzxopts); /* Expand file list */
7414 #endif /* ZXREWIND */
7415 debug(F111,"dodel",s,z);
7416
7417 /* If deleting directories, sort in reverse order */
7418 /* so we delete the files first, then the directory. */
7419
7420 #ifdef OS2
7421 /* In K95, we have no mtchs array, nor any control over */
7422 /* the order in which znext() returns filenames, so we */
7423 /* must copy the array and sort it. */
7424 {
7425 int i;
7426 if (xmtchs) { /* Free previous list in case */
7427 debug(F101,"dodel freeing previous list","",xmtchn);
7428 for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */
7429 if (xmtchs[i])
7430 free(xmtchs[i]);
7431 free(xmtchs);
7432 }
7433 xmtchn = 0;
7434 xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */
7435 if (!xmtchs) {
7436 printf("?Memory allocation failure\n");
7437 return(-9);
7438 }
7439 for (i = 0; i < z; i++) {
7440 xmtchs[i] = NULL;
7441 znext(tmpbuf);
7442 if (!*tmpbuf)
7443 break;
7444 makestr(&(xmtchs[i]),tmpbuf);
7445 if (!xmtchs[i]) {
7446 printf("?Memory allocation failure\n");
7447 xmtchn = i - 1;
7448 rc = -9;
7449 goto xdelete;
7450 }
7451 /* debug(F111,"dodel add",xmtchs[i],i); */
7452 }
7453 xmtchn = i;
7454 debug(F101,"dodel xmtchn","",xmtchn);
7455 sh_sort(xmtchs,NULL,z,0,deldirs,0);
7456 }
7457 #else
7458 #ifdef UNIX
7459 sh_sort(mtchs,NULL,z,0,deldirs,filecase);
7460 #endif /* UNIX */
7461 #endif /* OS2 */
7462
7463 if (z > 0) {
7464 int i;
7465 #ifdef OS2
7466 int ix = 0;
7467 #endif /* OS2 */
7468 success = 1;
7469 if (x_hdg > 0)
7470 printf("\n");
7471
7472 while (
7473 #ifdef OS2
7474 ix < xmtchn
7475 #else
7476 1
7477 #endif /* OS2 */
7478 ) { /* Loop for all files */
7479 #ifdef OS2
7480 ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ);
7481 #else
7482 znext(tmpbuf); /* Get next file */
7483 #endif /* OS2 */
7484 if (!*tmpbuf) { /* No more */
7485 if (deldirs && recursive && argisdir) {
7486 ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ);
7487 argisdir = 0; /* (only do this once) */
7488 } else
7489 break;
7490 }
7491 skip = 0;
7492 if (!deltree) {
7493 if (fs)
7494 if (fileselect(tmpbuf,
7495 del_aft,del_bef,del_naf,del_nbf,
7496 minsize,maxsize,0,8,dxlist) < 1) {
7497 skip++;
7498 }
7499 }
7500 if (!skip && scan && itsadir) {
7501 skip++;
7502 }
7503 if (!skip && scan) {
7504 switch (scanfile(tmpbuf,&y,nscanfile)) {
7505 case FT_BIN:
7506 if (xmode != 1)
7507 skip++;
7508 break;
7509 case FT_TEXT:
7510 case FT_7BIT:
7511 case FT_8BIT:
7512 #ifdef UNICODE
7513 case FT_UTF8:
7514 case FT_UCS2:
7515 #endif /* UNICODE */
7516 if (xmode != 0)
7517 skip++;
7518 }
7519 }
7520 if (!skip && asking) {
7521 int x;
7522 ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL);
7523 x = getyesno(line,3);
7524 switch (x) {
7525 case 0: continue; /* no */
7526 case 1: break; /* yes */
7527 case 2: goto xdelete; /* quit */
7528 case 3: asking = 0; break; /* go */
7529 }
7530 }
7531 #ifdef VMSORUNIX
7532 len = zgetfs(tmpbuf); /* Get length and accessibility */
7533 itsadir = zgfs_dir;
7534 if (itsadir && zgfs_link) { /* Treat links to directories */
7535 itsadir = 0; /* as regular files */
7536 if (scan) /* But not if /TYPE: was given */
7537 skip++;
7538 }
7539 if (itsadir) /* (emulate non-Unix code) */
7540 len = -2;
7541 #else
7542 len = zchki(tmpbuf); /* Get accessibility */
7543 if (len < 0) /* See if it's a directory */
7544 itsadir = isdir(tmpbuf);
7545 #endif /* VMSORUNIX */
7546
7547 if (skip) {
7548 #ifdef COMMENT /* Too verbose */
7549 if (x_lis > 0) {
7550 lines++;
7551 printf(" %s (SKIPPED)\n",tmpbuf);
7552 #ifdef CK_TTGWSIZ
7553 if (++n > cmd_rows - 3)
7554 if (!askmore()) goto xdelete; else n = 0;
7555 #endif /* CK_TTGWSIZ */
7556 }
7557 #endif /* COMMENT */
7558 continue;
7559 }
7560
7561 debug(F111,"DELETE len",tmpbuf,len);
7562 if (simulate) {
7563 filespace += len;
7564 count++;
7565 if (x_lis > 0) {
7566 lines++;
7567 printf(" %s (SELECTED)\n",tmpbuf);
7568 if (++n > cmd_rows - 3) {
7569 int xx;
7570 xx = askmore();
7571 if (!xx) goto xdelete; else n = 0;
7572 }
7573 }
7574 } else if (len >= 0 || !itsadir) { /* Regular file */
7575 zdelet(tmpbuf); /* or symlink, etc... */
7576 if (zchki(tmpbuf) < 0) {
7577 filespace += len;
7578 count++;
7579 if (x_lis > 0) {
7580 lines++;
7581 printf(" %s (OK)\n",tmpbuf);
7582 if (++n > cmd_rows - 3)
7583 if (!askmore()) goto xdelete; else n = 0;
7584 }
7585 } else {
7586 bad++;
7587 success = 0;
7588 if (x_lis > 0) {
7589 lines++;
7590 printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr());
7591 if (++n > cmd_rows - 3)
7592 if (!askmore()) goto xdelete; else n = 0;
7593 }
7594 }
7595 } else if (/* pass > 0 && */ deldirs && itsadir) {
7596 /* It's a directory */
7597 if (zrmdir(tmpbuf) > -1) { /* Only works if empty */
7598 count++;
7599 if (x_lis > 0) {
7600 lines++;
7601 printf(" %s (OK)\n",tmpbuf);
7602 if (++n > cmd_rows - 3)
7603 if (!askmore()) goto xdelete; else n = 0;
7604 }
7605 } else {
7606 success = 0;
7607 if (x_lis > 0) {
7608 lines++;
7609 printf(" %s (FAILED: %s)\n",
7610 tmpbuf,
7611 ck_errstr());
7612 if (++n > cmd_rows - 3)
7613 if (!askmore()) goto xdelete; else n = 0;
7614 }
7615 }
7616 } else if (x_lis > 0) {
7617 lines++;
7618 if (isdir(tmpbuf))
7619 printf(" %s (FAILED: directory)\n",tmpbuf);
7620 else
7621 printf(" %s (FAILED: not a regular file)\n",tmpbuf);
7622 if (++n > cmd_rows - 3)
7623 if (!askmore()) goto xdelete; else n = 0;
7624 }
7625 }
7626 if (x_hdg > 0) {
7627 if (lines > 0)
7628 printf("\n");
7629 if (++n > cmd_rows - 3)
7630 if (!askmore()) goto xdelete; else n = 0;
7631 printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
7632 count,
7633 count != 1 ? "s" : "",
7634 simulate ? "would be " : "",
7635 filespace,
7636 filespace != 1 ? "s" : "",
7637 simulate ? "would be " : "",
7638 simulate ? " (maybe)" : ""
7639 );
7640 }
7641 if (!x_lis && !success && !quiet) {
7642 printf("?DELETE failed for %d file%s \
7643 (use DELETE /LIST to see details)\n",
7644 bad, bad == 1 ? "" : "s"
7645 );
7646 }
7647 } else if (x_lis > 0) {
7648 if (errno)
7649 printf("?%s: %s\n",ck_errstr(), tmpbuf);
7650 else
7651 printf("?Can't delete: %s\n",tmpbuf);
7652 }
7653 }
7654 #else /* OS2ORUNIX */
7655 #ifndef VMS /* Others - let the system do it. */
7656 xsystem(line);
7657 x = nzxpand(tmpbuf,nzxopts);
7658 success = (x > 0) ? 0 : 1;
7659 if (x_hdg > 0)
7660 printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
7661 #else
7662 if (asking)
7663 printf("\n");
7664 x = xsystem(line); /* zshcmd returns 1 for success */
7665 success = (x > 0) ? 1 : 0;
7666 if (x_hdg > 0 && !asking)
7667 printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
7668 concb((char)escape);
7669 #endif /* VMS */
7670 #endif /* OS2ORUNIX */
7671 #endif /* MAC */
7672 xdelete:
7673 if (g_matchdot > -1) {
7674 matchdot = g_matchdot; /* Restore these... */
7675 g_matchdot = -1;
7676 }
7677 #ifdef OS2
7678 if (xmtchs) {
7679 int i;
7680 debug(F101,"dodel freeing list","",xmtchn);
7681 for (i = 0; i < xmtchn; i++)
7682 if (xmtchs[i]) free(xmtchs[i]);
7683 free(xmtchs);
7684 xmtchs = NULL;
7685 xmtchn = 0;
7686 }
7687 #endif /* OS2 */
7688 debug(F101,"dodel result","",rc);
7689 return((rc < 0) ? rc : success);
7690 }
7691 #endif /* NOFRILLS */
7692
7693 #ifndef NOSPL /* The ELSE command */
7694 _PROTOTYP( VOID pushqcmd, (char *) );
7695
7696 int
doelse()7697 doelse() {
7698 if (!ifcmd[cmdlvl]) {
7699 printf("?ELSE doesn't follow IF\n");
7700 return(-2);
7701 }
7702 #ifdef COMMENT
7703 /*
7704 Wrong. This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
7705 from working.
7706 */
7707 ifcmd[cmdlvl] = 0;
7708 #endif /* COMMENT */
7709 if (!iftest[cmdlvl]) { /* If IF was false do ELSE part */
7710 if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
7711 debug(F100,"doelse pushing","",0);
7712 #ifndef COMMENT
7713 pushcmd(NULL); /* save rest of command. */
7714 #else
7715 /* This fixes certain obscure problems */
7716 /* but breaks many other constructions that must work. */
7717 pushqcmd(NULL);
7718 #endif /* COMMENT */
7719 } else { /* If interactive, */
7720 cmini(ckxech); /* just start a new command */
7721 printf("\n"); /* (like in MS-DOS Kermit) */
7722 if (pflag) prompt(xxstring);
7723 }
7724 } else { /* Condition is false */
7725 if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
7726 return(y); /* Gobble up rest of line */
7727 }
7728 return(0);
7729 }
7730 #endif /* NOSPL */
7731
7732 #ifndef NOSPL
7733 int
doswitch()7734 doswitch() {
7735 char *lp, *ap; /* Macro argument pointer */
7736 int len = 0, x, y, pp = 0;
7737 char brbuf[3];
7738
7739 /* Get variable name */
7740
7741 tmpbuf[0] = NUL;
7742 brbuf[0] = '{';
7743 brbuf[1] = '}';
7744 brbuf[2] = NUL;
7745
7746 y = cmfld("Variable name","",&s,xxstring);
7747 debug(F111,"doswitch cmfld",s,y);
7748 if (y < 0) {
7749 if (y == -3) /* Because brstrip() writes */
7750 s = brbuf; /* into its argument. */
7751 else
7752 return(y);
7753 }
7754 debug(F110,"doswitch A",s,0);
7755 if (!strcmp(s,"(")) {
7756 pp++;
7757 if ((y = cmfld("Variable name","",&s,xxstring)) < 0) {
7758 if (y == -3)
7759 s = brbuf;
7760 else
7761 return(y);
7762 debug(F110,"doswitch B",s,0);
7763 }
7764 }
7765 len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
7766 if (tmpbuf[0] == CMDQ) {
7767 if (chkvar(s) < 1) {
7768 printf("?Variable name required\n");
7769 return(-9);
7770 }
7771 }
7772 if (pp > 0) { /* If open paren given parse closing */
7773 if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
7774 return(y);
7775 if (strcmp(atmbuf,")")) {
7776 printf("?Closing parenthesis required\n");
7777 return(-9);
7778 }
7779 }
7780 lp = line;
7781 x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */
7782 lp += x;
7783 ap = lp;
7784 debug(F010,"SWITCH a",line,0);
7785
7786 #ifdef COMMENT
7787 x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */
7788 #else
7789 { /* variable name + SP */
7790 char * p = tmpbuf;
7791 if (len > 0) {
7792 if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') {
7793 tmpbuf[len-1] = NUL;
7794 p++;
7795 }
7796 }
7797 x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," ");
7798 }
7799 #endif /* COMMENT */
7800 debug(F010,"SWITCH b",line,0);
7801 lp += x;
7802
7803 /* Get body */
7804
7805 if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
7806 if ((y = (int)strlen(s)) < 1) return(-2);
7807 if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
7808 ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
7809 s = tmpbuf;
7810 }
7811 if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
7812 printf("?Unbalanced braces\n");
7813 return(0);
7814 }
7815 debug(F010,"SWITCH c",line,0);
7816
7817 x = mlook(mactab,"_switx",nmac); /* Look up SWITCH macro definition */
7818 if (x < 0) { /* Not there? */
7819 addmmac("_switx",sw_def); /* Put it back. */
7820 if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
7821 printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
7822 return(success = 0);
7823 }
7824 }
7825 debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */
7826 success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC);
7827 debug(F101,"SWITCH status","",success);
7828 return(success);
7829 }
7830
7831 int
dofor()7832 dofor() { /* The FOR command. */
7833 int i, fx, fy, fz; /* loop variables */
7834 char *ap, *di; /* macro argument pointer */
7835 int pp = 0; /* Paren level */
7836 int mustquote = 0;
7837 char loopvar[8], loopvar2[8]; /* \%x-style loop variable */
7838
7839 debug(F100,"dofor entry","",0);
7840 for (i = 0; i < 2; i++) {
7841 if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
7842 if (y == -3) {
7843 printf("?Variable name required\n");
7844 return(-9);
7845 } else
7846 return(y);
7847 }
7848 if (strcmp(s,"("))
7849 break;
7850 pp++;
7851 }
7852 #ifdef COMMENT
7853 if ((y = parsevar(s,&x,&z)) < 0) /* Check variable. */
7854 return(y);
7855 #else
7856 if (*s == CMDQ) /* If loop variable starts with */
7857 mustquote++; /* backslash, mustquote is > 0. */
7858 #endif /* COMMENT */
7859 debug(F111," dofor loop variable mustquote",s,mustquote);
7860
7861 lp = line; /* Build a copy of the command */
7862 ckstrncpy(lp,"_forx ",LINBUFSIZ);
7863 lp += (int)strlen(line); /* "_for" macro. */
7864 ap = lp; /* Save pointer to macro args. */
7865
7866 if (*s == CMDQ) s++; /* Skip past backslash if any. */
7867 while ((*lp++ = *s++)) ; /* copy it */
7868 lp--; *lp++ = SP; /* add a space */
7869
7870 if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
7871 if (y == -3) return(-2);
7872 else return(y);
7873 }
7874 debug(F101," dofor fx","",fx);
7875 s = atmbuf; /* Copy the atom buffer */
7876
7877 if ((int)strlen(s) < 1) goto badfor;
7878 /*
7879 In edit 192, we change the loop variables to be evaluated at loop entry,
7880 not each time through the loop. This was required in order to allow
7881 \v(argc) to be used as a loop variable, or in a loop-variable expression.
7882 Thus, we can't have FOR loops that modify their own exit conditions by
7883 changing the final value or the increment. The problem with \v(argc) was
7884 that it is on the macro stack; after entry into the _forx macro, it is at
7885 the wrong place.
7886 */
7887 sprintf(tmpbuf,"%d",fx); /* (SAFE) Substitute actual value */
7888 s = tmpbuf;
7889 while ((*lp++ = *s++)) ; /* (what they actually typed) */
7890 lp--; *lp++ = SP;
7891 #ifdef DEBUG
7892 *lp = NUL;
7893 debug(F110," dofor line A",line,0);
7894 #endif /* DEBUG */
7895
7896 if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
7897 if (y == -3) return(-2);
7898 else return(y);
7899 }
7900 debug(F101," dofor loop exit value","",fy);
7901 s = atmbuf; /* Same deal */
7902 if ((int)strlen(s) < 1)
7903 goto badfor;
7904
7905 sprintf(tmpbuf,"%d",fy); /* SAFE */
7906 s = tmpbuf;
7907 while ((*lp++ = *s++)) ;
7908 lp--;
7909 *lp++ = SP;
7910 #ifdef DEBUG
7911 *lp = NUL;
7912 debug(F110," dofor line B",line,0);
7913 #endif /* DEBUG */
7914
7915 x_ifnum = 1; /* Increment or parenthesis */
7916 di = (fx < fy) ? "1" : "-1"; /* Default increment */
7917 debug(F110," dofor default increment",di,0);
7918 if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
7919 debug(F111," dofor increment parse failed",atmbuf,y);
7920 x_ifnum = 0;
7921 if (y == -3) { /* Premature termination */
7922 return(-2);
7923 } else if (y == -2) { /* Maybe closing paren */
7924 if (!strcmp(atmbuf,")")) {
7925 pp--; /* Count it */
7926 s = di; /* supply default interval */
7927 fz = atoi(s);
7928 } else /* Not closing paren, invalid */
7929 return(y);
7930 } else /* Other error */
7931 return(y);
7932 debug(F101," dofor default increment supplied","",fz);
7933 } else { /* Number */
7934 x_ifnum = 0;
7935 debug(F101," dofor parsed increment ok","",fz);
7936 s = atmbuf; /* Use it */
7937 }
7938 if ((int)strlen(s) < 1)
7939 goto badfor;
7940
7941 sprintf(tmpbuf,"%d",fz); /* (SAFE) Same deal */
7942 s = tmpbuf;
7943 while ((*lp++ = *s++)) ;
7944 lp--; *lp++ = SP;
7945
7946 #ifdef DEBUG
7947 *lp = NUL;
7948 debug(F110," dofor FOR command C",line,0);
7949 #endif /* DEBUG */
7950
7951 /* Insert the appropriate comparison operator */
7952 if (fz < 0)
7953 *lp++ = '<';
7954 else
7955 *lp++ = '>';
7956 *lp++ = SP;
7957
7958 #ifdef DEBUG
7959 *lp = NUL;
7960 debug(F110," dofor FOR command D",line,0);
7961 #endif /* DEBUG */
7962
7963 if (pp > 0) { /* If open paren given parse closing */
7964 if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
7965 return(y);
7966 if (strcmp(atmbuf,")")) {
7967 printf("?Closing parenthesis required\n");
7968 return(-9);
7969 }
7970 }
7971 if ((y = cmtxt("Command(s) to execute","",&s,NULL)) < 0) return(y);
7972 if ((y = (int)strlen(s)) < 1) return(-2);
7973 debug(F110," doif FOR body A",s,0);
7974 if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
7975 ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
7976 s = tmpbuf;
7977 }
7978 debug(F110," doif FOR body B",s,0);
7979 if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
7980 printf("?Unbalanced braces\n");
7981 return(0);
7982 }
7983
7984 #ifdef DEBUG
7985 *lp = NUL;
7986 debug(F110," doif FOR body C",s,0);
7987 #endif /* DEBUG */
7988
7989 #ifdef COMMENT
7990 /* Too strict */
7991 if (fz == 0) {
7992 printf("?Zero increment not allowed\n");
7993 return(0);
7994 }
7995 #endif /* COMMENT */
7996 /*
7997 In C-Kermit 8.0 we allow bare macro names anywhere a numeric-valed variable
7998 could appear. But this caused trouble for the FOR loops because the quoting
7999 in for_def[] assumed a \%i-style loop variable. We account for this here in
8000 the if (mustquote)...else logic by invoking separate FOR macro definitions
8001 in the two cases.
8002 */
8003 debug(F100," dofor choosing FOR macro definition","",0);
8004 if (mustquote) { /* \%i-style loop variable */
8005 debug(F101," dofor choosing _forx because mustquote","",mustquote);
8006 x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */
8007 if (x < 0) { /* Not there? */
8008 addmmac("_forx",for_def); /* Put it back. */
8009 if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
8010 printf("?FOR macro definition gone!\n");
8011 return(success = 0);
8012 }
8013 debug(F110," dofor loop var is \\%x",for_def[0],0);
8014 }
8015 } else { /* Loop variable is a macro */
8016 debug(F101," dofor choosing _forz because mustquote","",mustquote);
8017 x = mlook(mactab,"_forz",nmac);
8018 if (x < 0) {
8019 addmmac("_forz",foz_def);
8020 if ((x = mlook(mactab,"_forz",nmac)) < 0) {
8021 printf("?FOR macro definition gone!\n");
8022 return(success = 0);
8023 }
8024 }
8025 debug(F110," dofor loop var is macro",foz_def[0],0);
8026 }
8027 debug(F010," dofor final FOR body",line,0); /* Execute the FOR macro. */
8028 debug(F100," dofor done, chaining to dodo()...","",0);
8029 return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
8030
8031 badfor:
8032 printf("?Incomplete FOR command\n");
8033 debug(F100," dofoar parse failure","",0);
8034 return(-2);
8035 }
8036 #endif /* NOSPL */
8037
8038 #ifndef NOSPL
8039
8040 /* T O D 2 S E C -- Convert time of day as hh:mm:ss to secs since midnite */
8041 /*
8042 Call with a string hh:mm or hh:mm:ss.
8043 Returns a 0 to 86400 on success, or a negative number on failure.
8044 */
8045 long
tod2sec(t)8046 tod2sec(t) char * t; {
8047 long t2;
8048 long hh = 0L, mm = 0L, ss = 0L;
8049
8050 if (!t) t = "";
8051 if (!*t)
8052 return(-3L);
8053 debug(F110,"tod2sec",t,0);
8054
8055 if (isdigit(*t)) /* Get hours from argument */
8056 hh = *t++ - '0';
8057 else
8058 return(-1L);
8059 if (isdigit(*t))
8060 hh = hh * 10 + *t++ - '0';
8061 #ifdef COMMENT
8062 if (hh > 24L)
8063 return(-1L);
8064 #endif /* COMMENT */
8065 if (*t == ':')
8066 t++;
8067 else if (!*t)
8068 goto xtod2sec;
8069 else
8070 return(-1L);
8071
8072 if (isdigit(*t)) /* Minutes */
8073 mm = *t++ - '0';
8074 else
8075 return(-1L);
8076 if (isdigit(*t))
8077 mm = mm * 10 + *t++ - '0';
8078 if (mm > 60L)
8079 return(-1L);
8080 if (*t == ':')
8081 t++;
8082 else if (!*t)
8083 goto xtod2sec;
8084 else
8085 return(-1L);
8086
8087 if (isdigit(*t)) /* Seconds */
8088 ss = *t++ - '0';
8089 else
8090 return(-1L);
8091 if (isdigit(*t))
8092 ss = ss * 10 + *t++ - '0';
8093 if (ss > 60L)
8094 return(-1L);
8095
8096 if (*t > 32) /* No trailing junk allowed */
8097 return(-1L);
8098
8099 xtod2sec:
8100
8101 t2 = hh * 3600L + mm * 60L + ss; /* Seconds since midnight from arg */
8102 debug(F101,"tod2sec t2","",t2);
8103
8104 return(t2);
8105 }
8106
8107 int waitinterval = 1;
8108
8109 #ifdef OLDWAIT
8110 #undef OLDWAIT
8111 #endif /* OLDWAIT */
8112
8113 int kbchar = NUL;
8114
8115 int
dopaus(cx)8116 dopaus(cx) int cx; {
8117 long zz;
8118 extern int sleepcan;
8119
8120 #ifdef OLDWAIT
8121 zz = -1L;
8122 x_ifnum = 1; /* Turn off internal complaints */
8123 if (cx == XXWAI)
8124 y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
8125 else if (cx == XXPAU)
8126 y = cmnum("seconds to pause, or time of day hh:mm:ss",
8127 "1",10,&x,xxstring);
8128 else
8129 y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
8130 "100",10,&x,xxstring);
8131 x_ifnum = 0;
8132 if (y < 0) {
8133 if (y == -2) { /* Invalid number or expression */
8134 char *p = tmpbuf; /* Retrieve string from atmbuf */
8135 int n = TMPBUFSIZ;
8136 *p = NUL;
8137 zzstring(atmbuf,&p,&n); /* Evaluate in case it's a variable */
8138 zz = tod2sec(tmpbuf); /* Convert to secs since midnight */
8139 if (zz < 0L) {
8140 printf("?Number, expression, or time of day required\n");
8141 return(-9);
8142 } else {
8143 char now[32]; /* Current time */
8144 char *p;
8145 long tnow;
8146 p = now;
8147 ztime(&p);
8148 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
8149 if (zz < tnow) /* User's time before now */
8150 zz += 86400L; /* So make it tomorrow */
8151 zz -= tnow; /* Seconds from now. */
8152 }
8153 } else
8154 return(y);
8155 }
8156 if (x < 0) x = 0;
8157 switch (cx) {
8158 case XXPAU: /* PAUSE */
8159 case XXMSL: /* MSLEEP */
8160 if ((y = cmcfm()) < 0) return(y);
8161 break;
8162 case XXWAI: /* WAIT */
8163 z = 0; /* Modem signal mask */
8164 while (1) { /* Read zero or more signal names */
8165 y = cmkey(mstab,nms,"modem signal","",xxstring);
8166 if (y == -3) break; /* -3 means they typed CR */
8167 if (y < 0) return(y); /* Other negatives are errors */
8168 z |= y; /* OR the bit into the signal mask */
8169 }
8170 if ((y = cmcfm()) < 0) return(y);
8171 break;
8172
8173 default: /* Shouldn't happen */
8174 return(-2);
8175 }
8176
8177 /* Command is entered, now do it. */
8178
8179 if (zz > -1L) { /* Time of day given? */
8180 x = zz;
8181 if (zz != (long) x) {
8182 printf(
8183 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
8184 );
8185 return(-9);
8186 }
8187 }
8188 if (cx == XXMSL) { /* Millisecond sleep */
8189 msleep(zz < 0 ? x : x * 1000);
8190 return(success = 1);
8191 }
8192 if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
8193 sleep(x);
8194 return(success = 1);
8195 }
8196
8197 /* WAIT, or else SLEEP with cancellation allowed... */
8198
8199 do { /* Sleep loop */
8200 int mdmsig;
8201 if (sleepcan) { /* Keyboard cancellation allowed? */
8202 if (y = conchk()) { /* Did they type something? */
8203 #ifdef COMMENT
8204 while (y--) coninc(0); /* Yes, gobble it all up */
8205 #else
8206 /* There is a debate over whether PAUSE should absorb */
8207 /* its cancelling character(s). There are several */
8208 /* reasons why it should gobble at least one character: */
8209 /* (1) MS-DOS Kermit does it */
8210 /* (2) if not, subsequent PAUSE commands will terminate */
8211 /* immediately */
8212 /* (3) if not, subsequent ASK commands will use it as */
8213 /* valid input. If \13, then it will get no input */
8214 /* (4) if not, then the character appears on the command */
8215 /* line after all enclosing macros are complete. */
8216 kbchar = coninc(0); /* Gobble one up */
8217 #endif /* COMMENT */
8218 break; /* And quit PAUSing or WAITing */
8219 }
8220 }
8221 if (cx == XXWAI) { /* WAIT (z == modem signal mask) */
8222 debug(F101,"WAIT x","",x);
8223 if (z > 0) { /* Looking for any modem signals? */
8224 mdmsig = ttgmdm(); /* Yes, get them */
8225 if (mdmsig < 0) /* Failed */
8226 return(success = 0);
8227 if ((mdmsig & z) == z) /* Got what we wanted? */
8228 return(success = 1); /* Succeed */
8229 }
8230 if (x == 0) /* WAIT 0 and didn't get our signals */
8231 break;
8232 }
8233 sleep(1); /* No interrupt, sleep one second */
8234 } while (--x > 0);
8235
8236 if (cx == XXWAI) /* If WAIT and loop exhausted */
8237 success = (z == 0); /* Fail. */
8238 else /* */
8239 success = (x == 0); /* Set SUCCESS/FAILURE for PAUSE. */
8240 return(success);
8241
8242 #else /* New code uses chained FDBs and allows FILE waits... */
8243
8244 char * m = ""; /* Help message */
8245 struct FDB nu, fl; /* Parse function descriptor blocks */
8246 int filewait = 0;
8247 int mdmsig = 0, fs = 0;
8248 char filedate[32];
8249
8250 kbchar = 0;
8251
8252 switch (cx) {
8253 case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
8254 case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
8255 case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
8256 }
8257 zz = -1L;
8258 cmfdbi(&nu,
8259 _CMNUM, /* Number */
8260 m, /* Help message */
8261 (cx == XXMSL) ? "100" : "1", /* Default */
8262 "", /* N/A */
8263 0, /* N/A */
8264 0, /* N/A */
8265 xxstring, /* Processing function */
8266 NULL, /* N/A */
8267 &fl /* Next */
8268 );
8269 cmfdbi(&fl, /* Time of day */
8270 _CMFLD, /* Field */
8271 "", /* hlpmsg */
8272 "", /* default */
8273 "", /* addtl string data */
8274 0, /* addtl numeric data 1 */
8275 0, /* addtl numeric data 2 */
8276 xxstring, /* processing func */
8277 NULL, /* N/A */
8278 NULL /* No next */
8279 );
8280 x = cmfdb(&nu); /* Parse a number or a field */
8281 if (x < 0) {
8282 if (x == -3)
8283 x = -2;
8284 return(x);
8285 }
8286 switch (cmresult.fcode) {
8287 case _CMNUM: /* Number */
8288 x = cmresult.nresult;
8289 break;
8290 case _CMFLD: /* Field */
8291 zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */
8292 if (zz < 0L) {
8293 printf("?Number, expression, or time of day required\n");
8294 return(-9);
8295 } else {
8296 char now[32]; /* Current time */
8297 char *p;
8298 long tnow;
8299 p = now;
8300 ztime(&p);
8301 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
8302 if (zz < tnow) /* User's time before now */
8303 zz += 86400L; /* So make it tomorrow */
8304 zz -= tnow; /* Seconds from now. */
8305 }
8306 }
8307 debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
8308 switch (cx) {
8309 case XXPAU: /* PAUSE */
8310 case XXMSL: /* MSLEEP */
8311 if ((y = cmcfm()) < 0) return(y);
8312 break;
8313 case XXWAI: /* WAIT */
8314 z = 0; /* Modem signal mask */
8315 y = cmkey(waittab,nwaittab,"","",xxstring);
8316 if (y < 0) {
8317 if (y == -3) {
8318 if ((y = cmcfm()) < 0)
8319 return(y);
8320 break;
8321 } else
8322 return(y);
8323 }
8324 if (y == WAIT_FIL) { /* FILE */
8325 int wild = 0;
8326 if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
8327 return(z);
8328 filewait = z;
8329 if (filewait == WF_MOD || filewait == WF_DEL)
8330 z = cmifi("Filename","",&s,&wild,xxstring);
8331 else
8332 z = cmfld("Filename","",&s,xxstring);
8333 if (z < 0)
8334 return(z);
8335 if (wild || ((filewait == WF_CRE) && iswild(s))) {
8336 printf("?Wildcards not valid here\n");
8337 return(-9);
8338 }
8339 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8340 if ((z = cmcfm()) < 0)
8341 return(z);
8342 break;
8343 } else if (y != WAIT_MDM) { /* A modem signal */
8344 z |= y; /* OR the bit into the signal mask */
8345 }
8346 if (!filewait) { /* Modem signals... */
8347 while (1) { /* Get zero or more signal names */
8348 y = cmkey(mstab,nms,"modem signal","",xxstring);
8349 if (y == -3) break; /* -3 means they typed CR */
8350 if (y < 0) return(y); /* Other negatives are errors */
8351 z |= y; /* OR the bit into the signal mask */
8352 }
8353 if ((y = cmcfm()) < 0) return(y);
8354 break;
8355 }
8356
8357 default: /* Shouldn't happen */
8358 return(-2);
8359 } /* switch (cx) */
8360
8361 /* Command is entered, now do it. */
8362
8363 if (zz > -1L) { /* Time of day given? */
8364 x = zz;
8365 if (zz != (long) x) {
8366 printf(
8367 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
8368 );
8369 return(-9);
8370 }
8371 }
8372 if (sleepcan)
8373 concb((char)escape); /* Ensure single-char wakeup */
8374
8375 if (cx == XXMSL) { /* Millisecond sleep */
8376 msleep(zz < 0 ? x : x * 1000);
8377 return(success = 1);
8378 }
8379 if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
8380 sleep(x);
8381 return(success = 1);
8382 }
8383 if (filewait) { /* FILE... */
8384 fs = zchki(tmpbuf); /* Check if file exists */
8385 switch (filewait) {
8386 case WF_DEL:
8387 if (fs == -1)
8388 return(success = 1);
8389 break;
8390 case WF_MOD:
8391 if (fs == -1) {
8392 printf("?File does not exit: %s\n",tmpbuf);
8393 return(-9);
8394 }
8395 s = zfcdat(tmpbuf); /* Get current modification date */
8396 if (!s) s = "";
8397 if (ckstrncpy(filedate,s,32) != 17) {
8398 printf("?Can't get modification time: %s\n",tmpbuf);
8399 return(-9);
8400 }
8401 break;
8402 case WF_CRE:
8403 if (fs > -1)
8404 return(success = 1);
8405 break;
8406 }
8407 }
8408 do { /* Polling loop */
8409 if (sleepcan) { /* Keyboard cancellation allowed? */
8410 if ((y = conchk()) > 0) { /* Did they type something? */
8411 kbchar = coninc(0); /* Yes, get first char they typed */
8412 debug(F000,"WAIT kbchar","",kbchar);
8413 #ifdef COMMENT
8414 while (--y > 0) /* Gobble the rest up */
8415 coninc(0);
8416 #endif /* COMMENT */
8417 return(success = 0); /* And quit PAUSing or WAITing */
8418 }
8419 }
8420 if (filewait == 0) {
8421 if (cx == XXWAI) { /* WAIT for modem signals */
8422 if (z != 0) {
8423 mdmsig = ttgmdm(); /* Get them. */
8424 debug(F101,"WAIT ttgmdm","",mdmsig);
8425 if (mdmsig < 0) /* Failure to get them? */
8426 return(success = 0); /* Fail. */
8427 if ((mdmsig & z) == z) /* Got desired ones? */
8428 return(success = 1); /* Succeed. */
8429 } else if (x == 0)
8430 return(success = 0);
8431 }
8432 } else { /* FILE... */
8433 fs = zchki(tmpbuf); /* Get file status */
8434 if (filewait == WF_MOD) { /* Wait for modification */
8435 if (fs == -1) /* Failure to get status */
8436 return(success = 0); /* so WAIT fails. */
8437 s = zfcdat(tmpbuf); /* Get current modification time */
8438 if (!s) s = ""; /* And compare with the time */
8439 if (strcmp(s,filedate)) /* when the WAIT started */
8440 return(success = 1);
8441 } else if (filewait == WF_DEL) { /* Wait for deletion */
8442 if (fs == -1) /* If file doesn't exist, */
8443 return(success = 1); /* succeed. */
8444 } else if (filewait == WF_CRE) { /* Wait for creation */
8445 if (fs != -1) /* If file exists */
8446 return(success = 1); /* succeed. */
8447 }
8448 }
8449 if (x < 1) /* SLEEP/WAIT/PAUSE 0 */
8450 break;
8451 sleep(waitinterval); /* No interrupt, sleep */
8452 x -= waitinterval; /* Deduct sleep time */
8453 } while (x > 0);
8454
8455 if (cx == XXWAI) /* WAIT time expired */
8456 success = (z == 0); /* Succeed if no modem signals */
8457 else /* For SLEEP or PAUSE, success */
8458 success = (x == 0); /* depends on whether it was */
8459 return(success); /* interrupted from the keyboard. */
8460 #endif /* OLDWAIT */
8461 }
8462 #endif /* NOSPL */
8463
8464 #ifdef OS2ORUNIX
8465 _PROTOTYP(int zcmpfn,(char *, char *));
8466 #endif /* OS2ORUNIX */
8467
8468 #ifndef NOFRILLS
8469 #ifdef NT
8470 int
dolink()8471 dolink() {
8472 /* Parse a file or a directory name */
8473 int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
8474 struct FDB sw, fi;
8475
8476 cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
8477 _CMKEY, /* fcode */
8478 "Filename or switch", /* hlpmsg */
8479 "", /* default */
8480 "", /* addtl string data */
8481 nqvswtab, /* addtl numeric data 1: tbl size */
8482 4, /* addtl numeric data 2: 4 = cmswi */
8483 xxstring, /* Processing function */
8484 qvswtab, /* Keyword table */
8485 &fi /* Pointer to next FDB */
8486 );
8487
8488 cmfdbi(&fi, /* 1st FDB - file to type */
8489 _CMIFI, /* fcode */
8490 "", /* hlpmsg */
8491 "", /* default */
8492 "", /* addtl string data */
8493 3, /* addtl numeric data 1 */
8494 0, /* addtl numeric data 2 */
8495 xxstring,
8496 NULL,
8497 NULL
8498 );
8499
8500 while (!havename) {
8501 x = cmfdb(&sw); /* Parse something */
8502 if (x < 0) /* Error */
8503 return(x);
8504 switch (cmresult.fcode) {
8505 case _CMKEY:
8506 switch (cmresult.nresult) {
8507 case DEL_LIS:
8508 case DEL_VRB:
8509 listing = 1;
8510 break;
8511 case DEL_NOL:
8512 case DEL_QUI:
8513 listing = 0;
8514 break;
8515 }
8516 break;
8517 case _CMIFI:
8518 s = cmresult.sresult;
8519 havename = 1;
8520 break;
8521 default:
8522 return(-2);
8523 }
8524 }
8525 wild = cmresult.nresult; /* Source specification wild? */
8526
8527 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
8528 s = line;
8529
8530 if (!wild)
8531 wild = iswild(line);
8532
8533 p = tmpbuf; /* Place for new name */
8534 if ((x = cmofi(wild ? "Target directory" : "New name",
8535 "",&s,xxstring)) < 0) { /* Get new name */
8536 if (x == -3) {
8537 printf("?%s required\n", wild ? "Target directory" : "New name");
8538 return(-9);
8539 } else return(x);
8540 }
8541 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
8542 if ((y = cmcfm()) < 0) return(y);
8543
8544 if (!wild) { /* Just one */
8545 if (listing) printf("%s => %s ",line,p);
8546 if (zlink(line,p) < 0) {
8547 if (listing) printf("(FAILED: %s\n",ck_errstr());
8548 rc = 0;
8549 } else {
8550 if (listing) printf("(OK)\n");
8551 }
8552 return(success = rc);
8553 }
8554 if (!isdir(p)) { /* Multiple */
8555 printf( /* if target is not a directory */
8556 "?Multiple source files not allowed if target is not a directory.\n");
8557 return(-9);
8558 }
8559 #ifdef COMMENT
8560 else { /* Show full path of target */
8561 char buf[CKMAXPATH]; /* (too much) */
8562 if (zfnqfp(p,CKMAXPATH,buf))
8563 ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
8564 }
8565 #endif /* COMMENT */
8566
8567 #ifdef VMS
8568 conres(); /* Let Ctrl-C work. */
8569 #endif /* VMS */
8570 debug(F110,"dolink line",line,0);
8571
8572 #ifdef ZXREWIND
8573 z = zxrewind(); /* Rewind file list */
8574 #else
8575 z = nzxpand(s,0); /* Expand file list */
8576 #endif /* ZXREWIND */
8577 debug(F111,"dolink p",p,z);
8578
8579 #ifdef UNIX
8580 if (wild && z > 1)
8581 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
8582 #endif /* UNIX */
8583
8584 while (z-- > 0) {
8585 if (!(z == 0 && !wild))
8586 znext(line);
8587 if (!line[0])
8588 break;
8589 if (listing) printf("%s => %s ",line,p);
8590 if (zlink(line,p) < 0) {
8591 if (listing) printf("(FAILED: %s\n",ck_errstr());
8592 rc = 0;
8593 } else {
8594 if (listing) printf("(OK)\n");
8595 }
8596 }
8597 #ifdef VMS
8598 concb((char)escape);
8599 #endif /* VMS */
8600 return(success = rc);
8601 }
8602 #endif /* NT */
8603
8604 #ifdef ZCOPY
8605 int
docopy()8606 docopy() {
8607 int i, x, listing = 0, nolist = 0, havename = 0, getval;
8608 char c;
8609 struct FDB sw, fi;
8610 int overwrite = OVW_ALWAYS;
8611 int targetisdir = 0;
8612 int targetlen = 0;
8613 int appending = 0;
8614 int preserve = 0;
8615 int swapping = 0;
8616 int fromb64 = 0;
8617 int tob64 = 0;
8618 int wild = 0;
8619 int rc = 1;
8620
8621 char newname[CKMAXPATH], * nm;
8622 nm = newname;
8623
8624 cmfdbi(&sw, /* 1st FDB - switches */
8625 _CMKEY, /* fcode */
8626 "Filename or switch", /* hlpmsg */
8627 "", /* default */
8628 "", /* addtl string data */
8629 ncopytab, /* addtl numeric data 1: tbl size */
8630 4, /* addtl numeric data 2: 4 = cmswi */
8631 xxstring, /* Processing function */
8632 copytab, /* Keyword table */
8633 &fi /* Pointer to next FDB */
8634 );
8635 cmfdbi(&fi, /* 2nd FDB - file to copy */
8636 _CMIFI, /* fcode */
8637 "", /* hlpmsg */
8638 "", /* default */
8639 "", /* addtl string data */
8640 0, /* addtl numeric data 1 */
8641 0, /* addtl numeric data 2 */
8642 xxstring,
8643 NULL,
8644 NULL
8645 );
8646
8647 while (!havename) {
8648 x = cmfdb(&sw); /* Parse something */
8649 if (x < 0) /* Error */
8650 return(x);
8651 switch (cmresult.fcode) {
8652 case _CMKEY:
8653 c = cmgbrk(); /* Get break character */
8654 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
8655 printf("?This switch does not take an argument\n");
8656 rc = -9;
8657 return(rc);
8658 }
8659 if (!getval && (cmgkwflgs() & CM_ARG)) {
8660 printf("?This switch requires an argument\n");
8661 rc = -9;
8662 return(rc);
8663 }
8664 switch (cmresult.nresult) {
8665 case DEL_LIS:
8666 case DEL_VRB:
8667 nolist = 0;
8668 listing = 1;
8669 break;
8670 case DEL_NOL:
8671 case DEL_QUI:
8672 nolist = 1;
8673 listing = 0;
8674 break;
8675 case 999:
8676 swapping = 1;
8677 break;
8678 case 998:
8679 appending = 1;
8680 break;
8681 case 995:
8682 preserve = 1;
8683 break;
8684 case 994:
8685 if ((x = cmkey(ovwtab,novwtab,
8686 "When to overwrite existing destination file",
8687 "",xxstring)) < 0)
8688 return(x);
8689 overwrite = x;
8690 break;
8691 #ifndef NOSPL
8692 case 997:
8693 fromb64 = 1;
8694 break;
8695 case 996:
8696 tob64 = 1;
8697 break;
8698 #endif /* NOSPL */
8699 }
8700 break;
8701 case _CMIFI:
8702 s = cmresult.sresult;
8703 havename = 1;
8704 break;
8705 default:
8706 return(-2);
8707 }
8708 }
8709 wild = cmresult.nresult;
8710 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
8711 s = line;
8712 p = tmpbuf; /* Place for new name */
8713
8714 /* Get destination name */
8715 if ((x = cmofi("destination name and/or directory",
8716 #ifdef UNIX
8717 "."
8718 #else
8719 ""
8720 #endif /* UNIX */
8721 ,&s,xxstring)) < 0) {
8722 if (x == -3) {
8723 printf("?Name for destination file required\n");
8724 return(-9);
8725 } else return(x);
8726 }
8727 ckstrncpy(p,s,TMPBUFSIZ); /* Safe copy of destination name */
8728 if ((y = cmcfm()) < 0) return(y);
8729 if (appending && swapping) {
8730 printf("?Sorry, /APPEND and /SWAP conflict\n");
8731 return(-9);
8732 }
8733 #ifdef COMMENT
8734 /*
8735 This unreasonably prevented "COPY /APPEND *.* bigfile" from concatenating
8736 a bunch of files into one big file.
8737 */
8738 if (appending && wild) {
8739 printf("?Sorry, /APPEND can be used only with single files\n");
8740 return(-9);
8741 }
8742 #endif /* COMMENT */
8743 targetisdir = isdir(p);
8744 x = strlen(p);
8745 if (targetisdir) {
8746 #ifdef UNIXOROSK
8747 if (p[x-1] != '/') {
8748 ckstrncat(p,"/",TMPBUFSIZ);
8749 x++;
8750 }
8751 #else
8752 #ifdef OS2
8753 if (p[x-1] != '/') {
8754 ckstrncat(p,"/",TMPBUFSIZ);
8755 x++;
8756 }
8757 #else
8758 #ifdef STRATUS
8759 if (p[x-1] != '>') {
8760 ckstrncat(p,">",TMPBUFSIZ);
8761 x++;
8762 }
8763 #else
8764 #ifdef datageneral
8765 if (p[x-1] != ':') {
8766 ckstrncat(p,":",TMPBUFSIZ);
8767 x++;
8768 }
8769 #else
8770 if (p[x-1] != '/') {
8771 ckstrncat(p,"/",TMPBUFSIZ);
8772 x++;
8773 }
8774 #endif /* datageneral */
8775 #endif /* STRATUS */
8776 #endif /* OS2 */
8777 #endif /* UNIXOROSK */
8778 }
8779 targetlen = x;
8780
8781 if (!appending) { /* If /APPEND not given */
8782 if (wild && !targetisdir) { /* No wildcards allowed */
8783 printf( /* if target is not a directory */
8784 "?Multiple source files not allowed if target is not a directory.\n");
8785 return(-9);
8786 }
8787 }
8788
8789 #ifdef VMS
8790 conres(); /* Let Ctrl-C work. */
8791 #endif /* VMS */
8792 debug(F110,"docopy line",line,0);
8793 debug(F110,"docopy p",p,0);
8794 debug(F110,"docopy nm",nm,0);
8795
8796 #ifdef ZXREWIND
8797 z = zxrewind(); /* Rewind file list */
8798 #else
8799 z = nzxpand(s,0); /* Expand file list */
8800 #endif /* ZXREWIND */
8801
8802 #ifdef UNIX
8803 if (wild)
8804 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
8805 #endif /* UNIX */
8806
8807 #ifdef IKSD
8808 if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */
8809 if (inserver && (!ENABLED(en_del)
8810 #ifdef CK_LOGIN
8811 || isguest
8812 #endif /* CK_LOGIN */
8813 )) {
8814 printf("?Sorry, overwriting existing files is disabled\n");
8815 return(-9);
8816 }
8817 }
8818 #endif /* IKSD */
8819
8820 if (tob64 && fromb64) { /* To and from B64 = no conversion */
8821 tob64 = 0;
8822 fromb64 = 0;
8823 }
8824 debug(F110,"COPY dest",p,0);
8825
8826 while (z > 0) {
8827
8828 znext(line);
8829 if (!line[0])
8830 break;
8831
8832 errno = 0; /* Reset errno */
8833
8834 if (targetisdir) {
8835 zstrip(line,&nm);
8836 ckmakmsg(newname,CKMAXPATH,p,nm,NULL,NULL);
8837 nm = newname;
8838 } else {
8839 nm = p;
8840 }
8841 if (overwrite) { /* Overwrite checking? */
8842 if (zchki(nm) >= (CK_OFF_T)0) { /* Destination file exists? */
8843
8844 char d1[20], * d2;
8845 char * n1, * n2;
8846 int i, skip = 0;
8847
8848 i = strlen(line); /* Isolate source filename */
8849 for (; i >= 0; i--) {
8850 if (ISDIRSEP(line[i])) {
8851 n1 = &line[i+1];
8852 break;
8853 }
8854 }
8855 debug(F110,"COPY n1", n1, 0);
8856 i = strlen(nm); /* And destination filename */
8857 for (; i >= 0; i--) {
8858 if (ISDIRSEP(nm[i])) {
8859 n2 = &nm[i+1];
8860 break;
8861 }
8862 }
8863 debug(F110,"COPY n2", n2, 0);
8864 if (!strcmp(n1,n2)) { /* Same name? */
8865 if (overwrite == OVW_NEVER) { /* Never overwrite? */
8866 if (listing) /* Skip */
8867 if (listing) printf("%s => %s (SKIPPED)\n",line,nm);
8868 continue;
8869 }
8870 ckstrncpy(d1,zfcdat(line),20); /* Source file timestamp */
8871 d2 = zfcdat(nm); /* Timestamp of dest file */
8872 x = strcmp(d1,d2); /* Compare them */
8873 if (((overwrite == OVW_NEWER) && (x < 0)) ||
8874 ((overwrite == OVW_OLDER) && (x > 0))) {
8875 if (listing)
8876 if (listing) printf("%s => %s (SKIPPED)\n",line,nm);
8877 continue;
8878 }
8879 }
8880 }
8881 }
8882 if (listing) printf("%s => %s ",line,nm);
8883
8884 /* Straight copy */
8885 if (!swapping && !appending && !fromb64 && !tob64) {
8886 debug(F110,"COPY zcopy",line,0);
8887
8888 if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
8889 debug(F111,"COPY not OK",line,x);
8890 switch (x) {
8891 case -2:
8892 if (listing)
8893 printf("(FAILED: Not a regular file)\n");
8894 else if (!nolist)
8895 printf("?Not a regular file - %s\n",line);
8896 rc = 0;
8897 break;
8898 case -3:
8899 if (listing)
8900 printf("(FAILED: Not found or not accessible)\n");
8901 else if (!nolist)
8902 printf("?Not found or not accessible - %s\n",line);
8903 rc = 0;
8904 break;
8905 case -4:
8906 if (listing)
8907 printf("(FAILED: Permission denied)\n");
8908 else if (!nolist)
8909 printf("?Permission denied - %s\n",line);
8910 rc = 0;
8911 break;
8912 case -5:
8913 if (listing)
8914 printf("(Source and destination are the same file)\n");
8915 else if (!nolist)
8916 printf(
8917 "?Source and destination are the same file - %s\n",
8918 line
8919 );
8920 break;
8921 case -6:
8922 if (listing)
8923 printf("(FAILED: Input/Output error)\n");
8924 else if (!nolist)
8925 printf("?Input/Output error - %s\n",line);
8926 rc = 0;
8927 break;
8928 case -7:
8929 if (listing)
8930 printf("(FAILED: %s - %s)\n",p,ck_errstr());
8931 else if (!nolist)
8932 printf("?%s - %s\n",ck_errstr(),p);
8933 rc = 0;
8934 break;
8935 default:
8936 if (listing)
8937 printf("(FAILED: %s)\n",ck_errstr());
8938 else if (!nolist)
8939 printf("?%s\n",ck_errstr());
8940 rc = 0;
8941 }
8942 } else { /* Regular copy succeeded */
8943 debug(F110,"COPY OK..",newname,0);
8944 #ifndef NOXFER
8945 if (preserve) { /* Handle /PRESERVE */
8946 char * pstr = ""; /* File permissions string */
8947 struct zattr xx; /* File attribute structure */
8948 extern char * cksysid;
8949
8950 initattr(&xx); /* Initialize the struct */
8951
8952 xx.systemid.val = cksysid; /* Set our system ID */
8953 xx.systemid.len = (int)strlen(cksysid);
8954 #ifdef CK_PERMS
8955 pstr = zgperm(line); /* Get source file's permissions */
8956 #endif /* CK_PERMS */
8957 xx.lprotect.val = pstr;
8958 xx.lprotect.len = (int)strlen(pstr);
8959 xx.gprotect.len = 0;
8960 xx.date.val = zfcdat(line); /* Source file's timestamp */
8961 xx.date.len = (int)strlen(xx.date.val);
8962 if (zstime(nm,&xx,0) < 0) {
8963 printf("?COPY /PRESERVE %s: %s\n",nm,ck_errstr());
8964 rc = -9;
8965 }
8966 }
8967 #endif /* NOXFER */
8968 if (listing && rc > -1)
8969 printf("(OK)\n");
8970 }
8971
8972 } else { /* Special options */
8973
8974 int prev, y, x = 0; /* Variables needed for them */
8975 int i, t;
8976 char ibuf[100];
8977 char obuf[200];
8978 FILE * in = NULL;
8979 FILE * out = NULL;
8980
8981 if ((in = fopen(line,"r")) == NULL) { /* Open input file */
8982 if (listing)
8983 printf("(FAILED: %s)\n",ck_errstr());
8984 else if (!nolist)
8985 printf("?%s - %s)\n",ck_errstr(),line);
8986 rc = 0;
8987 continue;
8988 }
8989 if (targetisdir) { /* Target is directory */
8990 char * buf = NULL; /* so append this filename to it */
8991 zstrip(line,&buf);
8992 p[targetlen] = NUL;
8993 if (buf)
8994 ckstrncat(p,buf,TMPBUFSIZ);
8995 }
8996 #ifdef OS2ORUNIX
8997 if (zcmpfn(line,p)) { /* Input and output are same file? */
8998 if (listing)
8999 printf("(FAILED: Source and destination identical)\n");
9000 else if (!nolist)
9001 printf("?Source and destination identical - %s\n", line);
9002 rc = 0;
9003 continue;
9004 }
9005 #endif /* OS2ORUNIX */
9006 if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
9007 fclose(in);
9008 if (listing)
9009 printf("(FAILED: %s - %s)\n",p,ck_errstr());
9010 else if (!nolist)
9011 printf("?%s - %s\n",p,ck_errstr());
9012 rc = 0;
9013 continue;
9014 }
9015 #ifndef NOSPL
9016 if (tob64) { /* Converting to Base-64 */
9017
9018 debug(F110,"COPY tob64",line,0);
9019
9020 while (1) { /* Loop... */
9021 prev = x;
9022 if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */
9023 if (listing)
9024 printf("(OK)\n");
9025 break;
9026 }
9027 if (prev % 3) {
9028 if (listing)
9029 printf("(FAILED: Phase error at %d)\n",prev);
9030 else if (!nolist)
9031 printf("?Phase error at %d\n",prev);
9032 rc = 0;
9033 break;
9034 }
9035 if (swapping) {
9036 if (x & 1) {
9037 if (listing)
9038 printf("(FAILED: Swap error)\n");
9039 else if (!nolist)
9040 printf("?Swap error\n");
9041 rc = 0;
9042 break;
9043 }
9044 for (i = 0; i < x; i+=2) {
9045 t = ibuf[i];
9046 ibuf[i] = ibuf[i+1];
9047 ibuf[i+1] = t;
9048 }
9049 }
9050 if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
9051 if (listing)
9052 printf("(FAILED: Encoding error)\n");
9053 else if (!nolist)
9054 printf("?Encoding error\n");
9055 rc = 0;
9056 break;
9057 }
9058 fprintf(out,"%s\n",obuf);
9059 }
9060
9061 } else if (fromb64) { /* Converting from Base 64 */
9062
9063 debug(F110,"COPY fromb64",line,0);
9064
9065 if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
9066 fclose(in);
9067 if (listing)
9068 printf("(FAILED: %s - %s)\n",p,ck_errstr());
9069 else if (!nolist)
9070 printf("?%s - %s\n",p,ck_errstr());
9071 rc = 0;
9072 continue;
9073 }
9074 x = 1;
9075 while (x) {
9076 x = fread(ibuf,1,80,in);
9077 if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
9078 if (listing)
9079 printf("(FAILED: Decoding error)\n");
9080 else if (!nolist)
9081 printf("?Decoding error\n");
9082 rc = 0;
9083 break;
9084 }
9085 if (swapping) {
9086 if (x & 1) {
9087 if (listing)
9088 printf("(FAILED: Swap error)\n");
9089 else if (!nolist)
9090 printf("?Swap error\n");
9091 rc = 0;
9092 break;
9093 }
9094 for (i = 0; i < y; i+=2) {
9095 t = obuf[i];
9096 obuf[i] = obuf[i+1];
9097 obuf[i+1] = t;
9098 }
9099 }
9100 if (y > 0) {
9101 if (fwrite(obuf,1,y,out) < 1) {
9102 if (listing)
9103 printf("(FAILED: %s - %s)\n",p,ck_errstr());
9104 else if (!nolist)
9105 printf("?%s - %s\n",p,ck_errstr());
9106 rc = 0;
9107 break;
9108 }
9109 }
9110 }
9111
9112 } else
9113 #endif /* NOSPL */
9114
9115 if (swapping) { /* Swapping bytes */
9116
9117 CHAR c[3];
9118 c[2] = NUL;
9119
9120 debug(F110,"COPY swapping",line,0);
9121
9122 while (1) {
9123 x = fread((char *)c,1,2,in);
9124 if (x < 1) {
9125 if (listing)
9126 printf("(OK)\n");
9127 break;
9128 } else if (x == 1) {
9129 c[1] = c[0];
9130 c[0] = NUL;
9131 printf(
9132 "(WARNING: Odd byte count)");
9133 if (!listing) printf("\n");
9134 }
9135 if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
9136 if (listing)
9137 printf("(FAILED: %s - %s)\n",p,ck_errstr());
9138 else if (!nolist)
9139 printf("?%s - %s\n",p,ck_errstr());
9140 rc = 0;
9141 break;
9142 }
9143 }
9144
9145 } else if (appending) { /* Appending to target file */
9146
9147 char c;
9148
9149 debug(F110,"COPY appending",line,0);
9150
9151 while (1) {
9152 x = fread(&c,1,1,in);
9153 if (x < 1) {
9154 if (listing)
9155 printf("(OK)\n");
9156 break;
9157 }
9158 if (fwrite(&c,1,1,out) < 1) {
9159 if (listing)
9160 printf("(FAILED: %s - %s)\n",p,ck_errstr());
9161 else if (!nolist)
9162 printf("?%s - %s\n",p,ck_errstr());
9163 rc = 0;
9164 break;
9165 }
9166 }
9167 }
9168 if (out) fclose(out);
9169 if (in) fclose(in);
9170 }
9171 #ifdef VMSORUNIX
9172 concb((char)escape);
9173 #endif /* VMSORUNIX */
9174 }
9175 if (rc > -1) success = rc;
9176 return(rc);
9177 }
9178 #endif /* ZCOPY */
9179 #endif /* NOFRILLS */
9180
9181 #ifndef NOCSETS
9182 #ifndef NOUNICODE
9183 static struct keytab * xfcstab = NULL; /* For RENAME /CONVERT: */
9184 static char cvtbufin[CKMAXPATH+8] = { NUL, NUL };
9185 static char cvtbufout[CKMAXPATH+8] = { NUL, NUL };
9186 static char * pcvtbufin = NULL;
9187 static char * pcvtbufout = NULL;
9188
9189 static int /* Input function xgnbyte() */
cvtfnin()9190 cvtfnin() {
9191 CHAR c;
9192 c = *pcvtbufin++;
9193 return(c ? c : -1);
9194 }
9195
9196 _PROTOTYP(int cvtfnout,(char)); /* Output function for xpnbyte() */
9197 int
9198 #ifdef CK_ANSIC
cvtfnout(char c)9199 cvtfnout(char c)
9200 #else
9201 cvtfnout(c) char c;
9202 #endif /* CK_ANSIC */
9203 {
9204 if (pcvtbufout - cvtbufout >= CKMAXPATH)
9205 return(-1);
9206 *pcvtbufout++ = c;
9207 *pcvtbufout = NUL;
9208 return(1);
9209 }
9210
9211 /* Convert a string from any charset to any other charset */
9212
9213 char *
cvtstring(s,csin,csout)9214 cvtstring(s,csin,csout) char * s; int csin, csout; {
9215 int c;
9216 extern CK_OFF_T ffc;
9217
9218 ckstrncpy(cvtbufin,s,CKMAXPATH); /* Put it in a public place */
9219 pcvtbufin = cvtbufin; /* with public pointers */
9220 pcvtbufout = cvtbufout;
9221 *pcvtbufout = NUL;
9222
9223 if (csin == csout) /* If the two sets are the same */
9224 return((char *)cvtbufin); /* don't bother converting */
9225
9226 initxlate(csin,csout); /* Initialize the translator */
9227
9228 while ((c = xgnbyte(FC_UCS2,csin,cvtfnin)) > -1) { /* Loop thru string */
9229 if (xpnbyte(c,TC_UCS2,csout,cvtfnout) < 0) {
9230 ffc = (CK_OFF_T)0;
9231 return("");
9232 }
9233 }
9234 /* ffc is touched by xgnbyte() but this is not file transfer */
9235 /* so we have to undo it */
9236 ffc = (CK_OFF_T)0;
9237 return((char *)cvtbufout);
9238 }
9239 #endif /* NOUNICODE */
9240 #endif /* NOCSETS */
9241
9242 #ifndef NORENAME
9243 #ifndef NOFRILLS
9244 #ifdef ZRENAME
9245
9246 /* The RENAME command - expanded and improved in 8.0.212 April 2006 */
9247
9248 static char * ren_sub[4] = { NULL,NULL,NULL,NULL }; /* For RENAME /REPLACE */
9249
9250 int ren_list = 0; /* Default listing action for RENAME */
9251 int ren_coll = RENX_OVWR; /* Default collision action */
9252
9253 int
shorename()9254 shorename() {
9255 char * s;
9256 switch (ren_coll) {
9257 case RENX_FAIL: s = "fail"; break;
9258 case RENX_OVWR: s = "overwrite"; break;
9259 case RENX_SKIP: s = "proceed"; break;
9260 }
9261 printf(" rename collision: %s\n",s);
9262 printf(" rename list: %s\n",showoff(ren_list));
9263 return(1);
9264 }
9265
9266 int
setrename()9267 setrename() { /* Parse SET RENAME options */
9268 int x, y;
9269 if ((x = cmkey(renamset,nrenamset,"","", xxstring)) < 0)
9270 return(x);
9271 switch (x) {
9272 case REN_OVW: /* COLLISION */
9273 if ((x = cmkey(r_collision,nr_collision,"","", xxstring)) < 0)
9274 return(x);
9275 if ((y = cmcfm()) < 0)
9276 return(y);
9277 ren_coll = x;
9278 break;
9279 case DEL_LIS: /* LIST */
9280 return(seton(&ren_list));
9281 }
9282 return(success = 1);
9283 }
9284
9285 /* Reverse a string - Assumes a single-byte character set */
9286
9287 int
gnirts(s1,s2,len)9288 gnirts(s1, s2, len) char * s1, * s2; int len; {
9289 int n, m = 0;
9290 if (!s1) /* Null source pointer, fail */
9291 return(0);
9292 n = (int) strlen(s1);
9293 if (n > len-1) /* Source longer than dest, fail */
9294 return(0);
9295 s2[n--] = NUL; /* Deposit null byte at end of dest */
9296 for (; n >= 0; n--) { /* Copy the rest backwards */
9297 *s2++ = s1[n];
9298 m++;
9299 }
9300 return(m);
9301 }
9302
9303 /*
9304 r e n a m e o n e
9305
9306 Worker function to rename one file for dorenam() (below).
9307 old = name of file or directory to be renamed
9308 new = new name (not required for /UPPER, /LOWER, and /REPLACE)
9309 replacing = 1 if doing string replacement on the name
9310 casing = 1 if converting name to lowercase, 2 if to uppercase
9311 all = if doing case conversion on all names, not just monocase ones
9312 converting = 1 if converting character sets
9313 cset1 = character set to convert from (File Character Set index)
9314 cset2 = character set to convert to (ditto, see ck?xla.h)
9315 listing = 1 to show results of rename
9316 nolist = 1 to be completely silent (don't even print error messages)
9317 op = 1 means simulate, 2 means check for collision, 0 means rename
9318 size = length of result buffer.
9319 collision = action to take if destination file already exists:
9320 0 = fail
9321 1 = overwrite and succeed
9322 2 = skip and succeed
9323 Returns:
9324 0: on failure to rename or when a forbidden collision would have occurred.
9325 1: on success (file was renamed or did not need to be renamed).
9326 Note:
9327 If this code is ever built on any platform that is not Unix, Windows,
9328 VMS, or OS/2, this routine might need some adjustment.
9329 */
9330
9331 /* Opcodes for op... */
9332 #define REN_OP_SIM 1 /* Simulate */
9333 #define REN_OP_CHK 2 /* Check for collisions */
9334
9335 static int
renameone(old,new,replacing,casing,all,converting,cset1,cset2,listing,nolist,op,size,collision)9336 renameone(old,new,
9337 replacing,casing,all,converting,cset1,cset2,
9338 listing,nolist,op,size,collision)
9339 char * old, * new;
9340 int replacing,casing,all,converting,cset1,cset2,
9341 listing,nolist,op,size,collision;
9342 {
9343 char buf[CKMAXPATH]; /* Temporary filename buffer */
9344 char out[CKMAXPATH]; /* Buffer for new name */
9345 char dir[CKMAXPATH]; /* Destination directory */
9346 char pat[CKMAXPATH]; /* Path segment on old filename */
9347
9348 char * destdir; /* Destination directory, if any */
9349 char * srcpath; /* Source path, if any */
9350 int rc = 1, flag = 0, skip = 0; /* Control */
9351 int honorcase = 0, replaced = 0;
9352 int anchor = 0; /* 1 = beginning, 2 = end */
9353 int occur = 0; /* Occurrence */
9354 int minus = 0; /* Occurrence is negative */
9355 int allbut = 0; /* Occurrence is "all but" */
9356 int arg2isfile = 0; /* Arg2 ("new") is a filename */
9357
9358 debug(F110,"RENAMEONE old",old,0);
9359 debug(F110,"RENAMEONE new",new,0);
9360 debug(F110,"RENAMEONE ren_sub[0]",ren_sub[0],0);
9361 debug(F110,"RENAMEONE ren_sub[1]",ren_sub[1],0);
9362 debug(F110,"RENAMEONE ren_sub[2]",ren_sub[2],0);
9363
9364 if (op == REN_OP_SIM && !nolist) /* For convenience */
9365 listing = 1;
9366 #ifndef NOSPL
9367 honorcase = inpcas[cmdlvl]; /* Inherit SET CASE value */
9368 #else
9369 #ifdef UNIX
9370 honorcase = 1;
9371 #else
9372 honorcase = 0;
9373 #endif /* UNIX */
9374 #endif /* NOSPL */
9375
9376 if (!old) old = ""; /* In case of bad args */
9377 if (!new) new = "";
9378 if (!*old) return(success = 0);
9379 ckstrncpy(out,new,CKMAXPATH); /* So we don't write into */
9380 new = out; /* our argument... */
9381 size = CKMAXPATH;
9382
9383 pat[0] = NUL; /* Assume no path in source file.. */
9384 srcpath = pat;
9385 {
9386 int n; /* If the old name includes a path */
9387 n = (int)strlen(old) - 1; /* put it in a separate place. */
9388 for (; n >= 0; n--) { /* We are renaming the file only. */
9389 if (ISDIRSEP(old[n])) {
9390 ckstrncpy(pat,old,CKMAXPATH);
9391 pat[n+1] = NUL;
9392 old = old+n+1;
9393 break;
9394 }
9395 }
9396 }
9397 debug(F110,"RENAMEONE old 2",old,0);
9398 debug(F110,"RENAMEONE pat 2",pat,0);
9399
9400 dir[0] = NUL; /* Assume no destination directory */
9401 destdir = dir;
9402 if (*new) { /* If Arg2 given */
9403 if (isdir(new)) { /* If it's a directory */
9404 ckstrncpy(dir,new,CKMAXPATH); /* put it here */
9405 } else { /* otherwise */
9406 arg2isfile++; /* flag that it's a filename */
9407 }
9408 }
9409 if (!casing && !replacing && !converting) {
9410 if (!*new)
9411 return(success = 0);
9412 if (!arg2isfile) { /* Destination is a directory? */
9413 if (!isdir(old)) { /* and source is not? */
9414 #ifndef VMS
9415 int n, x = 0; /* Concatenate them */
9416 if ((n = strlen(new)) > 0) /* so we can check for */
9417 if (ISDIRSEP(new[n-1])) /* collisions. */
9418 x++;
9419 ckmakmsg(buf,size,new,x ? "" : "/", old, "");
9420 #else
9421 ckmakmsg(buf,size,new, old, NULL, NULL);
9422 #endif /* VMS */
9423 debug(F110,"RENAMEONE new new",new,0);
9424 new = buf;
9425 size = CKMAXPATH;
9426 }
9427 }
9428 } else if (*new) { /* Directory to move file to */
9429 int n, x = 0; /* after changing its name */
9430 if (!isdir(new))
9431 return(success = 0);
9432 #ifndef VMS
9433 if ((n = strlen(new)) > 0)
9434 if (ISDIRSEP(new[n-1]))
9435 x++;
9436 ckmakmsg(dir,CKMAXPATH,new,x ? "" : "/", "", "");
9437 #else
9438 ckstrncpy(dir,new,CKMAXPATH);
9439 #endif /* VMS */
9440 }
9441
9442 #ifndef NOCSETS
9443 #ifndef NOUNICODE
9444 if (converting) {
9445 new = cvtstring(old,cset1,cset2);
9446 }
9447 #endif /* NOUNICODE */
9448 #endif /* NOCSETS */
9449
9450 if (replacing) { /* Replacing strings */
9451 int todo = 0;
9452 int len0, len1, len2;
9453 char c, *p, *s, *bp[3];
9454
9455 bp[0] = old; /* Original name */
9456 bp[1] = ren_sub[0]; /* String to be replaced */
9457 bp[2] = ren_sub[1]; /* What to replace it with */
9458 if (!bp[2]) bp[2] = "";
9459
9460 len0 = (int)strlen(bp[0]); /* length of original filename */
9461 len1 = (int)strlen(bp[1]); /* length of target substring */
9462 len2 = (int)strlen(bp[2]); /* Length of replacement string */
9463
9464 if (ren_sub[2]) { /* Optional options */
9465 p = ren_sub[2];
9466 while ((c = *p++)) {
9467 switch (c) {
9468 case '^':
9469 anchor = 1; occur = 0; minus = 0; allbut = 0; break;
9470 case '$':
9471 anchor = 2; occur = 0; minus = 0; allbut = 0; break;
9472 case 'A': honorcase = 1; minus = 0; allbut = 0; break;
9473 case 'a': honorcase = 0; minus = 0; allbut = 0; break;
9474 case '-': minus = 1; break;
9475 case '~': allbut = 1; break;
9476 default:
9477 if (isdigit(c)) {
9478 occur = c - '0';
9479 if (minus) occur = 0 - occur;
9480 anchor = 0;
9481 }
9482 minus = 0;
9483 }
9484 }
9485 }
9486 if (anchor) { /* Anchored replacement... */
9487 y = len0 - len1;
9488 if (y > 0) {
9489 int x;
9490 switch (anchor) {
9491 case 1: /* Anchored at beginning */
9492 if (!ckstrcmp(bp[1],bp[0],len1,honorcase)) {
9493 x = ckstrncpy(new,bp[2],size);
9494 (VOID) ckstrncpy(new+x,bp[0]+len1,size-x);
9495 replaced = 1;
9496 }
9497 break;
9498 case 2: /* Anchored at end */
9499 if (!ckstrcmp(bp[1],bp[0]+y,len1,honorcase)) {
9500 x = ckstrncpy(new,bp[0],y+1);
9501 (VOID) ckstrncpy(new+y,bp[2],size-x);
9502 replaced = 1;
9503 }
9504 break;
9505 }
9506 }
9507 if (!replaced) {
9508 ckstrncpy(new,old,size); /* Keep old name */
9509 replaced = 1;
9510 }
9511 } else { /* Replace all occurrences */
9512 int j, n = 0; /* or a particular occurrence */
9513 char c;
9514 int x = 0;
9515 char * s0 = NULL, * s1 = NULL, * s2 = NULL;
9516 p = new; /* Pointer to new name */
9517
9518 if (occur < 0) { /* nth occurrence from the right */
9519 occur = 0 - occur;
9520 s0 = (char *)malloc(len0+1); /* Reverse original string */
9521 if (s0) {
9522 (VOID) gnirts(bp[0],s0,len0+1);
9523 bp[0] = s0;
9524 } else return(0);
9525 s1 = (char *)malloc(len1+1); /* Reverse target string */
9526 if (s1) {
9527 (VOID) gnirts(bp[1],s1,len1+1);
9528 bp[1] = s1;
9529 } else return(0);
9530 s2 = (char *)malloc(len2+1); /* Reverse replacement string */
9531 if (s2) {
9532 (VOID) gnirts(bp[2],s2,len2+1);
9533 bp[2] = s2;
9534 } else return(0);
9535 debug(F111,"RENAMEONE s0",s0,len0);
9536 debug(F111,"RENAMEONE s1",s1,len1);
9537 debug(F111,"RENAMEONE s2",s2,len2);
9538 }
9539 s = bp[0]; /* Pointer to old name */
9540 p = new; /* Pointer to new name */
9541 j = len0 - len1 + 1; /* How much to scan */
9542 while (j-- > 0) { /* For each character... */
9543 if (!ckstrcmp(bp[1],s,len1,honorcase)) { /* Match? */
9544 n++; /* Occurrence counter */
9545 todo = (occur == 0) ||
9546 (!allbut && n == occur) ||
9547 (allbut && n != occur);
9548 if (!todo) { /* Desired occurrence? */
9549 size -= ckstrncpy(p,bp[1],size); /* No... */
9550 p += len1; /* Copy target string */
9551 s += len1; /* instead of replacement string */
9552 continue;
9553 }
9554 if (len2) { /* If replacement string not empty */
9555 size -= ckstrncpy(p,bp[2],size); /* Copy it */
9556 p += len2;
9557 }
9558 s += len1; /* Advance source position */
9559 } else { /* No match */
9560 *p++ = *s++; /* just copy this character */
9561 size--;
9562 }
9563 }
9564 while ((*p++ = *s++)); /* Done copy the rest */
9565 replaced = 1; /* Remember we changed the name */
9566 if (s0) { /* Were we doing "all but"? */
9567 debug(F110,"RENAMEONE new1",new,0);
9568 x = (int)strlen(new); /* Unreverse the result */
9569 if ((p = (char *)malloc(x+2))) {
9570 (VOID) gnirts(new,p,x+2);
9571 debug(F110,"RENAMEONE new2",new,0);
9572 ckstrncpy(new,p,x+2);
9573 free(p);
9574 }
9575 if (s0) free(s0); /* Free the temporary strings */
9576 if (s1) free(s1);
9577 if (s2) free(s2);
9578 debug(F110,"RENAMEONE new3",new,0);
9579 }
9580 }
9581 }
9582 if (casing) { /* Changing case? */
9583 char c, * t; /* See if mixed case. */
9584 if (!replaced)
9585 ckstrncpy(new,old,size); /* Copy old name to new name */
9586 t = new;
9587 while ((c = *t++)) {
9588 if (islower(c)) flag |= 1; /* Have a lowercase letter */
9589 else if (isupper(c)) flag |= 2; /* Have an uppercase letter */
9590 if (flag == 3) break; /* Have a mixed-case name */
9591 }
9592 if (all || flag < 3) { /* Not skipping or not mixed case */
9593 if (casing == 1 && flag != 1) /* Change case to lower */
9594 (VOID) cklower(new);
9595 else if (casing == 2 && flag != 2) /* Change case to upper */
9596 (VOID) ckupper(new);
9597 }
9598 }
9599 if (*destdir && !arg2isfile) { /* Moving without renaming */
9600 ckstrncat(srcpath,old,CKMAXPATH);
9601 old = srcpath;
9602 new = destdir;
9603 } else if (*destdir || *srcpath) { /* Were there any pathnames? */
9604 char tmp[CKMAXPATH];
9605 ckmakmsg(tmp,CKMAXPATH,srcpath,old,NULL,NULL);
9606 ckstrncpy(old,tmp,CKMAXPATH);
9607 if (*destdir) { /* Directory-to-move-to given? */
9608 ckstrncat(destdir,new,CKMAXPATH);
9609 new = destdir;
9610 } else if (*srcpath && !arg2isfile) { /* Or was there a source path? */
9611 ckstrncat(srcpath,new,CKMAXPATH);
9612 new = srcpath;
9613 }
9614 }
9615 skip = 0; /* Can we skip this one? */
9616 #ifdef COMMENT
9617 if (casing && !replaced) {
9618 skip = (((all == 0) && (flag == 3)) || (flag == casing)) ? 1 : 0;
9619 if (!skip && destdir) skip = 0;
9620 }
9621 #endif /* COMMENT */
9622 if (!skip) {
9623 if (!ckstrcmp(old,new,-1,1))
9624 skip = 1;
9625 }
9626 if (op == 0 && !skip && (collision != RENX_OVWR)) {
9627 if (zchki(new) > (CK_OFF_T)-1) { /* New file already exists? */
9628 switch (collision) { /* Yes, take specified action */
9629 case RENX_SKIP: /* Skip this one and proceed */
9630 skip = 2;
9631 break;
9632 case RENX_FAIL: /* Or fail. */
9633 skip = 3;
9634 if (!listing && !nolist)
9635 printf("?File already exists: %s\n",new);
9636 }
9637 }
9638 }
9639 debug(F110,"RENAMEONE new",new,0);
9640 debug(F101,"RENAMEONE flag","",flag);
9641 debug(F101,"RENAMEONE skip","",skip);
9642 debug(F100,"RENAMEONE ----------------","",0);
9643
9644 if (skip == 3) {
9645 if (listing) printf("%s => %s (SKIPPED: %s already exists)\n",
9646 old,new,new);
9647 rc = 0;
9648 } else if (skip) { /* Skipping this one */
9649 if (listing) printf("%s => %s (%s)\n",
9650 old,new,
9651 (skip == 2) ? "COLLISION: SKIPPED" : "SKIPPED");
9652 } else { /* Have to rename this one */
9653 if (op == REN_OP_CHK) { /* Checking for collisions */
9654 return((zchki(new) > (CK_OFF_T)-1) ? 0 : 1 );
9655 } else if (op == REN_OP_SIM) { /* Simulating */
9656 if (listing) printf("%s => %s (SIMULATED)\n",old,new);
9657 } else { /* Really renaming */
9658 if (listing) printf("%s => %s ",old,new);
9659 if (zrename(old,new) < 0) {
9660 rc = 0;
9661 if (listing)
9662 printf("(FAILED: %s)\n",ck_errstr());
9663 else if (!nolist)
9664 printf("?%s\n",ck_errstr());
9665 } else {
9666 if (listing) printf("(OK)\n");
9667 }
9668 }
9669 }
9670 return(success = rc); /* Succeeds also if nothing needed to be renamed */
9671 }
9672
9673 int
dorenam()9674 dorenam() {
9675 #ifndef NOCSETS
9676 #ifndef NOUNICODE
9677 extern int nfilc;
9678 extern struct keytab fcstab[];
9679 extern struct csinfo fcsinfo[];
9680 #endif /* NOUNICODE */
9681 #endif /* NOCSETS */
9682 int cset1 = 0, cset2 = 0;
9683
9684 int i, x, z, fn, listing = 0, havename = 0, wild = 0, rc = 1, noarg = 0;
9685 int nolist = 0, all = 0, casing = 0, replacing = 0, getval = 0, sim = 0;
9686 int converting = 0, collision = 0;
9687
9688 char c;
9689 struct FDB sw, fi;
9690
9691 collision = ren_coll; /* Inherit SET RENAME COLLISION */
9692 listing = ren_list; /* Inhereit SET RENAME LIST */
9693
9694 if (ren_sub[0]) makestr(&(ren_sub[0]),NULL);
9695 if (ren_sub[1]) makestr(&(ren_sub[1]),NULL);
9696 if (ren_sub[2]) makestr(&(ren_sub[2]),NULL);
9697 line[0] = NUL;
9698 tmpbuf[0] = NUL;
9699
9700 cmfdbi(&sw, /* 1st FDB - switches */
9701 _CMKEY, /* fcode */
9702 "Filename or switch", /* hlpmsg */
9703 "", /* default */
9704 "", /* addtl string data */
9705 nrenamsw, /* addtl numeric data 1: tbl size */
9706 4, /* addtl numeric data 2: 4 = cmswi */
9707 xxstring, /* Processing function */
9708 renamsw, /* Keyword table */
9709 &fi /* Pointer to next FDB */
9710 );
9711
9712 cmfdbi(&fi, /* 2nd FDB - file or directory name */
9713 _CMIFI, /* fcode */
9714 "", /* hlpmsg */
9715 "", /* default */
9716 "", /* addtl string data */
9717 3, /* Flags */
9718 0, /* 0 = Parse file or directory names */
9719 xxstring,
9720 NULL,
9721 NULL
9722 );
9723
9724 if (cmflgs == 1) {
9725 printf("?File or directory name required\n");
9726 return(-9);
9727 }
9728 while (!havename) {
9729 noarg = 0;
9730 x = cmfdb(&sw); /* Parse something */
9731 if (x == -3) { /* They hit Enter prematurely */
9732 printf("?Command incomplete\n");
9733 return(-9);
9734 } else if (x < 0) { /* Other error */
9735 if (x == -1)
9736 return(x);
9737 if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
9738 printf("?No files match: %s\n",brstrip(atmbuf));
9739 else if (zchki(atmbuf) == -1)
9740 printf("?File not found: %s\n",brstrip(atmbuf));
9741 else
9742 printf("?Error with switch or filename: %s\n",brstrip(atmbuf));
9743 return(-9);
9744 }
9745 fn = cmresult.nresult; /* For brevity */
9746 switch (cmresult.fcode) { /* Handle each kind of field */
9747 case _CMKEY: /* Keyword (switch) */
9748 c = cmgbrk();
9749 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
9750 printf("?This switch does not take an argument\n");
9751 return(-9);
9752 }
9753 if (!getval && (cmgkwflgs() & CM_ARG))
9754 noarg = 1; /* Remember arg is missing */
9755 switch (cmresult.nresult) { /* Handle the switch */
9756 case DEL_LIS: /* /LIST */
9757 case DEL_VRB: /* /VERBOSE */
9758 listing = 1;
9759 break;
9760 case DEL_NOL: /* /NOLIST */
9761 case DEL_QUI: /* /QUIET */
9762 nolist = 1;
9763 listing = 0;
9764 break;
9765 case DEL_SIM: /* /SIMULATE */
9766 sim = 1;
9767 break;
9768 case REN_UPP: /* /UPPER: */
9769 case REN_LOW: /* /LOWER */
9770 all = 1;
9771 if (!noarg) {
9772 if ((x = cmkey((fn == REN_UPP) ? r_upper : r_lower,
9773 2, "","all",xxstring)) < 0) {
9774 if (x == -3)
9775 x = 1;
9776 else
9777 return(x);
9778 }
9779 all = x;
9780 }
9781 /* 0 = don't convert; 1 = convert to lower; 2 = to upper */
9782 casing = (fn == REN_UPP) ? 2 : 1;
9783 converting = 0;
9784 break;
9785 case REN_OVW: /* /COLLISION */
9786 if (!noarg) {
9787 if ((x = cmkey(r_collision,
9788 nr_collision,"","overwrite",xxstring))<0) {
9789 if (x == -3)
9790 x = RENX_OVWR;
9791 else
9792 return(x);
9793 }
9794 collision = x;
9795 }
9796 break;
9797 case REN_RPL: /* /REPLACE: */
9798 if (noarg) {
9799 printf("?This switch requires an argument\n");
9800 return(-9);
9801 }
9802 if ((x = cmfld("String to remove, or {{String1}{String2}}",
9803 "",&s,xxstring)) < 0) {
9804 if (x == -3) {
9805 printf("?Target string required\n");
9806 x = -9;
9807 }
9808 return(x);
9809 }
9810 if (s[0]) {
9811 if (s[0] == '{' && s[1] == '{') /* Get the list */
9812 makelist(s,ren_sub,3);
9813 else
9814 makestr(&(ren_sub[0]),s);
9815 }
9816 converting = 0;
9817 break;
9818
9819 case REN_SPA: /* /FIXSPACES: */
9820 if (!noarg)
9821 if ((x = cmfld("Character or string to replace spaces with",
9822 "_",&s,xxstring)) < 0)
9823 if (x == -3)
9824 s = "_";
9825 else
9826 return(x);
9827 makestr(&(ren_sub[0])," ");
9828 makestr(&(ren_sub[1]),noarg ? "_" : brstrip(s));
9829 makestr(&(ren_sub[3]),NULL);
9830 converting = 0;
9831 break;
9832
9833 #ifndef NOCSETS
9834 #ifndef NOUNICODE
9835 case REN_XLA: /* /CONVERT:cset1:cset2 */
9836 if (!xfcstab) { /* Make a copy of the file charset */
9837 int i, x; /* table with CM_ARG set for each */
9838 x = (nfilc + 1) * sizeof(struct keytab);
9839 xfcstab = (struct keytab *)malloc(x);
9840 if (!xfcstab) {
9841 printf("?Memory allocation failure\n");
9842 return(-9);
9843 }
9844 for (i = 0; i < nfilc; i++) {
9845 xfcstab[i].kwd = fcstab[i].kwd;
9846 xfcstab[i].kwval = fcstab[i].kwval;
9847 xfcstab[i].flgs = fcstab[i].flgs | CM_ARG;
9848 }
9849 }
9850 if ((x = cmswi(xfcstab,nfilc,
9851 "Character-set of old name","",xxstring)) < 0) {
9852 if (x == -3) {
9853 printf("?Pair of character-set names required\n");
9854 return(-9);
9855 } else
9856 return(x);
9857 }
9858 cset1 = x;
9859 c = cmgbrk();
9860 if (!getval) {
9861 printf("?Secondcharacter-set name required\n");
9862 return(-9);
9863 }
9864 if ((x = cmkey(fcstab,nfilc,
9865 "Character-set of new name","",xxstring)) < 0) {
9866 if (x == -3) {
9867 printf("?Second character-set name required\n");
9868 return(-9);
9869 } else
9870 return(x);
9871 }
9872 cset2 = x;
9873 if (casing)
9874 casing = 0;
9875 if (ren_sub[0])
9876 makestr(&(ren_sub[0]),NULL);
9877 if (ren_sub[1])
9878 makestr(&(ren_sub[1]),NULL);
9879 if (ren_sub[2])
9880 makestr(&(ren_sub[2]),NULL);
9881 converting = 1;
9882 break;
9883 #endif /* NOUNICODE */
9884 #endif /* NOCSETS */
9885 }
9886 break;
9887 case _CMIFI: /* File or directory name */
9888 s = cmresult.sresult;
9889 havename = 1;
9890 break;
9891 default:
9892 printf("?File or directory name required\n");
9893 return(-9);
9894 }
9895 }
9896 if (havename) {
9897 ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
9898 } else {
9899 printf("?Internal error\n");
9900 return(-9); /* Shouldn't happen */
9901 }
9902 wild = cmresult.nresult; /* Source specification wild? */
9903 if (!wild)
9904 wild = iswild(line);
9905
9906 debug(F111,"RENAME WILD",line,wild);
9907
9908 p = tmpbuf; /* Place for new name */
9909 p[0] = NUL;
9910 replacing = ren_sub[0] ? 1 : 0;
9911
9912 #ifdef COMMENT
9913 if (!(casing || replacing || converting)) {
9914 if ((x = cmofi(wild ? "Target directory" : "New name",
9915 "",&s,xxstring)) < 0) { /* Get new name */
9916 if (x == -3) {
9917 printf("?%s required\n",
9918 wild ? "Target directory" : "New name");
9919 return(-9);
9920 } else return(x);
9921 }
9922 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
9923 }
9924 #else
9925 if ((x = cmofi(wild ? "Target directory" : "New name",
9926 "",&s,xxstring)) < 0) { /* Get new name */
9927 if (x == -3) {
9928 if (casing || replacing || converting) {
9929 s = "";
9930 } else {
9931 printf("?%s required\n",
9932 wild ? "Target directory" : "New name");
9933 return(-9);
9934 }
9935 } else return(x);
9936 }
9937 ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
9938 #endif /* COMMENT */
9939
9940 if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
9941
9942 #ifdef COMMENT
9943 #ifndef NOUNICODE
9944 if (converting) {
9945 printf(" From: %s\n",fcsinfo[cset1].keyword);
9946 printf(" To: %s\n",fcsinfo[cset2].keyword);
9947 }
9948 #endif /* NOUNICODE */
9949 if (casing) {
9950 printf("CASING: %s\n", (casing == 1) ? "LOWER" : "UPPER");
9951 }
9952 if (replacing) {
9953 printf("REPLACING: '%s' with '%s'\n",
9954 ren_sub[0],
9955 ren_sub[1] ? ren_sub[1] : "");
9956 }
9957 #endif /* COMMENT */
9958
9959 s = line;
9960 if (!wild) /* Just one */
9961 return(success =
9962 renameone(s,p,
9963 replacing,casing,all,converting,cset1,cset2,
9964 listing,nolist,sim,TMPBUFSIZ,collision));
9965
9966 if (!casing && !replacing && !converting) { /* Multiple files */
9967 if (!isdir(p)) {
9968 printf( /* if target is not a directory */
9969 "?Multiple source files not allowed if target is not a directory.\n");
9970 return(-9);
9971 }
9972 }
9973 #ifdef COMMENT
9974 else { /* Show full path of target */
9975 char buf[CKMAXPATH]; /* (too much) */
9976 if (zfnqfp(p,CKMAXPATH,buf))
9977 ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
9978 }
9979 #endif /* COMMENT */
9980
9981 #ifdef VMS
9982 conres(); /* Let Ctrl-C work. */
9983 #endif /* VMS */
9984 debug(F110,"dorename line",line,0);
9985
9986 #ifdef ZXREWIND
9987 z = zxrewind(); /* Rewind file list */
9988 #else
9989 z = nzxpand(s,0); /* Expand file list */
9990 #endif /* ZXREWIND */
9991 debug(F111,"dorename p",p,z);
9992
9993 #ifdef UNIX
9994 if (wild && z > 1)
9995 sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
9996 #endif /* UNIX */
9997
9998 /* For /COLLISION:FAIL make a silent pass to see if there would be any */
9999
10000 if (collision == RENX_FAIL) {
10001 int n = 0;
10002 char line[CKMAXPATH+2];
10003 while (z-- > 0) {
10004 if (!(z == 0 && !wild))
10005 znext(line);
10006 if (!line[0])
10007 break;
10008 if (!renameone((char *)line,p,
10009 replacing,casing,all,converting,cset1,cset2,
10010 0,1,REN_OP_CHK,TMPBUFSIZ,RENX_FAIL))
10011 n++;
10012 }
10013 if (n > 0) {
10014 printf("?Failed: %d file%s would be overwritten\n",
10015 n, (n != 1) ? "s" : "");
10016 #ifdef VMS
10017 concb((char)escape);
10018 #endif /* VMS */
10019 return(success = 0);
10020 }
10021 /* Get the file list back. */
10022 #ifdef ZXREWIND
10023 z = zxrewind();
10024 #else
10025 z = nzxpand(s,0);
10026 #endif /* ZXREWIND */
10027 }
10028 while (z-- > 0 && rc > 0) {
10029 char line[CKMAXPATH+2];
10030 if (!(z == 0 && !wild))
10031 znext(line);
10032 if (!line[0])
10033 break;
10034 rc = renameone((char *)line,p,
10035 replacing,casing,all,converting,cset1,cset2,
10036 listing,nolist,sim,TMPBUFSIZ,collision);
10037 }
10038 #ifdef VMS
10039 concb((char)escape);
10040 #endif /* VMS */
10041 return(success = rc);
10042 }
10043 #endif /* ZRENAME */
10044 #endif /* NOFRILLS */
10045 #endif /* NORENAME */
10046
10047 #ifndef NOSPL
10048
10049 /* Do the RETURN command */
10050
10051 int
doreturn(s)10052 doreturn(s) char *s; {
10053 int x;
10054 extern int tra_asg;
10055 char * line, * lp;
10056
10057 if (cmdlvl < 1) {
10058 printf("\n?Can't return from level %d\n",maclvl);
10059 return(success = 0);
10060 }
10061 line = malloc(LINBUFSIZ);
10062 if (line == NULL)
10063 return(success = 0);
10064 lp = line; /* Expand return value now */
10065 x = LINBUFSIZ-1;
10066 if (!s) s = "";
10067 debug(F110,"RETURN s",s,0);
10068 if (zzstring(s,&lp,&x) > -1) {
10069 s = line;
10070 debug(F110,"RETURN zzstring",s,0);
10071 }
10072
10073 /* Pop from all FOR/WHILE/SWITCH/XIFs */
10074 while ((maclvl > 0) &&
10075 (m_arg[maclvl-1][0]) &&
10076 (cmdstk[cmdlvl].src == CMD_MD) &&
10077 (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
10078 !strncmp(m_arg[maclvl-1][0],"_for",4) ||
10079 !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
10080 !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
10081 debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl);
10082 dogta(XXPTA); /* Put args back */
10083 popclvl(); /* Pop up two levels */
10084 popclvl();
10085 }
10086 if (tra_asg) { /* If tracing show return value */
10087 if (*s)
10088 printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
10089 else
10090 printf("<<< %s: (null)\n", m_arg[maclvl][0]);
10091 }
10092 popclvl(); /* Pop from enclosing TAKE or macro */
10093 debug(F111,"RETURN tolevel",s,maclvl);
10094 if (!s) s = "";
10095 if (!*s) s = NULL;
10096 makestr(&(mrval[maclvl+1]),s); /* Set the RETURN value */
10097 free(line);
10098 return(success = 1); /* Macro succeeds if we RETURN */
10099 }
10100 #endif /* NOSPL */
10101
10102 #ifndef NOSPL
10103 /* Do the OPEN command */
10104
10105 int
doopen()10106 doopen() { /* OPEN { append, read, write } */
10107 int x, y, z = 0; char *s;
10108 static struct filinfo fcb; /* (must be static) */
10109 if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
10110 if (x == -3) {
10111 printf("?Mode required\n");
10112 return(-9);
10113 } else return(x);
10114 }
10115 switch (x) {
10116 case OPN_FI_R: /* Old file (READ) */
10117 if (chkfn(ZRFILE) > 0) {
10118 printf("?Read file already open\n");
10119 return(-2);
10120 }
10121 if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
10122 if (z == -3) {
10123 printf("?Input filename required\n");
10124 return(-9);
10125 } else return(z);
10126 }
10127 if (y) { /* No wildcards allowed */
10128 printf("\n?Please specify a single file\n");
10129 return(-2);
10130 }
10131 ckstrncpy(line,s,LINBUFSIZ);
10132 if ((int)strlen(line) < 1) return(-2);
10133 if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
10134 return(z);
10135 if (y < 1) {
10136 printf("?Positive number required\n");
10137 return(-9);
10138 }
10139 if ((z = cmcfm()) < 0) return(z);
10140 readblock = y;
10141 if (readbuf)
10142 free((char *)readbuf);
10143 if (!(readbuf = (CHAR *) malloc(readblock+1))) {
10144 printf("?Can't allocate read buffer\n");
10145 return(-9);
10146 }
10147 return(success = zopeni(ZRFILE,line));
10148
10149 #ifndef MAC
10150 #ifndef NOPUSH
10151 case OPN_PI_R: /* Pipe/Process (!READ) */
10152 if (nopush) {
10153 printf("?Read from pipe disabled\n");
10154 return(success=0);
10155 }
10156 if (chkfn(ZRFILE) > 0) {
10157 printf("?Read file already open\n");
10158 return(-2);
10159 }
10160 if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
10161 if (y == -3) {
10162 printf("?Command name required\n");
10163 return(-9);
10164 } else return(y);
10165 }
10166 ckstrncpy(line,brstrip(s),LINBUFSIZ);
10167 if (!line[0]) return(-2);
10168 if ((y = cmcfm()) < 0) return(y);
10169 if (!readbuf) {
10170 if (!(readbuf = (CHAR *) malloc(readblock+1))) {
10171 printf("?Can't allocate read buffer\n");
10172 return(-9);
10173 }
10174 }
10175 return(success = zxcmd(ZRFILE,line));
10176
10177 case OPN_PI_W: /* Write to pipe */
10178 if (nopush) {
10179 printf("?Write to pipe disabled\n");
10180 return(success=0);
10181 }
10182 if (chkfn(ZWFILE) > 0) {
10183 printf("?Write file already open\n");
10184 return(-2);
10185 }
10186 if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
10187 if (y == -3) {
10188 printf("?Command name required\n");
10189 return(-9);
10190 } else return(y);
10191 }
10192 ckstrncpy(line,brstrip(s),LINBUFSIZ);
10193 if (!line[0]) return(-2);
10194 if ((y = cmcfm()) < 0) return(y);
10195 success = zxcmd(ZWFILE,line);
10196 if (!success && msgflg)
10197 printf("Can't open process for writing: %s\n",line);
10198 return(success);
10199 #endif /* NOPUSH */
10200 #endif /* MAC */
10201
10202 case OPN_FI_W: /* New file (WRITE) */
10203 case OPN_FI_A: /* (APPEND) */
10204 if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
10205 if (z == -3) {
10206 printf("?Filename required\n");
10207 return(-9);
10208 } else return(z);
10209 }
10210 if (z == 2) {
10211 printf("?Sorry, %s is a directory name\n",s);
10212 return(-9);
10213 }
10214 if (chkfn(ZWFILE) > 0) {
10215 printf("?Write/Append file already open\n");
10216 return(-2);
10217 }
10218 fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
10219 fcb.lblopts = 0;
10220 fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
10221 ckstrncpy(line,s,LINBUFSIZ);
10222 if ((int)strlen(line) < 1) return(-2);
10223 if ((y = cmcfm()) < 0) return(y);
10224 return(success = zopeno(ZWFILE,line,NULL,&fcb));
10225
10226 #ifndef NOLOCAL
10227 case OPN_SER: /* OPEN PORT or LINE */
10228 case OPN_NET: { /* OPEN HOST */
10229 extern int didsetlin, ttnproto;
10230 if (x == OPN_NET) {
10231 z = ttnproto;
10232 ttnproto = NP_NONE;
10233 }
10234 if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
10235 if (x == OPN_NET)
10236 ttnproto = z;
10237 success = 0;
10238 }
10239 didsetlin++;
10240 return(y);
10241 }
10242 #endif /* NOLOCAL */
10243
10244 default:
10245 printf("?Not implemented");
10246 return(-2);
10247 }
10248 }
10249 #endif /* NOSPL */
10250
10251 #ifndef NOXFER
10252 /* D O X G E T -- GET command parser with switches */
10253
10254 #ifdef CK_LABELED
10255 int g_lf_opts = -1;
10256 extern int lf_opts;
10257 #endif /* CK_LABELED */
10258
10259 int
doxget(cx)10260 doxget(cx) int cx; {
10261 extern int /* External variables we need */
10262 #ifdef RECURSIVE
10263 recursive,
10264 #endif /* RECURSIVE */
10265 xfermode, fdispla, protocol, usepipes,
10266 g_binary, g_xfermode, g_displa, g_rpath, g_usepipes;
10267 extern char * rcv_move; /* Directory to move new files to */
10268 extern char * rcv_rename; /* What to rename new files to */
10269 extern char * rcvexcept[]; /* RECEIVE / GET exception list */
10270 int opkt = 0; /* Flag for O-Packet needed */
10271
10272 #ifdef PIPESEND
10273 extern int pipesend;
10274 extern char * rcvfilter;
10275 #endif /* PIPESEND */
10276 extern struct keytab rpathtab[];
10277 extern int nrpathtab;
10278 extern CK_OFF_T calibrate;
10279 int asname = 0; /* Flag for have as-name */
10280 int konly = 0; /* Kermit-only function */
10281 int c, i, n, confirmed = 0; /* Workers */
10282 int getval = 0; /* Whether to get switch value */
10283 int rcvcmd = 0; /* Whether it is the RECEIVE command */
10284 int mget = 0; /* Whether it is the MGET command */
10285 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
10286 struct FDB sw, fl, cm; /* FDBs for each parse function */
10287 char * cmdstr = "this command";
10288
10289 #ifdef NEWFTP
10290 if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) {
10291 extern int ftpget;
10292 extern int ftpisopen();
10293 if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) {
10294 int x;
10295 x = doftpget(cx,0);
10296 debug(F101,"doftpget return","",x);
10297 if (x > -1)
10298 success = x;
10299 debug(F101,"doftpget success","",success);
10300 return(x);
10301 }
10302 }
10303 #endif /* NEWFTP */
10304
10305 debug(F101,"xget cx","",cx);
10306
10307 oopts = -1;
10308 omode = -1;
10309
10310 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
10311 pv[i].sval = NULL;
10312 pv[i].ival = -1;
10313 pv[i].wval = (CK_OFF_T)-1;
10314 }
10315 /* Preset switch values based on top-level command that called us */
10316
10317 switch (cx) {
10318 case XXREC: /* RECEIVE */
10319 cmdstr = "RECEIVE";
10320 rcvcmd = 1; break;
10321 case XXGET: /* GET */
10322 cmdstr = "GET";
10323 konly = 1;
10324 break;
10325 #ifdef CK_RESEND
10326 case XXREGET: /* REGET */
10327 cmdstr = "REGET";
10328 konly = 1;
10329 pv[SND_BIN].ival = 1; /* Implies /BINARY */
10330 pv[SND_RES].ival = 1; break;
10331 #endif /* CK_RESEND */
10332 case XXRETR: /* RETRIEVE */
10333 cmdstr = "RETRIEVE";
10334 konly = 1;
10335 pv[SND_DEL].ival = 1; break;
10336 #ifdef PIPESEND
10337 case XXCREC: /* CRECEIVE */
10338 cmdstr = "CRECEIVE";
10339 konly = 1;
10340 rcvcmd = 1;
10341 pv[SND_CMD].ival = 1; break;
10342 case XXCGET: /* CGET */
10343 cmdstr = "CGET";
10344 konly = 1;
10345 pv[SND_CMD].ival = 1; break;
10346 #endif /* PIPESEND */
10347 #ifndef NOMGET
10348 case XXMGET: /* MGET */
10349 cmdstr = "MGET";
10350 konly = 1;
10351 mget = 1; break;
10352 #endif /* NOMGET */
10353 }
10354 debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
10355 debug(F101,"xget konly","",konly);
10356
10357 #ifdef CK_XYZ
10358 if (!rcvcmd && protocol != PROTO_K) {
10359 printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
10360 return(-9);
10361 }
10362 #endif /* CK_XYZ */
10363
10364 /* Set up chained parse functions... */
10365
10366 cmfdbi(&sw, /* First FDB - command switches */
10367 _CMKEY, /* fcode */
10368 rcvcmd ?
10369 "Optional name/template to store incoming files under, or switch" :
10370 "Remote filename, or switch", /* hlpmsg */
10371 "", /* default */
10372 "", /* addtl string data */
10373 rcvcmd ? nrcvtab : ngettab, /* addtl numeric data 1: tbl size */
10374 4, /* addtl numeric data 2: 4 = cmswi */
10375 xxstring, /* Processing function */
10376 rcvcmd ? rcvtab : gettab, /* Keyword table */
10377 &fl /* Pointer to next FDB */
10378 );
10379 if (rcvcmd || mget) /* RECEIVE or MGET */
10380 cmfdbi(&fl,
10381 _CMTXT, /* fcode */
10382 rcvcmd ? /* hlpmsg */
10383 "Output filename or Command" : /* Output filename */
10384 "File(s) to GET", /* Files we are asking for */
10385 "", /* default */
10386 "", /* addtl string data */
10387 0, /* addtl numeric data 1 */
10388 0, /* addtl numeric data 2 */
10389 #ifdef COMMENT
10390 #ifdef CK_XYZ
10391 (protocol == PROTO_X || protocol == PROTO_XC) ?
10392 xxstring :
10393 (rcvcmd ? (xx_strp)0 : xxstring)
10394 #else
10395 rcvcmd ? (xx_strp)0 : xxstring /* Processing function */
10396 #endif /* CK_XYZ */
10397 #else /* COMMENT */
10398 xxstring /* Always evaluate - fdc 2006/02/01 */
10399 #endif /* COMMENT */
10400 ,
10401 NULL,
10402 &cm
10403 );
10404 else
10405 cmfdbi(&fl, /* Remote filename or command */
10406 _CMFLD, /* fcode */
10407 "Remote filename", /* hlpmsg */
10408 "", /* default */
10409 "", /* addtl string data */
10410 0, /* addtl numeric data 1 */
10411 0, /* addtl numeric data 2 */
10412 xxstring,
10413 NULL,
10414 &cm
10415 );
10416 cmfdbi(&cm, /* Confirmation */
10417 _CMCFM, /* fcode */
10418 "", /* hlpmsg */
10419 "", /* default */
10420 "", /* addtl string data */
10421 0, /* addtl numeric data 1 */
10422 0, /* addtl numeric data 2 */
10423 NULL,
10424 NULL,
10425 NULL
10426 );
10427
10428 /* (See doxsend() for fuller commentary) */
10429
10430 while (1) { /* Parse 0 or more switches */
10431 x = cmfdb(&sw); /* Parse something */
10432 debug(F101,"xget cmfdb","",x);
10433 if (x < 0) /* Error */
10434 goto xgetx; /* or reparse needed */
10435 if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
10436 break;
10437 c = cmgbrk(); /* Get break character */
10438 if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
10439 printf("?This switch does not take an argument\n");
10440 x = -9;
10441 goto xgetx;
10442 }
10443 if (!getval && (cmgkwflgs() & CM_ARG)) {
10444 printf("?This switch requires an argument\n");
10445 x = -9;
10446 goto xgetx;
10447 }
10448 n = cmresult.nresult; /* Numeric result = switch value */
10449 debug(F101,"xget switch","",n);
10450
10451 switch (n) { /* Process the switch */
10452 #ifdef PIPESEND
10453 case SND_CMD: /* These take no args */
10454 if (nopush) {
10455 printf("?Sorry, system command access is disabled\n");
10456 x = -9;
10457 goto xgetx;
10458 } else if (rcvfilter) {
10459 printf(
10460 "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
10461 x = -9;
10462 goto xgetx;
10463 }
10464 if (rcvcmd)
10465 sw.hlpmsg = "Command, or switch"; /* Change help message */
10466 /* Fall thru... */
10467 #endif /* PIPESEND */
10468
10469 case SND_REC: /* /RECURSIVE */
10470 pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
10471 pv[n].ival = 1; /* Set the recursive flag */
10472 break;
10473
10474 case SND_RES: /* /RECOVER */
10475 pv[SND_BIN].ival = 1; /* Implies /BINARY */
10476 pv[n].ival = 1; /* Set the resend flag */
10477 break;
10478
10479 case SND_DEL: /* /DELETE */
10480 case SND_SHH: /* /QUIET */
10481 case SND_CAL: /* /CALIBRATE */
10482 case SND_XPA: /* /TRANSPARENT */
10483 pv[n].ival = 1; /* Just set the appropriate flag */
10484 break;
10485
10486 case SND_PIP: /* /PIPES:{ON,OFF} */
10487 if (!getval) {
10488 pv[n].ival = 1;
10489 break;
10490 }
10491 if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
10492 goto xgetx;
10493 if (!nopush)
10494 pv[n].ival = x;
10495 break;
10496
10497 /* File transfer modes - each undoes the others */
10498
10499 case SND_BIN: /* Binary */
10500 case SND_TXT: /* Text */
10501 case SND_IMG: /* Image */
10502 case SND_LBL: /* Labeled */
10503 pv[SND_BIN].ival = 0; /* Unset all */
10504 pv[SND_TXT].ival = 0;
10505 pv[SND_IMG].ival = 0;
10506 pv[SND_LBL].ival = 0;
10507 pv[n].ival = 1; /* Set the requested one */
10508 break;
10509
10510 case SND_EXC: /* Excludes */
10511 if (!getval) break;
10512 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
10513 if (x == -3) {
10514 printf("?Pattern required\n");
10515 x = -9;
10516 }
10517 goto xgetx;
10518 }
10519 if (pv[n].sval) free(pv[n].sval);
10520 y = strlen(s);
10521 if (y > 256) {
10522 printf("?Pattern too long - 256 max\n");
10523 x = -9;
10524 goto xgetx;
10525 }
10526 pv[n].sval = malloc(y+1);
10527 if (pv[n].sval) {
10528 strcpy(pv[n].sval,s); /* safe */
10529 pv[n].ival = 1;
10530 }
10531 break;
10532
10533 #ifdef COMMENT
10534 /* Not implemented */
10535 case SND_PRI: /* GET to printer */
10536 pv[n].ival = 1;
10537 if (!getval) break;
10538 if ((x = cmfld("Print options","",&s,xxstring)) < 0)
10539 goto xgetx;
10540 pv[n].sval = malloc((int)strlen(s)+1);
10541 if (pv[n].sval)
10542 strcpy(pv[n].sval,s); /* safe */
10543 break;
10544 #endif /* COMMENT */
10545
10546 case SND_MOV: /* MOVE after */
10547 case SND_REN: /* RENAME after */
10548 if (!getval) break;
10549 if ((x = cmfld(n == SND_MOV ?
10550 "device and/or directory for source file after sending" :
10551 "new name for source file after sending",
10552 "",
10553 &s,
10554 n == SND_MOV ? xxstring : NULL
10555 )) < 0) {
10556 if (x == -3) {
10557 printf("%s\n", n == SND_MOV ?
10558 "?Destination required" :
10559 "?New name required"
10560 );
10561 x = -9;
10562 }
10563 goto xgetx;
10564 }
10565 if (pv[n].sval) {
10566 free(pv[n].sval);
10567 pv[n].sval = NULL;
10568 }
10569 s = brstrip(s);
10570 y = strlen(s);
10571 if (y > 0) {
10572 pv[n].sval = malloc(y+1);
10573 if (pv[n].sval) {
10574 strcpy(pv[n].sval,s); /* safe */
10575 pv[n].ival = 1;
10576 }
10577 }
10578 break;
10579
10580 case SND_ASN: /* As-name */
10581 if (!getval) break;
10582 if (mget) {
10583 printf("?Sorry, as-name not allowed with MGET\n");
10584 x = -9;
10585 goto xgetx;
10586 }
10587 if (
10588 #ifdef COMMENT
10589 (x = cmfld("Name to store it under","",&s,NULL))
10590 #else
10591 (x = cmfld("Name to store it under","",&s,xxstring))
10592 #endif /* COMMENT */
10593 < 0)
10594 goto xgetx;
10595 s = brstrip(s);
10596 if ((y = strlen(s)) > 0) {
10597 if (pv[n].sval) free(pv[n].sval);
10598 pv[n].sval = malloc(y+1);
10599 if (pv[n].sval) {
10600 strcpy(pv[n].sval,s); /* safe */
10601 pv[n].ival = 1;
10602 }
10603 }
10604 break;
10605
10606 #ifdef PIPESEND
10607 case SND_FLT: /* Filter */
10608 debug(F101,"xget /filter getval","",getval);
10609 if (!getval) break;
10610 if ((x = cmfld("Filter program to receive through",
10611 "",&s,NULL)) < 0) {
10612 if (x == -3)
10613 s = "";
10614 else
10615 goto xgetx;
10616 }
10617 if (*s) s = brstrip(s);
10618 y = strlen(s);
10619 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
10620 if (s[x] != '\\') continue;
10621 if (s[x+1] == 'v') break;
10622 }
10623 if (x == y) {
10624 printf(
10625 "?Filter must contain a replacement variable for filename.\n"
10626 );
10627 x = -9;
10628 goto xgetx;
10629 }
10630 pv[n].ival = 1;
10631 if (pv[n].sval) {
10632 free(pv[n].sval);
10633 pv[n].sval = NULL;
10634 }
10635 if ((y = strlen(s)) > 0) {
10636 if ((pv[n].sval = malloc(y+1)))
10637 strcpy(pv[n].sval,s); /* safe */
10638 }
10639 break;
10640 #endif /* PIPESEND */
10641
10642 case SND_PTH: /* Pathnames */
10643 if (!getval) {
10644 pv[n].ival = PATH_REL;
10645 break;
10646 }
10647 if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
10648 goto xgetx;
10649 pv[n].ival = x; /* Ditto */
10650 break;
10651
10652 case SND_NAM: /* Filenames */
10653 if (!getval) break;
10654 if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
10655 goto xgetx;
10656 pv[n].ival = x;
10657 break;
10658
10659 case SND_PRO: /* Protocol to use */
10660 if (!getval) break;
10661 if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
10662 xxstring)) < 0) {
10663 if (x == -3)
10664 x = 0;
10665 else
10666 goto xgetx;
10667 }
10668 debug(F111,"xget /proto",atmbuf,x);
10669 pv[n].ival = x;
10670 if (konly && x != PROTO_K) {
10671 printf(
10672 "?Sorry, this command works only with Kermit protocol\n"
10673 );
10674 x = -9;
10675 goto xgetx;
10676 }
10677 break;
10678
10679 default:
10680 printf("?Unexpected switch value - %d\n",cmresult.nresult);
10681 x = -9;
10682 goto xgetx;
10683 }
10684 }
10685 debug(F101,"xget cmresult fcode","",cmresult.fcode);
10686
10687 cmarg = line; /* Initialize string pointers */
10688 cmarg2 = tmpbuf;
10689 asname = 0;
10690 line[0] = NUL; /* and buffers. */
10691 tmpbuf[0] = NUL;
10692
10693 switch (cmresult.fcode) { /* How did we get out of switch loop */
10694 case _CMFLD: /* (3) Remote filespec */
10695 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
10696 break;
10697 case _CMTXT: /* (4) As-name */
10698 if (rcvcmd) {
10699 ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
10700 if ((int)strlen(tmpbuf) > 0)
10701 asname = 1;
10702 } else {
10703 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
10704 }
10705 case _CMCFM: /* (6) Confirmation */
10706 confirmed = 1;
10707 break;
10708 default:
10709 printf("?Unexpected function code: %d\n",cmresult.fcode);
10710 x = -9;
10711 goto xgetx;
10712 }
10713 debug(F110,"xget string",cmarg,0);
10714 debug(F101,"xget confirmed","",confirmed);
10715
10716 cmarg = brstrip(cmarg); /* Strip any braces */
10717
10718 if (!confirmed) { /* CR not typed yet, get more fields */
10719 if (pv[SND_CMD].ival > 0) {
10720 debug(F100,"xget calling cmtxt","",0);
10721 x = cmtxt("Local command to pipe into","",&s,NULL);
10722 if (x < 0 && x != -3) goto xgetx;
10723 if (x != -3) {
10724 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
10725 asname = 1;
10726 }
10727 } else if (!rcvcmd) {
10728 #ifdef VMS
10729 /* cmofi() fails if you give it a directory name */
10730 x = cmfld("Name or directory for incoming file","",&s,NULL);
10731 debug(F111,"xget cmfld",s,x);
10732 #else
10733 x = cmofi("Name or directory for incoming file","",&s,NULL);
10734 debug(F111,"xget cmofi",s,x);
10735 #endif /* VMS */
10736 if (x < 0 && x != -3) goto xgetx;
10737 if (x != -3) {
10738 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
10739 if ((x = cmcfm()) < 0) goto xgetx;
10740 asname = 1;
10741 }
10742 }
10743 }
10744 /* Arrive here with cmarg and cmarg2 all set */
10745
10746 debug(F111,"xget asname",cmarg2,asname);
10747 if (!asname) {
10748 if (pv[SND_ASN].sval)
10749 ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
10750 else
10751 tmpbuf[0] = NUL;
10752 }
10753 cmarg2 = brstrip(cmarg2); /* Strip outer braces if any. */
10754 debug(F110,"xget cmarg",cmarg,0);
10755 debug(F110,"xget cmarg2",cmarg2,0);
10756
10757 if (!*cmarg &&
10758 (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
10759 printf("?A remote file specification is required\n");
10760 x = -9;
10761 goto xgetx;
10762 }
10763 #ifdef PIPESEND
10764 if (pv[SND_CMD].ival > 0) { /* /COMMAND sets pipesend flag */
10765 x = -9;
10766 if (!*cmarg2) {
10767 printf("?Command required\n");
10768 goto xgetx;
10769 } else if (nopush) {
10770 printf("?Sorry, system command access is disabled\n");
10771 goto xgetx;
10772 } else if (rcvfilter) {
10773 printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
10774 goto xgetx;
10775 } else
10776 pipesend = 1;
10777 }
10778 debug(F101,"xget /COMMAND pipesend","",pipesend);
10779 #endif /* PIPESEND */
10780
10781 #ifdef CK_RESEND
10782 if (pv[SND_RES].ival > 0) { /* REGET or GET /RECOVER */
10783 #ifdef RECURSIVE
10784 if (pv[SND_REC].ival > 0) { /* RECURSIVE */
10785 #ifdef COMMENT
10786 printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
10787 x = -9;
10788 goto xgetx;
10789 #else
10790 opkt = 1;
10791 #endif /* COMMENT */
10792 }
10793 #endif /* RECURSIVE */
10794 if (pv[SND_DEL].ival > 0) { /* /DELETE */
10795 #ifdef COMMENT
10796 printf("?Unsupported option combination: /RECOVER /DELETE\n");
10797 x = -9;
10798 goto xgetx;
10799 #else
10800 opkt = 1;
10801 #endif /* COMMENT */
10802 }
10803 }
10804 #endif /* CK_RESEND */
10805
10806 if (pv[SND_EXC].ival > 0) /* /EXCEPT */
10807 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
10808
10809 #ifdef IKS_OPTION
10810 if (!rcvcmd
10811 #ifdef CK_XYZ
10812 && protocol == PROTO_K
10813 #endif /* CK_XYZ */
10814 ) {
10815 if (!iks_wait(KERMIT_REQ_START,1)) {
10816 printf(
10817 "?A Kermit Server is not available to process this command\n");
10818 x = -9; /* correct the return code */
10819 goto xgetx;
10820 }
10821 }
10822 #endif /* IKS_OPTION */
10823
10824 #ifdef CK_XYZ
10825 {
10826 int po, pg; /* (for clarity) */
10827 po = pv[SND_PRO].ival; /* /PROTOCOL option */
10828 pg = protocol; /* Protocol global */
10829 if ((rcvcmd && !*cmarg2) && /* If no as-name was given */
10830 /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */
10831 ((po < 0 && (pg == PROTO_X || pg == PROTO_XC)) ||
10832 (po > -1 && (po == PROTO_X || po == PROTO_XC)))
10833 ) {
10834 printf(
10835 "Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
10836 );
10837 x = -9;
10838 goto xgetx;
10839 }
10840 }
10841 #endif /* CK_XYZ */
10842
10843 #ifdef RECURSIVE
10844 if (pv[SND_REC].ival > 0) { /* RECURSIVE */
10845 recursive = 1;
10846 pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames too */
10847 }
10848 #endif /* RECURSIVE */
10849
10850 if (pv[SND_PIP].ival > -1) {
10851 g_usepipes = usepipes;
10852 usepipes = pv[SND_PIP].ival;
10853 }
10854
10855 /* Save global protocol parameters */
10856
10857 g_proto = protocol;
10858 #ifdef CK_LABELED
10859 g_lf_opts = lf_opts; /* Save labeled transfer options */
10860 #endif /* CK_LABELED */
10861 g_urpsiz = urpsiz; /* Receive packet length */
10862 g_spsizf = spsizf; /* Send packet length flag */
10863 g_spsiz = spsiz; /* Send packet length */
10864 g_spsizr = spsizr; /* etc etc */
10865 g_spmax = spmax;
10866 g_wslotr = wslotr;
10867 g_prefixing = prefixing;
10868 g_fncact = fncact;
10869 g_fncnv = fncnv;
10870 g_fnspath = fnspath;
10871 g_fnrpath = fnrpath;
10872 g_xfrxla = xfrxla;
10873
10874 if (pv[SND_PRO].ival > -1) { /* Change according to switch */
10875 protocol = pv[SND_PRO].ival;
10876 if (ptab[protocol].rpktlen > -1) /* copied from initproto() */
10877 urpsiz = ptab[protocol].rpktlen;
10878 if (ptab[protocol].spktflg > -1)
10879 spsizf = ptab[protocol].spktflg;
10880 if (ptab[protocol].spktlen > -1) {
10881 spsiz = ptab[protocol].spktlen;
10882 if (spsizf)
10883 spsizr = spmax = spsiz;
10884 }
10885 if (ptab[protocol].winsize > -1)
10886 wslotr = ptab[protocol].winsize;
10887 if (ptab[protocol].prefix > -1)
10888 prefixing = ptab[protocol].prefix;
10889 if (ptab[protocol].fnca > -1)
10890 fncact = ptab[protocol].fnca;
10891 if (ptab[protocol].fncn > -1)
10892 fncnv = ptab[protocol].fncn;
10893 if (ptab[protocol].fnsp > -1)
10894 fnspath = ptab[protocol].fnsp;
10895 if (ptab[protocol].fnrp > -1)
10896 fnrpath = ptab[protocol].fnrp;
10897 }
10898 debug(F101,"xget protocol","",protocol);
10899 debug(F111,"xget cmarg2",cmarg2,xfermode);
10900
10901 g_xfermode = xfermode;
10902 g_binary = binary;
10903 if (pv[SND_BIN].ival > 0) { /* Change according to switch */
10904 xfermode = XMODE_M;
10905 binary = XYFT_B; /* FILE TYPE BINARY */
10906 omode = GMOD_BIN; /* O-Packet mode */
10907 debug(F101,"doxget /BINARY xfermode","",xfermode);
10908 } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */
10909 xfermode = XMODE_M;
10910 binary = XYFT_T;
10911 omode = GMOD_TXT;
10912 debug(F101,"doxget /TEXT xfermode","",xfermode);
10913 } else if (pv[SND_IMG].ival > 0) {
10914 xfermode = XMODE_M;
10915 #ifdef VMS
10916 binary = XYFT_I;
10917 #else
10918 binary = XYFT_B;
10919 #endif /* VMS */
10920 omode = GMOD_TXT;
10921 debug(F101,"doxget /IMAGE xfermode","",xfermode);
10922 }
10923 #ifdef CK_LABELED
10924 else if (pv[SND_LBL].ival > 0) {
10925 xfermode = XMODE_M;
10926 binary = XYFT_L;
10927 omode = GMOD_LBL;
10928 debug(F101,"doxget /LABELED xfermode","",xfermode);
10929 }
10930 #endif /* CK_LABELED */
10931 debug(F101,"xget binary","",binary);
10932 debug(F101,"xget omode","",omode);
10933
10934 if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */
10935 xfrxla = 0; /* Don't translate character sets */
10936
10937 #ifdef PIPESEND
10938 if (pv[SND_FLT].ival > 0)
10939 makestr(&rcvfilter,pv[SND_FLT].sval);
10940 #endif /* PIPESEND */
10941
10942 #ifdef CK_TMPDIR
10943 if (pv[SND_MOV].ival > 0) {
10944 int len;
10945 char * p = pv[SND_MOV].sval;
10946 #ifdef CK_LOGIN
10947 if (isguest) {
10948 printf("?Sorry, /MOVE-TO not available to guests\n");
10949 x = -9;
10950 goto xgetx;
10951 }
10952 #endif /* CK_LOGIN */
10953 len = strlen(p);
10954 if (!isdir(p)) { /* Check directory */
10955 #ifdef CK_MKDIR
10956 char * s = NULL;
10957 s = (char *)malloc(len + 4);
10958 if (s) {
10959 strcpy(s,p); /* safe */
10960 #ifdef datageneral
10961 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
10962 #else
10963 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
10964 #endif /* datageneral */
10965 s[len++] = 'X';
10966 s[len] = NUL;
10967 x = zmkdir(s);
10968 free(s);
10969 if (x < 0) {
10970 printf("?Can't create \"%s\"\n",p);
10971 x = -9;
10972 goto xgetx;
10973 }
10974 }
10975 #else
10976 printf("?Directory \"%s\" not found\n",p);
10977 x = -9;
10978 goto xgetx;
10979 #endif /* CK_MKDIR */
10980 }
10981 zfnqfp(p,LINBUFSIZ,line);
10982 makestr(&rcv_move,line);
10983 }
10984 #endif /* CK_TMPDIR */
10985
10986 if (pv[SND_REN].ival > 0) { /* /RENAME-TO:name */
10987 char * p = pv[SND_REN].sval;
10988 #ifdef CK_LOGIN
10989 if (isguest) {
10990 printf("?Sorry, /RENAME-TO not available to guests\n");
10991 x = -9;
10992 goto xgetx;
10993 }
10994 #endif /* CK_LOGIN */
10995 if (!p) p = "";
10996 if (!*p) {
10997 printf("?New name required for /RENAME\n");
10998 x = -9;
10999 goto xgetx;
11000 }
11001 p = brstrip(p);
11002 makestr(&rcv_rename,p);
11003 debug(F110,"xget rcv_rename","",0);
11004 }
11005
11006 #ifdef CALIBRATE
11007 if (pv[SND_CAL].ival > 0)
11008 calibrate = (CK_OFF_T)1;
11009 #endif /* CALIBRATE */
11010 g_displa = fdispla;
11011 if (pv[SND_SHH].ival > 0)
11012 fdispla = 0;
11013 debug(F101,"xget display","",fdispla);
11014
11015 if (pv[SND_NAM].ival > -1) { /* /FILENAMES */
11016 g_fncnv = fncnv; /* Save global value */
11017 fncnv = pv[SND_NAM].ival;
11018 debug(F101,"xsend fncnv","",fncnv);
11019 /* We should also handle O packet filename option here */
11020 /* but we don't really need to since WHATAMI already handles it */
11021 }
11022 if (pv[SND_PTH].ival > -1) { /* PATHNAMES */
11023 g_rpath = fnrpath; /* Save global values */
11024 fnrpath = pv[SND_PTH].ival;
11025 debug(F101,"xsend fnrpath","",fnrpath);
11026 #ifndef NZLTOR
11027 if (fnrpath != PATH_OFF) {
11028 g_fncnv = fncnv;
11029 fncnv = XYFN_L;
11030 debug(F101,"xsend fncnv","",fncnv);
11031 }
11032 /* We should also handle O packet pathname option here */
11033 /* but we don't really need to since WHATAMI already handles it */
11034 #endif /* NZLTOR */
11035 }
11036
11037 /* Set protocol start state */
11038
11039 if (opkt) { /* Extended GET Options*/
11040 sstate = (CHAR) 'o';
11041 oopts = 0;
11042 if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
11043 if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
11044 if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
11045 } else if (rcvcmd)
11046 sstate = (CHAR) 'v'; /* RECEIVE or CRECEIVE */
11047 else if (pv[SND_DEL].ival > 0)
11048 sstate = (CHAR) 'h'; /* GET /DELETE (= RETRIEVE) */
11049 else if (pv[SND_RES].ival > 0)
11050 sstate = (CHAR) 'j'; /* GET /RECOVER (= REGET) */
11051 else
11052 sstate = (CHAR) 'r'; /* Regular GET */
11053 getcmd = 1;
11054 debug(F000,"xget sstate","",sstate);
11055 #ifdef MAC
11056 what = W_RECV;
11057 scrcreate();
11058 #endif /* MAC */
11059 if (local) {
11060 if (pv[SND_SHH].ival != 0)
11061 displa = 1;
11062 if (protocol == PROTO_K) /* fdc 20070108 */
11063 ttflui();
11064 }
11065 x = 0;
11066 #ifdef PIPESEND
11067 if (pipesend)
11068 goto xgetx;
11069 #endif /* PIPESEND */
11070
11071 #ifdef CK_TMPDIR
11072 /*
11073 cmarg2 is also allowed to be a device or directory name;
11074 even the name of a directory that doesn't exist.
11075 */
11076 y = strlen(cmarg2);
11077 debug(F111,"xget strlen(cmarg2)",cmarg2,y);
11078 if ((y > 0) &&
11079 #ifdef OS2
11080 ((isalpha(cmarg2[0]) &&
11081 cmarg2[1] == ':' &&
11082 cmarg2[2] == NUL) ||
11083 (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
11084 isdir(cmarg2))
11085 #else
11086 #ifdef UNIXOROSK
11087 (cmarg2[y-1] == '/' || isdir(cmarg2))
11088 #else
11089 #ifdef VMS
11090 (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
11091 #else
11092 #ifdef STRATUS
11093 (cmarg2[y-1] == '>' || isdir(cmarg2))
11094 #else
11095 #ifdef datageneral
11096 (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
11097 #else
11098 isdir(cmarg2)
11099 #endif /* datageneral */
11100 #endif /* STRATUS */
11101 #endif /* VMS */
11102 #endif /* UNIXOROSK */
11103 #endif /* OS2 */
11104 ) {
11105 debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
11106 if (!f_tmpdir) {
11107 int x;
11108 s = zgtdir();
11109 if (s) {
11110 ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
11111 f_tmpdir = 1; /* and that we did this */
11112 } else {
11113 printf("?Can't get current directory\n");
11114 cmarg2 = "";
11115 f_tmpdir = 0;
11116 x = -9;
11117 goto xgetx;
11118 }
11119 #ifdef CK_MKDIR
11120 x = zchki(cmarg2); /* Does as-name exist? */
11121 if (x == -1) { /* Doesn't exist */
11122 char * p = NULL; /* Try to create it */
11123 x = strlen(cmarg2);
11124 if ((p = (char *)malloc(x+4))) {
11125 sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */
11126 x = zmkdir(p);
11127 free(p);
11128 if (x < 0) {
11129 printf("?Can't create %s\n",cmarg2);
11130 x = -9;
11131 goto xgetx;
11132 }
11133 }
11134 }
11135 #endif /* CK_MKDIR */
11136 if (!zchdir(cmarg2)) { /* change to given disk/directory, */
11137 printf("?Can't access %s\n",cmarg2);
11138 x = -9;
11139 goto xgetx;
11140 }
11141 cmarg2 = "";
11142 }
11143 }
11144 #endif /* CK_TMPDIR */
11145
11146 ckstrncpy(fspec,cmarg,CKMAXPATH); /* Note - this is a REMOTE filespec */
11147 debug(F111,"xget fspec",fspec,fspeclen);
11148 debug(F110,"xget cmarg2",cmarg2,0);
11149
11150 xgetx:
11151 for (i = 0; i < SND_MAX; i++)
11152 if (pv[i].sval)
11153 free(pv[i].sval);
11154 return(x);
11155 }
11156 #endif /* NOXFER */
11157
11158 #ifndef NOSPL
11159
11160 /*
11161 D O G T A -- Do _GETARGS or _PUTARGS Command.
11162
11163 Used by IF, FOR, WHILE, and SWITCH, each of which are implemented as
11164 2-level macros; the first level defines the macro, the second runs it.
11165 This routine hides the fact that they are macros by importing the
11166 macro arguments (if any) from two levels up, to make them available
11167 in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
11168 loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
11169 _PUTARGS is in case we changed any of these variables or used SHIFT
11170 on them, so the new values won't be lost as we pop up the stack.
11171 */
11172 int
dogta(cx)11173 dogta(cx) int cx; {
11174 int i, n;
11175 char c, *p, mbuf[4];
11176 extern int topargc, cmdint;
11177 extern char ** topxarg;
11178
11179 debug(F100,"GETARGS: dogta entry cx","",cx);
11180 if ((y = cmcfm()) < 0)
11181 return(y);
11182 debug(F101," dogta maclvl","",maclvl);
11183 if (cx == XXGTA) {
11184 debug(F101," dogta _GETARGS maclvl","",maclvl);
11185 } else if (cx == XXPTA) {
11186 debug(F101," dogta _PUTARGS maclvl","",maclvl);
11187 } else {
11188 return(-2);
11189 }
11190 if (maclvl < 1)
11191 return(success = 0);
11192
11193 /* Make new copies of macro arguments /%0..9 */
11194
11195 mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
11196
11197 if (cx == XXPTA) { /* Go NOINT because _PUTARGS */
11198 if (cmdint) /* temporarily changes maclvl. */
11199 connoi(); /* Interrupts OFF. */
11200 }
11201 for (i = 0; i < 10; i++) { /* For all args */
11202 c = (char) (i + '0'); /* Make name */
11203 mbuf[1] = (char) c; /* Insert digit */
11204 if (cx == XXGTA) { /* Get arg from level-minus-2 */
11205 if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
11206 else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
11207 debug(F111," dogta _GETARGS m_arg addmac var i",mbuf,i);
11208 debug(F111," dogta _GETARGS m_arg addmac def i",p,i);
11209 addmac(mbuf,p);
11210 #ifdef COMMENT
11211 if (maclvl > 1)
11212 makestr(&(m_line[maclvl]),m_line[maclvl-2]);
11213 #endif /* COMMENT */
11214 } else if (cx == XXPTA) { /* Put args level+2 */
11215 maclvl -= 2; /* This is gross, it's because we're */
11216 addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */
11217 maclvl += 2; /* and addmac() uses maclvl. */
11218 count[cmdlvl - 2] = count[cmdlvl];
11219 intime[cmdlvl - 2] = intime[cmdlvl];
11220 inpcas[cmdlvl - 2] = inpcas[cmdlvl];
11221 takerr[cmdlvl - 2] = takerr[cmdlvl];
11222 merror[cmdlvl - 2] = merror[cmdlvl];
11223 xquiet[cmdlvl - 2] = xquiet[cmdlvl];
11224 xvarev[cmdlvl - 2] = xvarev[cmdlvl];
11225 } else return(success = 0); /* Bad call to this routine */
11226 }
11227 if (cx == XXPTA) { /* Restore interrupts if we */
11228 if (cmdint) /* turned them off above. */
11229 conint(trap,stptrap);
11230 }
11231 /* Now take care of the argument vector array \&_[], \v(return), */
11232 /* and \v(argc) by just copying the pointers. */
11233
11234 if (cx == XXGTA) { /* GETARGS from 2 levels up */
11235 debug(F101," dogta _GETARGS m_xarg maclvl","",maclvl);
11236 if (maclvl == 1) {
11237 debug(F100," dogta _GETARGS m_xarg top level","",0);
11238 a_ptr[0] = topxarg; /* \&_[] array */
11239 a_dim[0] = topargc - 1; /* Dimension doesn't include [0] */
11240 m_xarg[maclvl] = topxarg;
11241 n_xarg[maclvl] = topargc; /* But \v(argc) does include \%0 */
11242 macargc[maclvl] = topargc;
11243 makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
11244 } else {
11245 debug(F100," dogta _GETARGS m_xarg in macro","",0);
11246 a_ptr[0] = m_xarg[maclvl-2];
11247 a_dim[0] = n_xarg[maclvl-2];
11248 m_xarg[maclvl] = m_xarg[maclvl-2];
11249 n_xarg[maclvl] = n_xarg[maclvl-2];
11250 macargc[maclvl] = n_xarg[maclvl-2];
11251 makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
11252 }
11253 } else { /* PUTARGS 2 levels up */
11254 if (maclvl > 1) {
11255 a_ptr[0] = m_xarg[maclvl];
11256 m_xarg[maclvl-2] = m_xarg[maclvl];
11257 a_dim[0] = n_xarg[maclvl];
11258 n_xarg[maclvl-2] = n_xarg[maclvl];
11259 macargc[maclvl-2] = n_xarg[maclvl];
11260 }
11261 }
11262 return(1); /* Internal command - don't change success */
11263 }
11264 #endif /* NOSPL */
11265
11266 #ifndef NOSPL
11267 /*
11268 Do the GOTO and [_]FORWARD commands.
11269 s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
11270 */
11271
11272 int
dogoto(s,cx)11273 dogoto(s, cx) char *s; int cx; {
11274 int i, j, x, y, z, bc;
11275 int empty = 0, stopflg = 0;
11276 char * cmd; /* Name of this command */
11277 char tmplbl[LBLSIZ+1], *lp; /* Current label from command stream */
11278 char tmp2[LBLSIZ+1]; /* SWITCH label conversion buffer */
11279 char tmp3[LBLSIZ+1]; /* Target label */
11280
11281 stopflg = (cx == XXXFWD); /* _FORWARD (used in SWITCH) */
11282 bc = 0; /* Brace counter */
11283
11284 cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
11285 if (!s) s = "";
11286 if (!*s) empty = 1;
11287
11288 #ifdef DEBUG
11289 if (deblog) {
11290 debug(F111,"GOTO command",cmd,cx);
11291 debug(F101,"GOTO cmdlvl","",cmdlvl);
11292 debug(F101,"GOTO maclvl","",maclvl);
11293 debug(F101,"GOTO tlevel","",tlevel);
11294 debug(F111,"GOTO target",s,empty);
11295 }
11296 #endif /* DEBUG */
11297 debug(F110,cmd,s,0);
11298 x = ckstrncpy(tmp3+1,s,LBLSIZ);
11299 debug(F101,"GOTO target len","",x);
11300 debug(F101,"GOTO target at x","",s[x]);
11301 if (s[x]) {
11302 debug(F100,"GOTO target overflow","",0);
11303 printf("?GOTO target or SWITCH case label too long\n");
11304 if (stopflg) dostop(); /* If in SWITCH return to prompt */
11305 return(success = 0);
11306 }
11307 s = tmp3+1;
11308 if (*s != ':') { /* Make copy of label */
11309 tmp3[0] = ':'; /* guaranteed to start with ":" */
11310 s--;
11311 }
11312 if (!stopflg && !empty) {
11313 if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
11314 printf("?Bad label syntax - '%s'\n",s);
11315 if (stopflg) dostop(); /* If in SWITCH return to prompt */
11316 return(success = 0);
11317 }
11318 }
11319 if (cmdlvl == 0) {
11320 printf("?Sorry, %s only works in a command file or macro\n",cmd);
11321 return(success = 0);
11322 }
11323 y = strlen(s); /* y = length of target label */
11324 debug(F111,cmd,s,y);
11325
11326 while (cmdlvl > 0) { /* As long as not at top level... */
11327 if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
11328 int i, m, flag;
11329 char *xp, *tp;
11330
11331 /* GOTO: rewind the macro; FORWARD: start at current position */
11332
11333 lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
11334 m = (int)strlen(lp);
11335 debug(F111,"GOTO in macro",lp,m);
11336
11337 flag = 1; /* flag for valid label position */
11338 for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
11339 if (*lp == '{') /* But only at this level */
11340 bc++; /* Anything inside braces is off */
11341 else if (*lp == '}') /* limits. */
11342 bc--;
11343 if (stopflg && bc > 0) /* This is good for SWITCH */
11344 continue; /* but interferes with WHILE, etc. */
11345 if (*lp == ',') {
11346 flag = 1;
11347 continue;
11348 }
11349 if (flag) { /* If in valid label position */
11350 if (*lp == SP) /* eat leading spaces */
11351 continue;
11352 if (*lp != ':') { /* Look for label introducer */
11353 flag = 0; /* this isn't it */
11354 continue; /* keep looking */
11355 }
11356 }
11357 if (!flag) /* We don't have a label */
11358 continue; /* so keep looking... */
11359 xp = lp; tp = tmplbl; /* Copy the label from the macro */
11360 j = 0; /* to make it null-terminated */
11361 while ((*tp = *xp)) {
11362 if (j++ > LBLSIZ-1) { /* j = length of word from macro */
11363 printf("?GOTO target or SWITCH case label too long\n");
11364 if (stopflg) dostop(); /* Return to prompt */
11365 return(success = 0);
11366 }
11367 if (!*tp || *tp == ',') /* Look for end of word */
11368 break;
11369 else tp++, xp++; /* Next character */
11370 }
11371 *tp = NUL; /* In case we stopped early */
11372 /* Now do caseless string comparison, using longest length */
11373 debug(F111,"macro GOTO label",s,y);
11374 debug(F111,"macro target label",tmplbl,j);
11375 if (stopflg) { /* Allow variables as SWITCH labels */
11376 int n = LBLSIZ - 1;
11377 char * p = tmp2;
11378 zzstring(tmplbl,&p,&n);
11379 if (n < 0) {
11380 printf("?GOTO target or SWITCH case label too long\n");
11381 if (stopflg) dostop(); /* Return to prompt */
11382 return(0);
11383 }
11384 ckstrncpy(tmplbl,tmp2,LBLSIZ);
11385 }
11386 debug(F111,"GOTO s",s,y);
11387 debug(F111,"GOTO tmplbl",tmplbl,j);
11388 debug(F111,"GOTO empty",ckitoa(stopflg),empty);
11389
11390 if (empty) { /* Empty target */
11391 z = (!strcmp(s,":") && /* String is empty */
11392 /* and Label is ":" or ":*"... */
11393 (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*")))
11394 ? 0 : 1;
11395 debug(F111,"GOTO","A",z);
11396 } else if (stopflg) {
11397 z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
11398 debug(F111,"GOTO","B",z);
11399 } else {
11400 z = (stopflg && inpcas[cmdlvl]) ?
11401 strcmp(s,tmplbl) :
11402 ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
11403 debug(F111,"GOTO","C",z);
11404 }
11405 if (!z) {
11406 break;
11407 } else if (stopflg &&
11408 !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) {
11409 debug(F100,"GOTO DEFAULT","",0);
11410 break;
11411 } else {
11412 flag = 0;
11413 }
11414 }
11415 debug(F111,"GOTO macro i",cmd,i);
11416 debug(F111,"GOTO macro m",cmd,m);
11417 if (i >= m) { /* Didn't find the label */
11418 debug(F101,"GOTO failed cmdlvl","",cmdlvl);
11419 #ifdef COMMENT
11420 /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */
11421 if (stopflg)
11422 return(0);
11423 #endif /* COMMENT */
11424 if ((maclvl > 0) &&
11425 (m_arg[maclvl-1][0]) &&
11426 (cmdstk[cmdlvl].src == CMD_MD) &&
11427 (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
11428 !strncmp(m_arg[maclvl-1][0],"_for",4) ||
11429 !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
11430 !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
11431 dogta(XXPTA); /* Restore args */
11432 debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
11433 popclvl(); /* Pop an extra level */
11434 }
11435 debug(F101,"GOTO popping","",cmdlvl);
11436 if (!popclvl()) { /* pop up to next higher level */
11437 printf("?Label '%s' not found\n",s); /* if none */
11438 return(0); /* Quit */
11439 } else if (stopflg) { /* SWITCH no case label match */
11440 return(0); /* and no DEFAULT lable. */
11441 } else {
11442 continue; /* otherwise look again */
11443 }
11444 }
11445 debug(F110,"GOTO found macro label",tmplbl,0);
11446 macp[maclvl] = lp; /* set macro buffer pointer */
11447 return(1);
11448 } else if (cmdstk[cmdlvl].src == CMD_TF) {
11449 x = 0; /* GOTO issued in take file */
11450 debug(F111,"GOTO in TAKE file",cmd,cx);
11451 if (cx == XXGOTO) { /* If GOTO, but not FORWARD, */
11452 rewind(tfile[tlevel]); /* search file from beginning */
11453 tfline[tlevel] = 0;
11454 }
11455 while (! feof(tfile[tlevel])) {
11456 #ifdef COMMENT
11457 /* This is wrong - it lets us jump to labels inside inferior blocks */
11458 tfline[tlevel]++;
11459 if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
11460 #else
11461 if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0)
11462 #endif /* COMMENT */
11463 break; /* If no more, done, label not found */
11464 lp = line; /* Got line */
11465 while (*lp == SP || *lp == HT)
11466 lp++; /* Strip leading whitespace */
11467 if (*lp != ':') continue; /* Check for label introducer */
11468 while (*(lp+1) == SP) { /* Remove space between : and name */
11469 *(lp+1) = ':';
11470 lp++; /* Strip leading whitespace */
11471 }
11472 tp = lp; /* Get end of word */
11473 j = 0;
11474 while (*tp) { /* And null-terminate it */
11475 if (*tp < 33) {
11476 *tp = NUL;
11477 break;
11478 } else tp++, j++;
11479 }
11480 if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
11481 x = 1; /* Got it */
11482 break; /* done. */
11483 } else if (stopflg &&
11484 !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
11485 x = 1;
11486 break;
11487 }
11488 }
11489 if (x == 0) { /* If not found, print message */
11490 debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
11491 if (stopflg)
11492 return(0);
11493 if (!popclvl()) { /* pop up to next higher level */
11494 printf("?Label '%s' not found\n",s); /* if none */
11495 return(0); /* quit */
11496 } else continue; /* otherwise look again */
11497 }
11498 return(x); /* Send back return code */
11499 }
11500 }
11501 printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
11502 return(0);
11503 }
11504 #endif /* NOSPL */
11505
11506 /* Finish parsing and do the IF, XIF, and WHILE commands */
11507
11508 #ifndef NOSPL
11509
11510 /* C H K V A R -- Check (if it's a) Variable */
11511
11512
11513 #ifdef OLDCHKVAR
11514 /*
11515 Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
11516 have backslashes in them. How do we know if a backslash in a filename is a
11517 directory separator, or if it's a Kermit backslash? This routine does a
11518 rough syntax check of the next few characters and if it looks like it MIGHT
11519 be a variable, then it tries to evaluate it, and if the result is not empty,
11520 we say it's a variable, although sometimes it might not be -- some cases are
11521 truly ambiguous. For example there might a DOS directory called \%a, and
11522 we also have a variable with the same name. This is all for the sake of not
11523 having to tell PC users that they have to double all backslashes in file
11524 and directory names.
11525 */
11526 #else
11527 /*
11528 Somewhat less crude & disgusting. The previous method was nondeterministic
11529 and (worse) it interfered with macro argument passing. So now we only
11530 check the syntax of backslash-items to see if they are variables, but we
11531 do NOT check their values.
11532 */
11533 #endif /* OLDCHKVAR */
11534 /*
11535 Call with a string pointer pointing at the backslash of the purported
11536 variable. Returns 1 if it has the syntax of a variable, 0 if not.
11537 */
11538 int
chkvar(s)11539 chkvar(s) char *s; {
11540 int z = 0; /* Return code - assume failure. */
11541 if (!s) s = ""; /* Watch our for null pointers. */
11542 if (!*s) return(0); /* Empty arg so not a variable. */
11543 if (*s == CMDQ) { /* Object begins with backslash. */
11544 char c;
11545 c = s[1]; /* Character following backslash. */
11546 if (c) {
11547 int t = 0;
11548 if (c == CMDQ) /* Quoted backslash */
11549 return(1);
11550 c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
11551 if (c == '%') { /* Simple variable */
11552 #ifdef OLDCHKVAR
11553 t = 1;
11554 #else
11555 return(1);
11556 #endif /* OLDCHKVAR */
11557 } else if (c == '&') { /* Array */
11558 if (!s[2]) return(0);
11559 if (s[3] == '[')
11560 t = ckindex("]",s,4,0,1);
11561 #ifndef OLDCHKVAR
11562 return((t > 0) ? 1 : 0);
11563 #endif /* OLDCHKVAR */
11564 } else if (c == '$' || /* Environment variable */
11565 c == 'V' || /* Built-in variable */
11566 c == 'M') { /* Macro name */
11567 t = (s[2] == '(');
11568 #ifndef OLDCHKVAR
11569 return((t > 0) ? 1 : 0);
11570 #endif /* OLDCHKVAR */
11571 } else if (c == 'F') { /* Function reference */
11572 /* Don't actually call it - it might have side effects */
11573 int x;
11574 if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */
11575 if ((x = ckindex(")",s,x,0,1)))
11576 z = 1;
11577 /* Insert a better syntax check here if necessary */
11578 }
11579 #ifdef OLDCHKVAR
11580 if (t) {
11581 t = 255; /* This lets us test \v(xxx) */
11582 lp = line; /* and even \f...(xxx) */
11583 zzstring(s,&lp,&t); /* Evaluate it, whatever it is. */
11584 t = strlen(line); /* Get its length. */
11585 debug(F111,"chkvar",line,t);
11586 z = t > 0; /* If length > 0, it's defined */
11587 }
11588 #endif /* OLDCHKVAR */
11589 }
11590 }
11591 return(z);
11592 }
11593
11594 /* B O O L E X P -- Evaluate a Boolean expression */
11595
11596 #define BOOLLEN 1024
11597 static char boolval[BOOLLEN];
11598
11599 int
boolexp(cx)11600 boolexp(cx) int cx; {
11601 int x, y, z; char *s, *p;
11602 int parens = 0, pcount = 0, ecount = 0;
11603 char *q, *bx;
11604 struct FDB kw, nu;
11605 #ifdef FNFLOAT
11606 struct FDB fl;
11607 CKFLOAT f1 = 0.0, f2 = 0.0;
11608 int f1flag = 0, f2flag = 0;
11609 #endif /* FNFLOAT */
11610 #ifdef OS2
11611 extern int keymac;
11612 #endif /* OS2 */
11613 char varnam[VNAML+1];
11614
11615 not = 0; /* Flag for whether "NOT" was seen */
11616 z = 0; /* Initial IF condition */
11617 ifargs = 0; /* Count of IF condition words */
11618 bx = boolval; /* Initialize boolean value */
11619 *bx = NUL;
11620
11621 ifagain:
11622 cmfdbi(&kw, /* First FDB - command switches */
11623 _CMKEY, /* fcode */
11624 "Number, numeric-valued variable, Boolean expression, or keyword",
11625 "", /* default */
11626 "", /* addtl string data */
11627 nif, /* addtl numeric data 1: tbl size */
11628 0, /* addtl numeric data 2: 4 = silent */
11629 xxstring, /* Processing function */
11630 iftab, /* Keyword table */
11631 &nu /* Pointer to next FDB */
11632 );
11633 cmfdbi(&nu, /* 2nd FDB - An integer */
11634 _CMNUM, /* fcode */
11635 "", /* hlpmsg */
11636 "", /* Default */
11637 "", /* addtl string data */
11638 0,
11639 0,
11640 xxstring,
11641 NULL,
11642 #ifdef FNFLOAT
11643 &fl
11644 #else
11645 NULL
11646 #endif /* FNFLOAT */
11647 );
11648 #ifdef FNFLOAT
11649 cmfdbi(&fl, /* A floating-point number */
11650 _CMFLD, /* fcode */
11651 "", /* hlpmsg */
11652 "", /* default */
11653 "", /* addtl string data */
11654 0, /* addtl numeric data 1 */
11655 0, /* addtl numeric data 2 */
11656 xxstring,
11657 NULL,
11658 NULL
11659 );
11660 #endif /* FNFLOAT */
11661 x = cmfdb(&kw); /* Parse a keyword or a number */
11662 debug(F111,"boolval cmfdb","",x);
11663 if (x < 0) {
11664 if (x == -3)
11665 x = -2;
11666 return(x);
11667 }
11668 debug(F111,"boolval switch","",cmresult.fcode);
11669 switch (cmresult.fcode) { /* What did we get? */
11670 case _CMFLD: { /* A "field" */
11671 int i;
11672 char * s;
11673 s = cmresult.sresult;
11674
11675 /* fdc 2013/12/06 - Remember the variable name for error messages */
11676 varnam[0] = NUL;
11677 i = ckindex("if ",cmdbuf,0,0,0);
11678 if (i) {
11679 i += 2;
11680 while (cmdbuf[i] == ' ') i++;
11681 if (cmdbuf[i]) {
11682 int j, k;
11683 j = i;
11684 k = 0;
11685 while (cmdbuf[j] && (cmdbuf[j] != ' ')) {
11686 varnam[k++] = cmdbuf[j++];
11687 }
11688 varnam[k] = NUL;
11689 }
11690 }
11691 /*
11692 C-Kermit 9.0: This allows a macro name to serve as an
11693 IF condition without having to enclose it in \m(...).
11694 */
11695 if (
11696 #ifdef FNFLOAT
11697 !isfloat(cmresult.sresult,0) /* Not a number */
11698 #else
11699 !chknum(cmresult.sresult) /* Not a number */
11700 #endif /* FNFLOAT */
11701 ) {
11702 i = mlook(mactab,cmresult.sresult,nmac); /* Look it up */
11703 if (i > -1) /* in the macro table */
11704 s = mactab[x].mval; /* and get its value */
11705 else /* Otherwise if no such macro */
11706 #ifdef COMMENT
11707 s = "0"; /* evaluate as FALSE (bad idea) */
11708 #else
11709 {
11710 if (varnam[0])
11711 printf("?Variable %s does not have a numeric value\n",
11712 varnam);
11713 else
11714 printf("?Not an IF condition, macro name or number: %s\n",
11715 cmresult.sresult);
11716 return(-9);
11717 }
11718 #endif /* COMMENT */
11719 }
11720 #ifdef FNFLOAT
11721 if (isfloat(s,0)) { /* A floating-point number? */
11722 f1 = floatval; /* Yes, get its value */
11723 f1flag = 1; /* remember we did this */
11724 ifc = 9999; /* Set special "if-code" */
11725 }
11726 #else
11727 if (chknum(s)) {
11728 cmresult.nresult = atoi(s);
11729 ifc = 9999;
11730 break;
11731 }
11732 #endif /* FNFLOAT */
11733 else
11734 return(-2);
11735 }
11736 case _CMNUM: /* A number... */
11737 ifc = 9999; /* Set special "if-code" */
11738 break;
11739 case _CMKEY: /* A keyword */
11740 ifc = cmresult.nresult; /* Get if-code */
11741 break;
11742 default:
11743 return(-2);
11744 }
11745 switch (ifc) { /* set z = 1 for true, 0 for false */
11746 case 9999: /* Number */
11747 #ifdef FNFLOAT
11748 if (f1flag) {
11749 z = (f1 == 0.0) ? 0 : 1;
11750 } else
11751 #endif /* FNFLOAT */
11752 z = (cmresult.nresult == 0) ? 0 : 1;
11753 break;
11754 case XXIFLP: /* Left paren */
11755 if (pcount == 0 && ifargs > 0)
11756 return(-2);
11757 parens = 1;
11758 pcount++;
11759 ifargs++;
11760 *bx++ = '(';
11761 goto ifagain;
11762 case XXIFRP: /* Right paren */
11763 if (!parens)
11764 return(-2);
11765 if (--pcount < 0)
11766 return(-2);
11767 ifargs++;
11768 *bx++ = ')';
11769 *bx = NUL;
11770 if (pcount == 0)
11771 goto ifend;
11772 goto ifagain;
11773 case XXIFAN: /* AND (&&) */
11774 ifargs++;
11775 if (!ecount)
11776 return(-2);
11777 *bx++ = '&';
11778 goto ifagain;
11779 case XXIFOR: /* OR (||) */
11780 ifargs++;
11781 if (!ecount)
11782 return(-2);
11783 *bx++ = '|';
11784 goto ifagain;
11785 case XXIFNO: /* IF NOT [ NOT [ NOT ... ] ] */
11786 if (bx > boolval) { /* evala() doesn't like cascaded */
11787 if (*(bx-1) == '!') { /* unary operators... */
11788 *(bx-1) = NUL; /* So here, two wrongs make a right. */
11789 bx--;
11790 } else {
11791 *bx++ = '!';
11792 }
11793 } else {
11794 *bx++ = '!';
11795 }
11796 ifargs++;
11797 goto ifagain;
11798 case XXIFTR: /* IF TRUE */
11799 z = 1;
11800 debug(F101,"if true","",z);
11801 ifargs += 1;
11802 break;
11803 case XXIFNT: /* IF FALSE */
11804 z = 0;
11805 debug(F101,"if true","",z);
11806 ifargs += 1;
11807 break;
11808 case XXIFSU: /* IF SUCCESS */
11809 z = ( success != 0 ) ? 1 : 0;
11810 debug(F101,"if success","",z);
11811 ifargs += 1;
11812 break;
11813 case XXIFFA: /* IF FAILURE */
11814 z = ( success == 0 ) ? 1 : 0;
11815 debug(F101,"if failure","",z);
11816 ifargs += 1;
11817 break;
11818
11819 case XXIFDE: /* IF DEFINED */
11820 if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
11821 return((x == -3) ? -2 : x);
11822
11823 if (*s == CMDQ) {
11824 char * lp;
11825 char line[256];
11826 int t, x;
11827 if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */
11828 extern struct keytab fnctab[];
11829 extern int nfuncs;
11830 ckstrncpy(line,s+2,256);
11831 if (line[0]) {
11832 lp = ckstrchr(line,'(');
11833 if (lp) *lp = NUL;
11834 x = lookup(fnctab,line,nfuncs,&t);
11835 z = x > -1;
11836 }
11837 debug(F111,"if defined function",line,z);
11838 } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */
11839 extern struct keytab vartab[];
11840 extern int nvars;
11841 z = 0;
11842 if (*(s+2) == '(') {
11843 ckstrncpy(line,s+3,256);
11844 if (line[0]) {
11845 lp = ckstrchr(line,')');
11846 if (lp) *lp = NUL;
11847 x = lookup(vartab,line,nvars,&t);
11848 z = x > -1;
11849 if (z) { /* 8.0.203 */
11850 int t; /* It must have a value to succeed */
11851 t = 255; /* as in C-Kermit 6.0 and 7.0 */
11852 lp = line; /* (this was broken in 8.0.200-201) */
11853 zzstring(s,&lp,&t);
11854 t = strlen(line);
11855 z = line[0] ? 1 : 0;
11856 }
11857 }
11858 }
11859 debug(F111,"if defined variable",line,z);
11860 } else {
11861 z = chkvar(s); /* Starts with backslash */
11862 if (z > 0) { /* Yes... */
11863 t = 255; /* than buffer so if zzstring fails */
11864 lp = line; /* check for that -- overflow means */
11865 line[0] = NUL; /* the quantity is defined. */
11866 x = zzstring(s,&lp,&t);
11867 if ((x < 0 && t != 255) || !line[0])
11868 z = 0;
11869 debug(F111,"if defined zzstring",line,z);
11870 debug(F101,"if defined zzstring t","",t);
11871 }
11872 }
11873 } else {
11874 z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
11875 }
11876 debug(F111,"if defined final",s,z);
11877 ifargs += 2;
11878 break;
11879
11880 case XXIFDC: { /* IF DECLARED */
11881 char * lp;
11882 char line[32];
11883 int j, k, t, x;
11884 if ((x = cmfld("Array name","",&s,NULL)) < 0)
11885 return((x == -3) ? -2 : x);
11886 if (*s == CMDQ) {
11887 if (*(s+1) != '&') {
11888 t = 31;
11889 lp = line;
11890 line[0] = NUL;
11891 x = zzstring(s,&lp,&t);
11892 s = line;
11893 }
11894 }
11895 z = 0;
11896 if ((x = arraybounds(s,&j,&k)) > -1) {
11897 if (a_ptr[x]) {
11898 if (j < 1)
11899 z = 1;
11900 else if (j <= a_dim[x])
11901 z = 1;
11902 if (z == 1 && k > a_dim[x])
11903 z = 0;
11904 }
11905 }
11906 break;
11907 }
11908 case XXIFBG: /* IF BACKGROUND */
11909 case XXIFFG: /* IF FOREGROUND */
11910 bgchk(); /* Check background status */
11911 if (ifc == XXIFFG) /* Foreground */
11912 z = pflag ? 1 : 0;
11913 else z = pflag ? 0 : 1; /* Background */
11914 ifargs += 1;
11915 break;
11916
11917 case XXIFCO: /* IF COUNT */
11918 z = ( --count[cmdlvl] > 0 );
11919 if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
11920 debug(F101,"if count","",z);
11921 ifargs += 1;
11922 break;
11923
11924 case XXIFEX: /* IF EXIST */
11925 #ifdef CK_TMPDIR
11926 case XXIFDI: /* IF DIRECTORY */
11927 #endif /* CK_TMPDIR */
11928 case XXIFAB: /* IF ABSOLUTE */
11929 case XXIFLN: /* IF LINK */
11930 if ((x = cmfld(
11931 ((ifc == XXIFDI) ? "Directory name" : "File"),
11932 "",&s,
11933 #ifdef OS2
11934 NULL /* This allows \'s in filenames */
11935 #else
11936 xxstring
11937 #endif /* OS2 */
11938 )) < 0) {
11939 if (x == -3) {
11940 extern int cmflgs;
11941 if (cmflgs == 1) {
11942 printf("?File or directory name required\n");
11943 return(-9);
11944 }
11945 } else return(x);
11946 }
11947 s = brstrip(s);
11948 #ifdef UNIX
11949 if (ifc == XXIFLN) {
11950 z = isalink(s);
11951 } else
11952 #endif /* UNIX */
11953 if (ifc == XXIFAB) {
11954 z = isabsolute(s);
11955 } else if (ifc == XXIFEX) {
11956 z = (zgetfs(s) > -1L);
11957 debug(F101,"if exist 1","",z);
11958 #ifdef OS2
11959 if (!z) { /* File not found. */
11960 int t; /* Try expanding variables */
11961 t = LINBUFSIZ-1; /* and looking again. */
11962 lp = line;
11963 zzstring(s,&lp,&t);
11964 s = line;
11965 z = ( zchki(s) > -1L );
11966 debug(F101,"if exist 2","",z);
11967 }
11968 #endif /* OS2 */
11969 #ifdef CK_TMPDIR
11970 } else {
11971 #ifdef VMS
11972 z = (zchki(s) == -2)
11973 #else
11974 /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
11975 z = isdir(s)
11976 #ifdef OS2
11977 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
11978 #endif /* OS2 */
11979 #endif /* VMS */
11980 ;
11981 debug(F101,"if directory 1","",z);
11982
11983 if (!z) { /* File not found. */
11984 int t; /* Try expanding variables */
11985 t = LINBUFSIZ-1; /* and looking again. */
11986 lp = line;
11987 zzstring(s,&lp,&t);
11988 s = line;
11989 z = isdir(s)
11990 #ifdef OS2
11991 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
11992 #endif /* OS2 */
11993 ;
11994 debug(F101,"if directory 2","",z);
11995 }
11996 #endif /* CK_TMPDIR */
11997 }
11998 ifargs += 2;
11999 break;
12000
12001 case XXIFEQ: /* IF EQUAL (string comparison) */
12002 case XXIFLL: /* IF Lexically Less Than */
12003 case XXIFLLE: /* IF Lexically Less Than or Equal */
12004 case XXIFLG: /* If Lexically Greater Than */
12005 case XXIFLGE: /* If Lexically Greater Than or Equal*/
12006 case XXIFNN: /* If Lexically No Equal */
12007 if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
12008 if (x == -3) {
12009 printf("?Text required\n");
12010 return(-9);
12011 } else return(x);
12012 }
12013 s = brstrip(s); /* Strip braces */
12014 x = (int)strlen(s);
12015 if (x > LINBUFSIZ-1) {
12016 printf("?IF: strings too long\n");
12017 return(-2);
12018 }
12019 lp = line; /* lp points to first string */
12020 ckstrncpy(line,s,LINBUFSIZ);
12021 if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
12022 if (y == -3) {
12023 printf("?Text required\n");
12024 return(-9);
12025 } else return(y);
12026 }
12027 s = brstrip(s);
12028 y = (int)strlen(s);
12029 if (x + y + 2 > LINBUFSIZ) {
12030 printf("?IF: strings too long\n");
12031 return(-2);
12032 }
12033 #ifdef COMMENT
12034 tp = lp + x + 2; /* tp points to second string */
12035 strncpy(tp,s,LINBUFSIZ-x-3);
12036 #else
12037 tp = s;
12038 #endif /* COMMENT */
12039 lexical:
12040 x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
12041 switch (ifc) {
12042 case XXIFEQ: /* EQUAL (string comparison) */
12043 z = (x == 0);
12044 break;
12045 case XXIFLL: /* Lexically Less Than */
12046 z = (x < 0);
12047 break;
12048 case XXIFLLE: /* Lexically Less Than or Equal */
12049 z = (x <= 0);
12050 break;
12051 case XXIFLG: /* Lexically Greater Than */
12052 z = (x > 0);
12053 break;
12054 case XXIFLGE: /* Lexically Greater Than or Equal */
12055 z = (x >= 0);
12056 break;
12057 case XXIFNN: /* Lexically Not Equal */
12058 z = (x != 0);
12059 break;
12060 }
12061 debug(F101,"IF EQ result","",z);
12062 ifargs += 3;
12063 break;
12064
12065 case XXIFVE: /* IF VERSION */
12066 case XXIFAE: /* IF (arithmetically) = */
12067 case XXIFNQ: /* IF != (not arithmetically equal) */
12068 case XXIFLT: /* IF < */
12069 case XXIFLE: /* IF <= */
12070 case XXIFGE: /* IF >= */
12071 case XXIFGT: { /* IF > */
12072 /* July 2006 - converted to use CK_OFF_T rather than int to */
12073 /* allow long integers on platforms that have ck_off_t > 32 bits */
12074 int xx;
12075 CK_OFF_T n1 = (CK_OFF_T)0, n2 = (CK_OFF_T)0;
12076 if (ifc == XXIFVE) {
12077 n1 = (CK_OFF_T) vernum;
12078 } else {
12079 x = cmfld("first number or variable name","",&s,xxstring);
12080 if (x == -3) {
12081 printf("?Quantity required\n");
12082 return(-9);
12083 }
12084 if (x < 0) return(x);
12085 debug(F101,"xxifgt cmfld","",x);
12086 ckstrncpy(line,s,LINBUFSIZ);
12087 lp = brstrip(line);
12088 debug(F110,"xxifgt exp1",lp,0);
12089
12090 /* The following bit is for compatibility with old versions of MS-DOS Kermit */
12091
12092 if (!ckstrcmp(lp,"count",5,0)) {
12093 n1 = (CK_OFF_T)count[cmdlvl];
12094 } else if (!ckstrcmp(lp,"version",7,0)) {
12095 n1 = (CK_OFF_T) vernum;
12096 } else if (!ckstrcmp(lp,"argc",4,0)) {
12097 n1 = (CK_OFF_T) macargc[maclvl];
12098 } else {
12099
12100 /* End of compatibility bit */
12101
12102 #ifdef FNFLOAT
12103 if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */
12104 f1 = floatval;
12105 f1flag = 1;
12106 } else
12107 #endif /* FNFLOAT */
12108 if (chknum(lp)) {
12109 n1 = ckatofs(lp);
12110 } else { /* Check for arithmetic expression */
12111 q = evala(lp); /* cmnum() does this but ... */
12112 if (chknum(q)) { /* we're not using cmnum(). */
12113 n1 = ckatofs(q);
12114 } else {
12115 printf("?Value not numeric - %s", lp);
12116 return(-9);
12117 }
12118 }
12119 }
12120 }
12121 y = cmfld("number or variable name","",&s,xxstring);
12122 if (y == -3) {
12123 printf("?Quantity required\n");
12124 return(-9);
12125 }
12126 if (y < 0) return(y);
12127 s = brstrip(s);
12128 if (!*s) return(-2);
12129 if (ifc == XXIFVE) {
12130 tp = line;
12131 } else {
12132 x = (int)strlen(lp);
12133 tp = line + x + 2;
12134 }
12135 ckstrncpy(tp,s,LINBUFSIZ-x-2);
12136 debug(F110,"xxifgt exp2",tp,0);
12137
12138 if (!ckstrcmp(tp,"count",5,0)) {
12139 n2 = (CK_OFF_T) count[cmdlvl];
12140 } else if (!ckstrcmp(tp,"version",7,0)) {
12141 n2 = (CK_OFF_T) vernum;
12142 } else if (!ckstrcmp(tp,"argc",4,0)) {
12143 n2 = (CK_OFF_T) macargc[maclvl];
12144 } else {
12145 #ifdef FNFLOAT
12146 if (isfloat(tp,0) > 1) {
12147 f2 = floatval;
12148 f2flag = 1;
12149 } else
12150 #endif /* FNFLOAT */
12151 if (chknum(tp)) {
12152 n2 = ckatofs(tp);
12153 } else {
12154 q = evala(tp);
12155 if (chknum(q)) { /* we're not using cmnum(). */
12156 n2 = ckatofs(q);
12157 } else {
12158 printf("?Value not numeric - %s", tp);
12159 return(-9);
12160 }
12161 }
12162 }
12163 xx = (ifc == XXIFVE) ? XXIFGE : ifc;
12164
12165 #ifdef FNFLOAT
12166 if (f1flag && !f2flag) {
12167 f2 = (CKFLOAT)n2;
12168 f2flag = 1;
12169 }
12170 if (f2flag && !f1flag)
12171 f1 = (CKFLOAT)n1;
12172 if (f1flag)
12173 z = ((f1 < f2 && xx == XXIFLT)
12174 || (f1 != f2 && xx == XXIFNQ)
12175 || (f1 <= f2 && xx == XXIFLE)
12176 || (f1 == f2 && xx == XXIFAE)
12177 || (f1 >= f2 && xx == XXIFGE)
12178 || (f1 > f2 && xx == XXIFGT));
12179 else
12180 #endif /* FNFLOAT */
12181 z = ((n1 < n2 && xx == XXIFLT)
12182 || (n1 != n2 && xx == XXIFNQ)
12183 || (n1 <= n2 && xx == XXIFLE)
12184 || (n1 == n2 && xx == XXIFAE)
12185 || (n1 >= n2 && xx == XXIFGE)
12186 || (n1 > n2 && xx == XXIFGT));
12187 debug(F101,"xxifge z","",z);
12188 if (ifc == XXIFVE)
12189 ifargs += 2;
12190 else
12191 ifargs += 3;
12192 break;
12193 }
12194
12195 case XXIFNU: /* IF NUMERIC */
12196 x = cmfld("variable name or constant","",&s,NULL);
12197 if (x == -3) {
12198 extern int cmflgs;
12199 if (cmflgs == 1) {
12200 printf("?Quantity required\n");
12201 return(-9);
12202 }
12203 } else if (x < 0)
12204 return(x);
12205 x = LINBUFSIZ-1;
12206 lp = line;
12207 zzstring(s,&lp,&x);
12208 lp = line;
12209 debug(F110,"xxifnu quantity",lp,0);
12210 z = chknum(lp);
12211 #ifdef COMMENT
12212 /*
12213 This works, but it's not wise -- IF NUMERIC is mostly used to see if a
12214 string really does contain only numeric characters. If they want to force
12215 evaluation, they can use \feval() on the argument string.
12216 */
12217 if (!z) { /* Not a number */
12218 x_ifnum = 1; /* Avoid "eval" error messages */
12219 q = evala(lp); /* Maybe it's an expression */
12220 z = chknum(q); /* that evaluates to a number */
12221 x_ifnum = 0; /* Put eval messages back to normal */
12222 if (z) debug(F110,"xxifnu exp",lp,0);
12223 }
12224 #endif /* COMMENT */
12225 debug(F101,"xxifnu chknum","",z);
12226 ifargs += 2;
12227 break;
12228
12229 #ifdef ZFCDAT
12230 case XXIFNE: { /* IF NEWER */
12231 char d1[20], * d2; /* Buffers for 2 dates */
12232 if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
12233 return(z);
12234 ckstrncpy(d1,zfcdat(s),20);
12235 if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
12236 return(z);
12237 d2 = zfcdat(s);
12238 if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
12239 printf("?Failure to get file date\n");
12240 return(-9);
12241 }
12242 debug(F110,"xxifnewer d1",d1,0);
12243 debug(F110,"xxifnewer d2",d2,0);
12244 z = (strcmp(d1,d2) > 0) ? 1 : 0;
12245 debug(F101,"xxifnewer","",z);
12246 ifargs += 2;
12247 break;
12248 }
12249 #endif /* ZFCDAT */
12250
12251 #ifdef CK_IFRO
12252 case XXIFRO: /* REMOTE-ONLY advisory */
12253 ifargs++;
12254 #ifdef NOLOCAL
12255 z = 1;
12256 #else
12257 z = remonly;
12258 #endif /* NOLOCAL */
12259 break;
12260 #endif /* CK_IFRO */
12261
12262 case XXIFAL: /* ALARM */
12263 ifargs++;
12264 debug(F101,"IF ALARM ck_alarm","",ck_alarm);
12265 debug(F110,"IF ALARM alrm_date",alrm_date,0);
12266 debug(F110,"IF ALARM alrm_time",alrm_time,0);
12267
12268 if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
12269 z = 0; /* ALARM not SET */
12270 break; /* so IF ALARM fails */
12271 }
12272 /* Get current date and time */
12273 ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ);
12274 s = tmpbuf;
12275 s[8] = NUL;
12276 z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
12277 debug(F101,"IF ALARM date z","",z);
12278 if (z == 0) { /* Dates are the same */
12279 /* Compare times */
12280 z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
12281 debug(F101,"IF ALARM time z","",z);
12282 }
12283 tmpbuf[0] = NUL; /* z >= 0 if alarm is passed */
12284 z = ((z >= 0) ? 1 : 0); /* z < 0 otherwise */
12285 debug(F101,"IF ALARM final z","",z);
12286 break;
12287
12288 case XXIFOP: /* IF OPEN */
12289 if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
12290 return(x);
12291 if (x == 9999 || x == ZSTDIO) {
12292 bgchk(); /* Check background status */
12293 z = pflag ? 1 : 0;
12294 } else if (x == 8888) {
12295 z = local ? ttchk() > -1 : 0;
12296 #ifdef CKLOGDIAL
12297 } else if (x == 7777) {
12298 extern int dialog;
12299 z = dialog ? 1 : 0;
12300 #endif /* CKLOGDIAL */
12301 } else
12302 z = (chkfn(x) > 0) ? 1 : 0;
12303 ifargs += 1;
12304 break;
12305
12306 case XXIFSD: /* Started-From-Dialer */
12307 #ifdef OS2
12308 z = StartedFromDialer;
12309 #else
12310 z = 0;
12311 #endif /* OS2 */
12312 break;
12313
12314 case XXIFTM: /* Terminal-Macro */
12315 #ifdef OS2
12316 z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
12317 #else
12318 z = 0;
12319 #endif /* OS2 */
12320 break;
12321
12322 case XXIFEM: /* Emulation is active */
12323 #ifdef OS2
12324 z = 1;
12325 #else
12326 z = 0;
12327 #endif /* OS2 */
12328 break;
12329
12330 case XXIFIK: /* Running as IKSD? */
12331 z = inserver;
12332 break;
12333
12334 case XXIFTA: /* Connection is TAPI */
12335 z = 0;
12336 #ifndef NODIAL
12337 #ifdef CK_TAPI
12338 if (local && !network && tttapi)
12339 z = 1;
12340 #endif /* CK_TAPI */
12341 #endif /* NODIAL */
12342 break;
12343
12344 case XXIFMA: /* IF MATCH */
12345 x = cmfld("String or variable","",&s,xxstring);
12346 if (x == -3) {
12347 extern int cmflgs;
12348 if (cmflgs == 1) {
12349 printf("?String required\n");
12350 return(-9);
12351 }
12352 } else if (x < 0)
12353 return(x);
12354 ckstrncpy(line,s,LINBUFSIZ);
12355 s = brstrip(line);
12356 debug(F110,"xxifma string",line,0);
12357 x = cmfld("Pattern","",&p,xxstring);
12358 if (x == -3) {
12359 extern int cmflgs;
12360 if (cmflgs == 1) {
12361 printf("?Pattern required\n");
12362 return(-9);
12363 }
12364 } else if (x < 0)
12365 return(x);
12366 ckstrncpy(tmpbuf,p,TMPBUFSIZ);
12367 p = brstrip(tmpbuf);
12368 debug(F110,"xxifma pattern",tmpbuf,0);
12369 z = ckmatch(p,s,inpcas[cmdlvl],1);
12370 break;
12371
12372 case XXIFFL: { /* IF FLAG */
12373 extern int ooflag;
12374 z = ooflag;
12375 break;
12376 }
12377 case XXIFAV: { /* IF AVAILABLE */
12378 if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
12379 return(x);
12380 switch (x) {
12381 case AV_KRB4:
12382 z = ck_krb4_is_installed();
12383 break;
12384 case AV_KRB5:
12385 z = ck_krb5_is_installed();
12386 break;
12387 case AV_SRP:
12388 z = ck_srp_is_installed();
12389 break;
12390 case AV_SSL:
12391 z = ck_ssleay_is_installed();
12392 break;
12393 case AV_NTLM:
12394 z = ck_ntlm_is_installed();
12395 break;
12396 case AV_CRYPTO:
12397 z = ck_crypt_is_installed();
12398 break;
12399 case AV_SSH:
12400 z = ck_ssh_is_installed();
12401 break;
12402 default:
12403 z = 0;
12404 }
12405 break;
12406 }
12407 case XXIFAT: /* IF ASKTIMEOUT */
12408 z = asktimedout;
12409 break;
12410
12411 case XXIFRD: /* IF READABLE */
12412 case XXIFWR: /* IF WRITEABLE */
12413 if ((x = cmfld("File or directory name",
12414 "",
12415 &s,
12416 #ifdef OS2
12417 NULL /* This allows \'s in filenames */
12418 #else
12419 xxstring
12420 #endif /* OS2 */
12421 )) < 0) {
12422 if (x == -3) {
12423 extern int cmflgs;
12424 if (cmflgs == 1) {
12425 printf("?File or directory name required\n");
12426 return(-9);
12427 }
12428 } else return(x);
12429 }
12430 s = brstrip(s);
12431 /*
12432 zchk[io]() do not do what we want here for directories, so we set
12433 a global flag telling it to behave specially in this case. Othewise
12434 we'd have to change the API and change all ck?fio.c modules accordingly.
12435 */
12436 y = 0; /* Try-again control */
12437 #ifdef OS2
12438 ifrdagain:
12439 #endif /* OS2 */
12440 if (ifc == XXIFRD) { /* IF READABLE */
12441 zchkid = 1;
12442 z = zchki(s) > -1;
12443 zchkid = 0;
12444 } else if (ifc == XXIFWR) { /* IF WRITEABLE */
12445 zchkod = 1;
12446 z = zchko(s) > -1;
12447 zchkod = 0;
12448 }
12449 #ifdef OS2
12450 if (!z && !y) { /* File not found. */
12451 int t; /* Try expanding variables */
12452 t = LINBUFSIZ-1; /* and looking again. */
12453 lp = line;
12454 zzstring(s,&lp,&t);
12455 s = line;
12456 z = zchko(s) > -1;
12457 y++;
12458 goto ifrdagain;
12459 }
12460 #endif /* OS2 */
12461 ifargs += 2;
12462 break;
12463 case XXIFQU: /* IF QUIET */
12464 z = quiet ? 1 : 0;
12465 debug(F101,"if quiet","",z);
12466 ifargs += 1;
12467 break;
12468
12469 case XXIFWI: /* WILD */
12470 if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
12471 z = iswild(s);
12472 break;
12473
12474 case XXIFCK: /* C-KERMIT */
12475 #ifdef OS2
12476 z = 0;
12477 #else
12478 z = 1;
12479 #endif /* OS2 */
12480 break;
12481
12482 case XXIFK9: /* K-95 */
12483 #ifdef OS2
12484 z = 1;
12485 #else
12486 z = 0;
12487 #endif /* OS2 */
12488 break;
12489
12490 case XXIFGU: /* GUI */
12491 #ifdef KUI
12492 z = 1;
12493 #else
12494 z = 0;
12495 #endif /* KUI */
12496 break;
12497
12498 case XXIFMS: /* MS-KERMIT */
12499 z = 0;
12500 break;
12501
12502 case XXIFLO: /* IF LOCAL */
12503 z = local ? 1 : 0;
12504 break;
12505
12506 case XXIFCM: { /* IF COMMAND */
12507 extern struct keytab cmdtab[];
12508 extern int ncmd;
12509 if ((x = cmfld("Word","",&s,xxstring)) < 0)
12510 return(x);
12511 z = lookup(cmdtab,s,ncmd,&y);
12512 z = (z == -2 || z > -1) ? 1 : 0;
12513 break;
12514 }
12515 #ifdef CKFLOAT
12516 case XXIFFP: /* IF FLOAT */
12517 if ((x = cmfld("Number","",&s,xxstring)) < 0)
12518 if (x != -3) /* e.g. empty variable */
12519 return(x);
12520 z = isfloat(s,0);
12521 break;
12522 #endif /* CKFLOAT */
12523
12524 case XXIFKB: /* KBHIT */
12525 z = conchk();
12526 if (z < 0) z = 0;
12527 if (z > 1) z = 1;
12528 break;
12529
12530 case XXIFKG: { /* KERBANG */
12531 extern int cfilef;
12532 #ifdef COMMENT
12533 z = (xcmdsrc == 0) ? 0 : (cfilef && cmdlvl == 1);
12534 #else
12535 z = (xcmdsrc == 0) ? 0 : (cfilef && tlevel == 0);
12536 #endif /* COMMENT */
12537 break;
12538 }
12539
12540 case XXIFDB: { /* IF DEBUG - 2010/03/16 */
12541 extern int debmsg;
12542 z = debmsg;
12543 break;
12544 }
12545 case XXIFFU: { /* IF FUNCTION - 2013/04/15 */
12546 extern struct keytab fnctab[];
12547 extern int nfuncs;
12548 int x, y;
12549
12550 y = cmkeyx(fnctab,nfuncs,"Name of function","",NULL);
12551 if (y == -1) /* Reparse needed */
12552 return(y);
12553 if (y < 0) { /* Something given but didn't match */
12554 int dummy;
12555 char * p;
12556 for (p = atmbuf; *p; p++) { /* Chop off trailing parens if any */
12557 if (*p == '(') {
12558 *p = NUL;
12559 break;
12560 }
12561 }
12562 /* Chop off leading "\\f" or "\f" or "f" */
12563 p = atmbuf;
12564 if (*p == CMDQ) /* Allow for \\f... */
12565 p++;
12566 if (*p == CMDQ && (*(p+1) == 'f' || *(p+1) == 'F')) { /* or \f */
12567 p += 2;
12568 } else if (*p == 'f' || *p == 'F') { /* or just f */
12569 p++;
12570 }
12571 y = lookup(fnctab,p,nfuncs,&dummy); /* Look up the result */
12572 }
12573 z = (y < 1) ? 0 : 1;
12574 break;
12575 }
12576 case XXIFTXT: /* IF TEXT - 2013/04/17 */
12577 case XXIFBIN: { /* IF BINARY - 2013/04/17 */
12578 if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0)
12579 return(x);
12580 if (y) {
12581 printf("?Please enter the name of a single file\n");
12582 return(-9);
12583 }
12584 if (isdir(s)) { /* Is the file a directory? */
12585 z = 0;
12586 } else {
12587 x = scanfile(s,NULL,nscanfile);
12588 if (x < 0) {
12589 printf("?Problem scanning %s\n",s);
12590 return(-9);
12591 }
12592 switch (x) {
12593 case FT_BIN: /* Binary */
12594 z = (ifc == XXIFBIN) ? 1 : 0;
12595 break;
12596 case FT_7BIT: /* Different text encodings */
12597 case FT_8BIT:
12598 case FT_UTF8:
12599 case FT_UCS2:
12600 case FT_TEXT:
12601 z = (ifc == XXIFTXT) ? 1 : 0;
12602 break;
12603 default:
12604 printf("?Problem scanning %s\n",s);
12605 return(-9);
12606 }
12607 }
12608 break;
12609 }
12610 default: /* Shouldn't happen */
12611 return(-2);
12612 } /* end of switch */
12613
12614 if (z)
12615 *bx++ = '1';
12616 else
12617 *bx++ = '0';
12618 *bx = NUL;
12619 if (bx > boolval + BOOLLEN - 2) {
12620 printf("?Boolean expression too long");
12621 return(-9);
12622 }
12623 ecount++; /* Expression counter */
12624 debug(F101,"boolexp parens","",parens);
12625 debug(F101,"boolexp pcount","",pcount);
12626 if (parens && pcount > 0)
12627 goto ifagain;
12628
12629 ifend: /* No more - done */
12630 *bx = NUL;
12631 z = atoi(evalx(boolval));
12632 debug(F111,"boolexp boolval",boolval,z);
12633 return(z);
12634 }
12635
12636 /* D O I F -- Do the IF command */
12637
12638 int
doif(cx)12639 doif(cx) int cx; {
12640 int x, y, z; char *s, *p;
12641 char *q;
12642 #ifdef OS2
12643 extern int keymac;
12644 #endif /* OS2 */
12645
12646 debug(F101,"doif cx","",cx);
12647
12648 /* Boolexp() calls the parsing functions: cmkey, cmnum, cmfld */
12649
12650 z = boolexp(cx); /* Evaluate the condition(s) */
12651 debug(F010,"doif cmdbuf",cmdbuf,0);
12652 debug(F101,"doif boolexp","",z);
12653 if (z < 0)
12654 return(z);
12655
12656 if (cx == XXIF) { /* Allow IF to have XIF semantics. */
12657 char * p;
12658 p = cmpeek();
12659 if (!p) p = "";
12660 while (*p) {
12661 if (*p == SP || *p == HT)
12662 p++;
12663 else
12664 break;
12665 }
12666 if (*p == '{')
12667 cx = XXIFX;
12668 }
12669 switch (cx) { /* Separate handling for IF and XIF */
12670
12671 case XXASSER: /* And ASSERT */
12672 if ((x = cmcfm()) < 0)
12673 return(x);
12674 return(success = z);
12675
12676 case XXIF: /* This is IF... */
12677 ifcmd[cmdlvl] = 1; /* We just completed an IF command */
12678 debug(F101,"doif condition","",z);
12679 if (z) { /* Condition is true */
12680 iftest[cmdlvl] = 1; /* Remember that IF succeeded */
12681 if (maclvl > -1) { /* In macro, */
12682 pushcmd(NULL); /* save rest of command. */
12683 } else if (tlevel > -1) { /* In take file, */
12684 debug(F100, "doif: pushing command", "", 0);
12685 pushcmd(NULL); /* save rest of command. */
12686 } else { /* If interactive, */
12687 cmini(ckxech); /* just start a new command */
12688 printf("\n"); /* (like in MS-DOS Kermit) */
12689 if (pflag) prompt(xxstring);
12690 }
12691 } else { /* Condition is false */
12692 iftest[cmdlvl] = 0; /* Remember command failed. */
12693 if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
12694 return(y); /* Gobble up rest of line */
12695 }
12696 return(0);
12697
12698 case XXIFX: { /* This is XIF (Extended IF) */
12699 char *p;
12700 char e[5];
12701 int i;
12702 if ((y = cmtxt("Object command","",&s,NULL)) < 0)
12703 return(y); /* Get object command. */
12704 p = s;
12705 lp = line;
12706 debug(F110,"doif THEN part",s,-54);
12707 if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
12708 return(-2);
12709 }
12710 debug(F111,"doif THEN part 2",line,z);
12711
12712 while (*p == SP) p++; /* Strip trailing spaces */
12713 ifcmd[cmdlvl] = 0; /* Assume ELSE part in same line */
12714 iftest[cmdlvl] = z ? 1 : 0;
12715 if (*p) { /* At end? */
12716 if (!z) { /* No, use ELSE-part, if any */
12717 for (i = 0; i < 4; i++) e[i] = *p++;
12718 if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
12719 return(-2); /* Something else - error. */
12720 debug(F010,"doif ELSE line 1",p,0);
12721 while (*p == SP) p++; /* Skip spaces */
12722 if (*p != '{') { /* Brace ELSE part if necessary */
12723 ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL);
12724 p = tmpbuf;
12725 debug(F010,"doif ELSE line 2",p,0);
12726 }
12727 lp = line; /* Write over THEN part... */
12728 *lp = NUL; /* with ELSE part. */
12729 if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
12730 return(-2);
12731 }
12732 while (*p == SP) p++; /* Strip trailing spaces */
12733 if (*p) return(-2); /* Should be nothing here. */
12734 debug(F010,"doif ELSE line 3",line,0);
12735 }
12736 } else { /* At end, treat like an IF command */
12737 if (!z) line[0] = NUL; /* Condition not true and no ELSE */
12738 ifcmd[cmdlvl] = 1; /* Allow ELSE on next line */
12739 debug(F101,"IF condition","",z);
12740 }
12741 if (line[0]) {
12742 x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
12743 if (x < 0) { /* Not there? */
12744 addmmac("_xif",xif_def); /* Put it back. */
12745 if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
12746 printf("?XIF macro gone!\n");
12747 return(success = 0);
12748 }
12749 }
12750 dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
12751 }
12752 return(0);
12753 }
12754 case XXWHI: { /* WHILE Command */
12755 p = cmdbuf; /* Capture IF condition */
12756 ifcond[0] = NUL; /* from command buffer */
12757 while (*p == SP) p++;
12758 while (*p != SP) p++;
12759 ifcp = ifcond;
12760 ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN);
12761 #ifdef COMMENT
12762 /*
12763 This doesn't work because it breaks on the first left brace, which does
12764 not necessarily start the command list, e.g. "while equal \%a {\35}".
12765 */
12766 while (*p != '{' && *p != NUL) *ifcp++ = *p++;
12767 p = " ) goto _..bot) } ";
12768 while (*ifcp++ = *p++) ;
12769 #else
12770 /*
12771 The command parser sets cmbptr to the spot where it left off parsing in
12772 the command buffer.
12773 */
12774 {
12775 extern char * cmbptr;
12776 if (cmbptr) {
12777 while (p < cmbptr && *p != NUL)
12778 *ifcp++ = *p++;
12779 p = " ) goto _..bot) } ";
12780 while ((*ifcp++ = *p++)) ;
12781 } else {
12782 printf("?Internal error parsing WHILE condition\n");
12783 return(-9);
12784 }
12785 }
12786 #endif /* COMMENT */
12787
12788 debug(F110,"WHILE cmd",ifcond,0);
12789
12790 if ((y = cmtxt("Object command","",&s,NULL)) < 0)
12791 return(y); /* Get object command. */
12792 p = s;
12793 lp = line;
12794 if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
12795 return(-2);
12796 }
12797 debug(F111,"WHILE body",line,-54);
12798 if (line[0]) {
12799 char *p;
12800 x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
12801 if (x < 0) { /* Not there? */
12802 addmmac("_while",whil_def); /* Put it back. */
12803 /* Look it up again */
12804 if ((x = mlook(mactab,"_while",nmac)) < 0) {
12805 printf("?WHILE macro definition gone!\n");
12806 return(success = 0);
12807 }
12808 }
12809 p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
12810 if (p) {
12811 strcpy(p,ifcond); /* safe (prechecked) */
12812 strcat(p,line); /* safe (prechecked) */
12813 debug(F110,"WHILE dodo",p,0);
12814 dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
12815 free(p);
12816 p = NULL;
12817 } else {
12818 printf("?Can't allocate storage for WHILE command");
12819 return(success = 0);
12820 }
12821 }
12822 return(0);
12823 }
12824 default:
12825 return(-2);
12826 }
12827 }
12828 #endif /* NOSPL */
12829
12830 /* Set up a TAKE command file */
12831
12832 int
dotake(s)12833 dotake(s) char *s; {
12834 #ifndef NOSPL
12835 extern char lasttakeline[]; /* Last TAKE-file line */
12836 extern int tra_cmd;
12837 #endif /* NOSPL */
12838 #ifndef NOLOCAL
12839 #ifdef OS2
12840 extern int term_io;
12841 int term_io_sav = term_io;
12842 #endif /* OS2 */
12843 #endif /* NOLOCAL */
12844 int slen;
12845
12846 debug(F110,"dotake",s,0);
12847 if (!s) s = "";
12848 if (!*s) return(success = 0);
12849 slen = strlen(s);
12850 debug(F101,"dotake len","",slen);
12851
12852 if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
12853 perror(s);
12854 debug(F110,"dotake fail",s,0);
12855 tlevel--;
12856 return(success = 0);
12857 } else {
12858 lasttakeline[0] = NUL;
12859 tfline[tlevel] = 0; /* Line counter */
12860 #ifdef VMS
12861 conres(); /* So Ctrl-C will work */
12862 #endif /* VMS */
12863 #ifndef NOLOCAL
12864 #ifdef OS2
12865 term_io = 0; /* Disable Terminal Emulator I/O */
12866 #endif /* OS2 */
12867 #endif /* NOLOCAL */
12868 #ifndef NOSPL
12869 cmdlvl++; /* Entering a new command level */
12870 debug(F111,"CMD +F",s,cmdlvl);
12871 debug(F101,"dotake cmdlvl","",cmdlvl);
12872 debug(F101,"dotake tlevel","",tlevel);
12873 if (cmdlvl > CMDSTKL) {
12874 debug(F100,"dotake stack overflow","",0);
12875 cmdlvl--;
12876 debug(F111,"CMD*-F",s,cmdlvl);
12877 fclose(tfile[tlevel--]);
12878 printf("?TAKE files and/or DO commands nested too deeply\n");
12879 return(success = 0);
12880 }
12881 if (tfnam[tlevel]) { /* Copy the filename */
12882 free(tfnam[tlevel]);
12883 tfnam[tlevel] = NULL;
12884 }
12885 if ((tfnam[tlevel] = malloc(strlen(s) + 1))) {
12886 strcpy(tfnam[tlevel],s); /* safe */
12887 } else {
12888 printf("?Memory allocation failure\n");
12889 return(success = 0);
12890 }
12891 ifcmd[cmdlvl] = 0; /* Set variables for this cmd file */
12892 iftest[cmdlvl] = 0;
12893 count[cmdlvl] = count[cmdlvl-1]; /* Inherit this */
12894 intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
12895 inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
12896 takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
12897 merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
12898 xquiet[cmdlvl] = quiet;
12899 xvarev[cmdlvl] = vareval;
12900 xcmdsrc = CMD_TF;
12901 cmdstk[cmdlvl].src = CMD_TF; /* Say we're in a TAKE file */
12902 cmdstk[cmdlvl].lvl = tlevel; /* nested at this level */
12903 cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
12904 #else
12905 takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
12906 #endif /* NOSPL */
12907 }
12908 #ifndef NOSPL
12909 if (tra_cmd)
12910 printf("[%d] +F: \"%s\"\n",cmdlvl,s);
12911 #endif /* NOSPL */
12912 #ifndef NOLOCAL
12913 #ifdef OS2
12914 term_io = term_io_sav;
12915 #endif /* OS2 */
12916 #endif /* NOLOCAL */
12917 return(1);
12918 }
12919 #endif /* NOICP */
12920