home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / MMV-32.ZIP / MMV-ORIG.C < prev    next >
C/C++ Source or Header  |  1990-06-13  |  61KB  |  2,910 lines

  1. /*
  2.     mmv 1.01b
  3.     Copyright (c) 1990 Vladimir Lanin.
  4.     This program may be freely used and copied on a non-commercial basis.
  5.     The author assumes no responsibility for any damage or data loss that may
  6.     result from the use of this program.
  7.  
  8.     Author may be reached at:
  9.  
  10.     lanin@csd4.cs.nyu.edu
  11.  
  12.     Vladimir Lanin
  13.     330 Wadsworth Ave, Apt 6F,
  14.     New York, NY 10040
  15.  
  16.     Many thanks to those who have to contributed to the design
  17.     and/or coding of this program:
  18.  
  19.     Tom Albrecht:    initial Sys V adaptation, consultation, and testing
  20.     Carl Mascott:    V7 adaptation
  21.     Mark Lewis:    -n flag idea, consultation.
  22.     Dave Bernhold:    upper/lowercase conversion idea.
  23.     Paul Stodghill:    copy option, argv[0] checking.
  24.     Frank Fiamingo:    consultation and testing.
  25.     Tom Jordahl:    bug reports and testing.
  26.     John Lukas, Hugh Redelmeyer, Barry Nelson, John Sauter,
  27.     Phil Dench, John Nelson:
  28.             bug reports.
  29. */
  30.  
  31. /*
  32.     Define SYSV to compile under System V.
  33.     Define both SYSV and V7 to compile under V7.
  34.     If your System V has a rename() call, define RENAME.
  35.     Otherwise, mmv will only be able to rename directories (via option -r)
  36.     when running as the super-user.
  37.     There is no reason to set the suid bit on mmv if rename() is available.
  38.     It is important that mmv not be run with effective uid set
  39.     to any value other than either the real uid or the super-user.
  40.     Even when running with effective uid set to super-user,
  41.     mmv will only perform actions permitted to the real uid.
  42.  
  43.     Define MSDOS to compile under MS-D*S Turbo C 1.5.
  44.     If you prefer mmv's output to use /'s instead of \'s under MS-D*S,
  45.     define SLASH.
  46.  
  47.     When neither MSDOS nor SYSV are defined, compiles under BSD.
  48.  
  49.     RENAME is automatically defined under MSDOS and BSD.
  50.  
  51.     If you are running a (UN*X) system that provides the
  52.     "struct dirent" readdir() directory reading standard,
  53.     define DIRENT. Otherwise, mmv uses the BSD-like
  54.     "struct direct" readdir().
  55.     If your (UN*X) system has neither of these, get the "dirent"
  56.     by Doug Gwyn, available as gwyn-dir-lib in volume 9
  57.     of the comp.sources.unix archives.
  58. */
  59.  
  60. static char USAGE[] =
  61. #ifdef MSDOS
  62.  
  63. "Usage: \
  64. %s [-m|x%s|c|o|a|z] [-h] [-d|p] [-g|t] [-v|n] [from to]\n\
  65. \n\
  66. Use =N in the ``to'' pattern to get the string matched\n\
  67. by the N'th ``from'' pattern wildcard.\n";
  68.  
  69. #define OTHEROPT (_osmajor < 3 ? "" : "|r")
  70.  
  71. #else
  72.  
  73. "Usage: \
  74. %s [-m|x|r|c|o|a|l%s] [-h] [-d|p] [-g|t] [-v|n] [from to]\n\
  75. \n\
  76. Use =[l|u]N in the ``to'' pattern to get the [lowercase|uppercase of the]\n\
  77. string matched by the N'th ``from'' pattern wildcard.\n\
  78. \n\
  79. A ``from'' pattern containing wildcards should be quoted when given\n\
  80. on the command line.\n";
  81.  
  82. #ifdef SYSV
  83. #define OTHEROPT ""
  84. #else
  85. #define OTHEROPT "|s"
  86. #endif
  87.  
  88. #endif
  89.  
  90. #include <stdio.h>
  91. #include <ctype.h>
  92.  
  93. #ifdef MSDOS
  94. /* for MS-DOS (under Turbo C 1.5)*/
  95.  
  96. #include <string.h>
  97. #include <stdlib.h>
  98. #include <sys/stat.h>
  99. #include <dos.h>
  100. #include <dir.h>
  101. #include <io.h>
  102. #include <fcntl.h>
  103.  
  104. #define ESC '\''
  105. #ifdef SLASH
  106. #define SLASH '/'
  107. #define OTHERSLASH '\\'
  108. #else
  109. #define SLASH '\\'
  110. #define OTHERSLASH '/'
  111. #endif
  112.  
  113. typedef int DIRID;
  114. typedef int DEVID;
  115.  
  116. static char TTY[] = "/dev/con";
  117. extern unsigned _stklen = 10000;
  118.  
  119. #define RENAME
  120.  
  121. #else
  122. /* for various flavors of UN*X */
  123.  
  124. #include <sys/types.h>
  125. #include <sys/stat.h>
  126. #include <sys/file.h>
  127.  
  128. extern char *getenv();
  129. extern long lseek();
  130. extern char *malloc();
  131.  
  132. #ifdef DIRENT
  133. #include <dirent.h>
  134. typedef struct dirent DIRENTRY;
  135. #else
  136. #ifdef SYSV
  137. #include <sys/dir.h>
  138. /* might need to be changed to <dir.h> */
  139. #else
  140. #include <sys/dir.h>
  141. #endif
  142. typedef struct direct DIRENTRY;
  143. #endif
  144.  
  145. #define void char    /* might want to remove this line */
  146.  
  147. #ifndef O_BINARY
  148. #define O_BINARY 0
  149. #endif
  150. #ifndef R_OK
  151. #define R_OK 4
  152. #define W_OK 2
  153. #define X_OK 1
  154. #endif
  155.  
  156. #define ESC '\\'
  157. #define SLASH '/'
  158.  
  159. typedef ino_t DIRID;
  160. typedef dev_t DEVID;
  161.  
  162. #define MAXPATH 1024
  163.  
  164. static char TTY[] = "/dev/tty";
  165.  
  166. #ifdef V7
  167. /* for Version 7 */
  168. #include <errno.h>
  169. extern int errno;
  170. #define strchr index
  171. extern char *strcpy(), *strchr();
  172. #include <signal.h>
  173. #define O_RDONLY 0
  174. #define O_WRONLY 1
  175. #define O_RDWR   2
  176.  
  177. #else
  178. /* for System V and BSD */
  179. #include <string.h>
  180. #include <sys/signal.h>
  181. #include <fcntl.h>
  182. #endif
  183.  
  184. #ifdef SYSV
  185. /* for System V and Version 7*/
  186. struct utimbuf {
  187.     time_t actime;
  188.     time_t modtime;
  189. };
  190. #define utimes(f, t) utime((f), &(t))
  191.  
  192. #else
  193. /* for BSD */
  194. #define RENAME
  195. #include <sys/time.h>
  196.  
  197. #endif
  198. #endif
  199.  
  200. #define mylower(c) (isupper(c) ? (c)-'A'+'a' : (c))
  201. #define myupper(c) (islower(c) ? (c)-'a'+'A' : (c))
  202. #define STRLEN(s) (sizeof(s) - 1)
  203. #define mydup(s) (strcpy((char *)challoc(strlen(s) + 1, 0), (s)))
  204.  
  205.  
  206. #define DFLT 0x001
  207. #define NORMCOPY 0x002
  208. #define OVERWRITE 0x004
  209. #define NORMMOVE 0x008
  210. #define XMOVE 0x010
  211. #define DIRMOVE 0x020
  212. #define NORMAPPEND 0x040
  213. #define ZAPPEND 0x080
  214. #define HARDLINK 0x100
  215. #define SYMLINK 0x200
  216.  
  217. #define COPY (NORMCOPY | OVERWRITE)
  218. #define MOVE (NORMMOVE | XMOVE | DIRMOVE)
  219. #define APPEND (NORMAPPEND | ZAPPEND)
  220. #define LINK (HARDLINK | SYMLINK)
  221.  
  222. static char MOVENAME[] = "mmv";
  223. static char COPYNAME[] = "mcp";
  224. static char APPENDNAME[] = "mad";
  225. static char LINKNAME[] = "mln";
  226.  
  227. #define ASKDEL 0
  228. #define ALLDEL 1
  229. #define NODEL 2
  230.  
  231. #define ASKBAD 0
  232. #define SKIPBAD 1
  233. #define ABORTBAD 2
  234.  
  235. #define STAY 0
  236. #define LOWER 1
  237. #define UPPER 2
  238.  
  239. #define MAXWILD 20
  240. #define MAXPATLEN MAXPATH
  241. #define INITROOM 10
  242. #define CHUNKSIZE 2048
  243. #define BUFSIZE 4096
  244.  
  245. #define FI_STTAKEN 0x01
  246. #define FI_LINKERR 0x02
  247. #define FI_INSTICKY 0x04
  248. #define FI_NODEL 0x08
  249. #define FI_KNOWWRITE 0x010
  250. #define FI_CANWRITE 0x20
  251. #define FI_ISDIR 0x40
  252. #define FI_ISLNK 0x80
  253.  
  254. typedef struct {
  255.     char *fi_name;
  256.     struct rep *fi_rep;
  257. #ifdef MSDOS
  258.     char fi_attrib;
  259. #else
  260.     short fi_mode;
  261.     char fi_stflags;
  262. #endif
  263. } FILEINFO;
  264.  
  265. #define DI_KNOWWRITE 0x01
  266. #define DI_CANWRITE 0x02
  267. #define DI_CLEANED 0x04
  268.  
  269. typedef struct {
  270.     DEVID di_vid;
  271.     DIRID di_did;
  272.     unsigned di_nfils;
  273.     FILEINFO **di_fils;
  274.     char di_flags;
  275. } DIRINFO;
  276.  
  277. #define H_NODIR 1
  278. #define H_NOREADDIR 2
  279.  
  280. typedef struct {
  281.     char *h_name;
  282.     DIRINFO *h_di;
  283.     char h_err;
  284. } HANDLE;
  285.  
  286. #define R_ISX 0x01
  287. #define R_SKIP 0x02
  288. #define R_DELOK 0x04
  289. #define R_ISALIASED 0x08
  290. #define R_ISCYCLE 0x10
  291. #define R_ONEDIRLINK 0x20
  292.  
  293. typedef struct rep {
  294.     HANDLE *r_hfrom;
  295.     FILEINFO *r_ffrom;
  296.     HANDLE *r_hto;
  297.     char *r_nto;            /* non-path part of new name */
  298.     FILEINFO *r_fdel;
  299.     struct rep *r_first;
  300.     struct rep *r_thendo;
  301.     struct rep *r_next;
  302.     char r_flags;
  303. } REP;
  304.  
  305. typedef struct {
  306.     REP *rd_p;
  307.     DIRINFO *rd_dto;
  308.     char *rd_nto;
  309.     unsigned rd_i;
  310. } REPDICT;
  311.  
  312. typedef struct chunk {
  313.     struct chunk *ch_next;
  314.     unsigned ch_len;
  315. } CHUNK;
  316.  
  317. typedef struct {
  318.     CHUNK *sl_first;
  319.     char *sl_unused;
  320.     int sl_len;
  321. } SLICER;
  322.  
  323.  
  324. static void init(/* */);
  325. static void procargs(/* int argc, char **argv,
  326.     char **pfrompat, char **ptopat */);
  327. static void domatch(/* char *cfrom, char *cto */);
  328. static int getpat(/* */);
  329. static int getword(/* char *buf */);
  330. static void matchpat(/*  */);
  331. static int parsepat(/*  */);
  332. static int dostage(/* char *lastend, char *pathend,
  333.     char **start1, int *len1, int stage, int anylev */);
  334. static int trymatch(/* FILEINFO *ffrom, char *pat */);
  335. static int keepmatch(/* FILEINFO *ffrom, char *pathend,
  336.     int *pk, int needslash, int dirs, int fils */);
  337. static int badrep(/* HANDLE *hfrom, FILEINFO *ffrom,
  338.     HANDLE **phto, char **pnto, FILEINFO **pfdel, int *pflags */);
  339. static int checkto(/* HANDLE *hfrom, char *f,
  340.     HANDLE **phto, char **pnto, FILEINFO **pfdel */);
  341. static char *getpath(/* char *tpath */);
  342. static int badname(/* char *s */);
  343. static FILEINFO *fsearch(/* char *s, DIRINFO *d */);
  344. static int ffirst(/* char *s, int n, DIRINFO *d */);
  345. static HANDLE *checkdir(/* char *p, char *pathend, int which */);
  346. static void takedir(/*
  347.     char *p, DIRINFO *di, int sticky
  348. or
  349.     struct ffblk *pff, DIRINFO *di
  350. */);
  351. static int fcmp(/* FILEINFO **pf1, FILEINFO **pf2 */);
  352. static HANDLE *hadd(/* char *n */);
  353. static int hsearch(/* char *n, int which, HANDLE **ph */);
  354. static DIRINFO *dadd(/* DEVID v, DIRID d */);
  355. static DIRINFO *dsearch(/* DEVID v, DIRID d */);
  356. static int match(/* char *pat, char *s, char **start1, int *len1 */);
  357. static void makerep(/*  */);
  358. static void checkcollisions(/*  */);
  359. static int rdcmp(/* REPDICT *rd1, REPDICT *rd2 */);
  360. static void findorder(/*  */);
  361. static void scandeletes(/* int (*pkilldel)(REP *p) */);
  362. static int baddel(/* REP *p */);
  363. static int skipdel(/* REP *p */);
  364. static void nochains(/*  */);
  365. static void printchain(/* REP *p */);
  366. static void goonordie(/*  */);
  367. static void doreps(/*  */);
  368. static long appendalias(/* REP *first, REP *p, int *pprintaliased */);
  369. static int movealias(/* REP *first, REP *p, int *pprintaliased */);
  370. static int snap(/* REP *first, REP *p */);
  371. static void showdone(/* REP *fin */);
  372. static void breakout(/*  */);
  373. static int breakrep(/* */);
  374. static void breakstat(/* */);
  375. static void quit(/*  */);
  376. static int copymove(/* REP *p */);
  377. static int copy(/* FILENFO *f, long len */);
  378. static int myunlink(/* char *n, FILEINFO *f */);
  379. static int getreply(/* char *m, int failact */);
  380. static void *myalloc(/* unsigned k */);
  381. static void *challoc(/* int k, int which */);
  382. static void chgive(/* void *p, unsigned k */);
  383. static int mygetc(/* */);
  384. static char *mygets(/* char *s, int l */);
  385. #ifdef MSDOS
  386. static int leave(/*  */);
  387. static void cleanup(/*  */);
  388. #else
  389. static int getstat(/* char *full, FILEINFO *f */);
  390. static int dwritable(/* HANDLE *h */);
  391. static int fwritable(/* char *hname, FILEINFO *f */);
  392. static void memmove(/* void *to, void *from, int k */);
  393. #endif
  394. #ifndef RENAME
  395. static int rename(/* char *from, char *to */);
  396. #endif
  397.  
  398. static int op, badstyle, delstyle, verbose, noex, matchall;
  399. static int patflags;
  400.  
  401. static unsigned ndirs = 0, dirroom;
  402. static DIRINFO **dirs;
  403. static unsigned nhandles = 0, handleroom;
  404. static HANDLE **handles;
  405. static HANDLE badhandle = {"\200", NULL, 0};
  406. static HANDLE *(lasthandle[2]) = {&badhandle, &badhandle};
  407. static unsigned nreps = 0;
  408. static REP hrep, *lastrep = &hrep;
  409. static CHUNK *freechunks = NULL;
  410. static SLICER slicer[2] = {{NULL, NULL, 0}, {NULL, NULL, 0}};
  411.  
  412. static int badreps = 0, paterr = 0, direrr, failed = 0, gotsig = 0, repbad;
  413. static FILE *outfile = stdout;
  414.  
  415. static char IDF[] = "$$mmvdid.";
  416. static char TEMP[] = "$$mmvtmp.";
  417. static char TOOLONG[] = "(too long)";
  418. static char EMPTY[] = "(empty)";
  419.  
  420. static char SLASHSTR[] = {SLASH, '\0'};
  421.  
  422. static char PATLONG[] = "%.40s... : pattern too long.\n";
  423.  
  424. char from[MAXPATLEN], to[MAXPATLEN];
  425. static int fromlen, tolen;
  426. static char *(stagel[MAXWILD]), *(firstwild[MAXWILD]), *(stager[MAXWILD]);
  427. static int nwilds[MAXWILD];
  428. static int nstages;
  429. char pathbuf[MAXPATH];
  430. char fullrep[MAXPATH + 1];
  431. static char *(start[MAXWILD]);
  432. static int len[MAXWILD];
  433. static char hasdot[MAXWILD];
  434. static REP mistake;
  435. #define MISTAKE (&mistake)
  436.  
  437. #ifdef MSDOS
  438.  
  439. static int olddevflag, curdisk, maxdisk;
  440. static struct {
  441.     char ph_banner[30];
  442.     char ph_name[9];
  443.     int ph_dfltop;
  444.     int ph_safeid;
  445.     int ph_clustoff;
  446.     int ph_driveoff;
  447.     int ph_drivea;
  448. } patch = {"mmv 1.0 patchable flags", "mmv", XMOVE, 1, 0};
  449.  
  450. #define DFLTOP (patch.ph_dfltop)
  451. #define CLUSTNO(pff) (*(int *)(((char *)(pff)) + patch.ph_clustoff))
  452. #define DRIVENO(pff) (*(((char *)(pff)) + patch.ph_driveoff) - patch.ph_drivea)
  453.  
  454.  
  455. #else
  456.  
  457. #define DFLTOP XMOVE
  458.  
  459. static char *home;
  460. static int homelen;
  461. static int uid, euid, oldumask;
  462. static DIRID cwdd = -1;
  463. static DEVID cwdv = -1;
  464.  
  465. #endif
  466.  
  467.  
  468. int main(argc, argv)
  469.     int argc;
  470.     char *(argv[]);
  471. {
  472.     char *frompat, *topat;
  473.  
  474.     init();
  475.     procargs(argc, argv, &frompat, &topat);
  476.     domatch(frompat, topat);
  477.     if (!(op & APPEND))
  478.         checkcollisions();
  479.     findorder();
  480.     if (op & (COPY | LINK))
  481.         nochains();
  482.     scandeletes(baddel);
  483.     goonordie();
  484.     if (!(op & APPEND) && delstyle == ASKDEL)
  485.         scandeletes(skipdel);
  486.     doreps();
  487.     return(failed ? 2 : nreps == 0 && (paterr || badreps));
  488. }
  489.  
  490.  
  491. static void init()
  492. {
  493. #ifdef MSDOS
  494.     curdisk = getdisk();
  495.     maxdisk = setdisk(curdisk);
  496. /*
  497.     Read device availability : undocumented internal MS-DOS function.
  498.     If (_DX == 0) then \dev\ must precede device names.
  499. */
  500.     bdos(0x37, 0, 2);
  501.     olddevflag = _DX;
  502. /*
  503.     Write device availability: undocumented internal MS-DOS function.
  504.     Specify \dev\ must precede device names.
  505. */
  506.     bdos(0x37, 0, 3);
  507.     atexit((atexit_t)cleanup);
  508.     ctrlbrk((int (*)())breakout);
  509. #else
  510.     struct stat dstat;
  511.  
  512.     if ((home = getenv("HOME")) == NULL || strcmp(home, SLASHSTR) == 0)
  513.         home = "";
  514.     if (!stat(".", &dstat)) {
  515.         cwdd = dstat.st_ino;
  516.         cwdv = dstat.st_dev;
  517.     }
  518.     oldumask = umask(0);
  519.     euid = geteuid();
  520.     uid = getuid();
  521.     signal(SIGINT, breakout);
  522. #endif
  523.  
  524.     dirroom = handleroom = INITROOM;
  525.     dirs = (DIRINFO **)myalloc(dirroom * sizeof(DIRINFO *));
  526.     handles = (HANDLE **)myalloc(handleroom * sizeof(HANDLE *));
  527.     ndirs = nhandles = 0;
  528. }
  529.  
  530.  
  531. static void procargs(argc, argv, pfrompat, ptopat)
  532.     int argc;
  533.     char **argv;
  534.     char **pfrompat, **ptopat;
  535. {
  536.     char *p, c;
  537.     char *cmdname = argv[0];
  538.  
  539. #ifdef MSDOS
  540. #define CMDNAME (patch.ph_name)
  541. #else
  542. #define CMDNAME cmdname
  543. #endif
  544.  
  545.     op = DFLT;
  546.     verbose = noex = matchall = 0;
  547.     delstyle = ASKDEL;
  548.     badstyle = ASKBAD;
  549.     for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++)
  550.         for (p = *argv + 1; *p != '\0'; p++) {
  551.             c = mylower(*p);
  552.             if (c == 'v' && !noex)
  553.                 verbose = 1;
  554.             else if (c == 'n' && !verbose)
  555.                 noex = 1;
  556.             else if (c == 'h')
  557.                 matchall = 1;
  558.             else if (c == 'd' && delstyle == ASKDEL)
  559.                 delstyle = ALLDEL;
  560.             else if (c == 'p' && delstyle == ASKDEL)
  561.                 delstyle = NODEL;
  562.             else if (c == 'g' && badstyle == ASKBAD)
  563.                 badstyle = SKIPBAD;
  564.             else if (c == 't' && badstyle == ASKBAD)
  565.                 badstyle = ABORTBAD;
  566.             else if (c == 'm' && op == DFLT)
  567.                 op = NORMMOVE;
  568.             else if (c == 'x' && op == DFLT)
  569.                 op = XMOVE;
  570.             else if (c == 'r' && op == DFLT)
  571.                 op = DIRMOVE;
  572.             else if (c == 'c' && op == DFLT)
  573.                 op = NORMCOPY;
  574.             else if (c == 'o' && op == DFLT)
  575.                 op = OVERWRITE;
  576.             else if (c == 'a' && op == DFLT)
  577.                 op = NORMAPPEND;
  578. #ifdef MSDOS
  579.             else if (c == 'z' && op == DFLT)
  580.                 op = ZAPPEND;
  581. #else
  582.             else if (c == 'l' && op == DFLT)
  583.                 op = HARDLINK;
  584. #ifndef SYSV
  585.             else if (c == 's' && op == DFLT)
  586.                 op = SYMLINK;
  587. #endif
  588. #endif
  589.             else {
  590.                 fprintf(stderr, USAGE, CMDNAME, OTHEROPT);
  591.                 exit(1);
  592.             }
  593.         }
  594.  
  595.     if (op == DFLT)
  596.         if (strcmp(cmdname, MOVENAME) == 0)
  597.             op = XMOVE;
  598.         else if (strcmp(cmdname, COPYNAME) == 0)
  599.             op = NORMCOPY;
  600.         else if (strcmp(cmdname, APPENDNAME) == 0)
  601.             op = NORMAPPEND;
  602.         else if (strcmp(cmdname, LINKNAME) == 0)
  603.             op = HARDLINK;
  604.         else
  605.             op = DFLTOP;
  606.     if (
  607.         op & DIRMOVE &&
  608. #ifdef MSDOS
  609.         _osmajor < 3
  610. #else
  611. #ifndef RENAME
  612.         euid != 0
  613. #else
  614.         0
  615. #endif
  616. #endif
  617.     ) {
  618.         fprintf(stderr,
  619.             "Unable to do directory renames. Option -r refused.\n");
  620.         quit();
  621.     }
  622.  
  623. #ifndef MSDOS
  624.     if (euid != uid && !(op & DIRMOVE)) {
  625.         setuid(uid);
  626.         setgid(getgid());
  627.     }
  628. #endif
  629.  
  630.     if (badstyle != ASKBAD && delstyle == ASKDEL)
  631.         delstyle = NODEL;
  632.  
  633.     if (argc == 0)
  634.         *pfrompat = NULL;
  635.     else if (argc == 2) {
  636.         *pfrompat = *(argv++);
  637.         *ptopat = *(argv++);
  638.     }
  639.     else {
  640.         fprintf(stderr, USAGE, CMDNAME, OTHEROPT);
  641.         exit(1);
  642.     }
  643. }
  644.  
  645.  
  646. static void domatch(cfrom, cto)
  647.     char *cfrom, *cto;
  648. {
  649.     if (cfrom == NULL)
  650.         while (getpat())
  651.             matchpat();
  652.     else if ((fromlen = strlen(cfrom)) >= MAXPATLEN) {
  653.         printf(PATLONG, cfrom);
  654.         paterr = 1;
  655.     }
  656.     else if ((tolen = strlen(cto)) >= MAXPATLEN) {
  657.         printf(PATLONG, cto);
  658.         paterr = 1;
  659.     }
  660.     else {
  661.         strcpy(from, cfrom);
  662.         strcpy(to, cto);
  663.         matchpat();
  664.     }
  665. }
  666.  
  667.  
  668. static int getpat()
  669. {
  670.     int c, gotit = 0;
  671.     char extra[MAXPATLEN];
  672.  
  673.     patflags = 0;
  674.     do {
  675.         if ((fromlen = getword(from)) == 0 || fromlen == -1)
  676.             goto nextline;
  677.  
  678.         do {
  679.             if ((tolen = getword(to)) == 0) {
  680.                 printf("%s -> ? : missing replacement pattern.\n", from);
  681.                 goto nextline;
  682.             }
  683.             if (tolen == -1)
  684.                 goto nextline;
  685.         } while (
  686.             tolen == 2 &&
  687.             (to[0] == '-' || to[0] == '=') &&
  688.             (to[1] == '>' || to[1] == '^')
  689.         );
  690.         if (getword(extra) == 0)
  691.             gotit = 1;
  692.         else if (strcmp(extra, "(*)") == 0) {
  693.             patflags |= R_DELOK;
  694.             gotit = (getword(extra) == 0);
  695.         }
  696.  
  697. nextline:
  698.         while ((c = mygetc()) != '\n' && c != EOF)
  699.             ;
  700.         if (c == EOF)
  701.             return(0);
  702.     } while (!gotit);
  703.  
  704.     return(1);
  705. }
  706.  
  707.  
  708. static int getword(buf)
  709.     char *buf;
  710. {
  711.     int c, prevc, n;
  712.     char *p;
  713.  
  714.     p = buf;
  715.     prevc = ' ';
  716.     n = 0;
  717.     while ((c = mygetc()) != EOF && (prevc == ESC || !isspace(c))) {
  718.         if (n == -1)
  719.             continue;
  720.         if (n == MAXPATLEN - 1) {
  721.             *p = '\0';
  722.             printf(PATLONG, buf);
  723.             n = -1;
  724.         }
  725.         *(p++) = c;
  726.         n++;
  727.         prevc = c;
  728.     }
  729.     *p = '\0';
  730.     while (c != EOF && isspace(c) && c != '\n')
  731.         c = mygetc();
  732.     if (c != EOF)
  733.         ungetc(c, stdin);
  734.     return(n);
  735. }
  736.  
  737.  
  738. static void matchpat()
  739. {
  740.     if (parsepat())
  741.         paterr = 1;
  742.     else if (dostage(from, pathbuf, start, len, 0, 0)) {
  743.         printf("%s -> %s : no match.\n", from, to);
  744.         paterr = 1;
  745.     }
  746. }
  747.  
  748.  
  749. static int parsepat()
  750. {
  751.     char *p, *lastname, c;
  752.     int totwilds, instage, x, havedot;
  753.     static char TRAILESC[] = "%s -> %s : trailing %c is superfluous.\n";
  754.  
  755.     lastname = from;
  756. #ifdef MSDOS
  757.     havedot = 0;
  758.     if (from[0] != '\0' && from[1] == ':')
  759.         lastname += 2;
  760. #else
  761.     if (from[0] == '~' && from[1] == SLASH) {
  762.         if ((homelen = strlen(home)) + fromlen > MAXPATLEN) {
  763.             printf(PATLONG, from);
  764.             return(-1);
  765.         }
  766.         memmove(from + homelen, from + 1, fromlen);
  767.         memmove(from, home, homelen);
  768.         lastname += homelen + 1;
  769.     }
  770. #endif
  771.     totwilds = nstages = instage = 0;
  772.     for (p = lastname; (c = *p) != '\0'; p++)
  773.         switch (c) {
  774. #ifdef MSDOS
  775.         case '.':
  776.             havedot = 1;
  777.             break;
  778.         case OTHERSLASH:
  779.             *p = SLASH;
  780. #endif
  781.          case SLASH:
  782. #ifdef MSDOS
  783.             if (!havedot && lastname != p) {
  784.                 if (fromlen++ == MAXPATLEN) {
  785.                     printf(PATLONG, from);
  786.                     return(-1);
  787.                 }
  788.                 memmove(p + 1, p, strlen(p) + 1);
  789.                 *(p++) = '.';
  790.             }
  791.             else
  792.                 havedot = 0;
  793. #endif
  794.             lastname = p + 1;
  795.             if (instage) {
  796.                 if (firstwild[nstages] == NULL)
  797.                     firstwild[nstages] = p;
  798.                 stager[nstages++] = p;
  799.                 instage = 0;
  800.             }
  801.             break;
  802.         case ';':
  803.             if (lastname != p) {
  804.                 printf("%s -> %s : badly placed ;.\n", from, to);
  805.                 return(-1);
  806.             }
  807.         case '!':
  808.         case '*':
  809.         case '?':
  810.         case '[':
  811. #ifdef MSDOS
  812.             if ((hasdot[totwilds] = (c == '!')) != 0)
  813.                 havedot = 1;
  814. #endif
  815.             if (totwilds++ == MAXWILD) {
  816.                 printf("%s -> %s : too many wildcards.\n", from, to);
  817.                 return(-1);
  818.             }
  819.             if (instage) {
  820.                 nwilds[nstages]++;
  821.                 if (firstwild[nstages] == NULL)
  822.                     firstwild[nstages] = p;
  823.             }
  824.             else {
  825.                 stagel[nstages] = lastname;
  826.                 firstwild[nstages] = (c == ';' ? NULL : p);
  827.                 nwilds[nstages] = 1;
  828.                 instage = 1;
  829.             }
  830.             if (c != '[')
  831.                 break;
  832.             while ((c = *(++p)) != ']') {
  833.                 switch (c) {
  834.                 case '\0':
  835.                     printf("%s -> %s : missing ].\n", from, to);
  836.                     return(-1);
  837. #ifdef MSDOS
  838.                 case '.':
  839.                 case ':':
  840.                 case OTHERSLASH:
  841. #endif
  842.                 case SLASH:
  843.                     printf("%s -> %s : '%c' can not be part of [].\n",
  844.                         from, to, c);
  845.                     return(-1);
  846.                 case ESC:
  847.                     if ((c = *(++p)) == '\0') {
  848.                         printf(TRAILESC, from, to, ESC);
  849.                         return(-1);
  850.                     }
  851. #ifdef MSDOS
  852.                 default:
  853.                     if (isupper(c))
  854.                         *p = c + ('a' - 'A');
  855. #endif
  856.                 }
  857.             }
  858.             break;
  859.         case ESC:
  860.             if ((c = *(++p)) == '\0') {
  861.                 printf(TRAILESC, from, to, ESC);
  862.                 return(-1);
  863.             }
  864. #ifdef MSDOS
  865.         default:
  866.             if (isupper(c))
  867.                 *p = c + ('a' - 'A');
  868. #endif
  869.         }
  870.  
  871. #ifdef MSDOS
  872.     if (!havedot && lastname != p) {
  873.         if (fromlen++ == MAXPATLEN) {
  874.             printf(PATLONG, from);
  875.             return(-1);
  876.         }
  877.         strcpy(p++, ".");
  878.     }
  879. #endif
  880.  
  881.     if (instage) {
  882.         if (firstwild[nstages] == NULL)
  883.             firstwild[nstages] = p;
  884.         stager[nstages++] = p;
  885.     }
  886.     else {
  887.         stagel[nstages] = lastname;
  888.         nwilds[nstages] = 0;
  889.         firstwild[nstages] = p;
  890.         stager[nstages++] = p;
  891.     }
  892.  
  893.     lastname = to;
  894. #ifdef MSDOS
  895.     havedot = 0;
  896.     if (to[0] != '\0' && to[1] == ':')
  897.         lastname += 2;
  898. #else
  899.     if (to[0] == '~' && to[1] == SLASH) {
  900.         if ((homelen = strlen(home)) + tolen > MAXPATLEN) {
  901.             printf(PATLONG, to);
  902.                 return(-1);
  903.         }
  904.         memmove(to + homelen, to + 1, tolen);
  905.         memmove(to, home, homelen);
  906.         lastname += homelen + 1;
  907.     }
  908. #endif
  909.  
  910.     for (p = lastname; (c = *p) != '\0'; p++)
  911.         switch (c) {
  912. #ifdef MSDOS
  913.         case '.':
  914.             havedot = 1;
  915.             break;
  916.         case OTHERSLASH:
  917.             *p = SLASH;
  918. #endif
  919.         case SLASH:
  920.             if (op & DIRMOVE) {
  921.                 printf("%s -> %s : no path allowed in target under -r.\n",
  922.                     from, to);
  923.                 return(-1);
  924.             }
  925. #ifdef MSDOS
  926.             if (!havedot && lastname != p) {
  927.                 if (tolen++ == MAXPATLEN) {
  928.                     printf(PATLONG, to);
  929.                     return(-1);
  930.                 }
  931.                 memmove(p + 1, p, strlen(p) + 1);
  932.                 *(p++) = '.';
  933.             }
  934.             else
  935.                 havedot = 0;
  936. #endif
  937.             lastname = p + 1;
  938.             break;
  939.         case '=':
  940.             c = *(++p);
  941.             if (c == 'l' || c == 'u') {
  942. #ifdef MSDOS
  943.                 strcpy(p, p + 1);
  944.                 c = *p;
  945. #else
  946.                 c = *(++p);
  947. #endif
  948.             }
  949.             if (!isdigit(c)) {
  950.                 printf("%s -> %s : expected digit (not '%c') after =.\n",
  951.                     from, to, c);
  952.                 return(-1);
  953.             }
  954.             for(x = 0; ;x *= 10) {
  955.                 x += c - '0';
  956.                 c = *(p+1);
  957.                 if (!isdigit(c))
  958.                     break;
  959.                 p++;
  960.             }
  961.             if (x < 1 || x > totwilds) {
  962.                 printf("%s -> %s : wildcard %d does not exist.\n",
  963.                     from, to, x);
  964.                 return(-1);
  965.             }
  966. #ifdef MSDOS
  967.             if (hasdot[x - 1])
  968.                 havedot = 1;
  969. #endif
  970.             break;
  971.         case ESC:
  972.             if ((c = *(++p)) == '\0') {
  973.                 printf(TRAILESC, from, to, ESC);
  974.                 return(-1);
  975.             }
  976.         default:
  977.             if (
  978. #ifdef MSDOS
  979.                 c <= ' ' || c >= 127 ||
  980.                 strchr(":/\\*?[]=+;,\"|<>", c) != NULL
  981. #else
  982.                 c & 0x80
  983. #endif
  984.             ) {
  985.                 printf("%s -> %s : illegal character '%c' (0x%02X).\n",
  986.                     from, to, c, c);
  987.                 return(-1);
  988.             }
  989. #ifdef MSDOS
  990.             if (isupper(c))
  991.                 *p = c + ('a' - 'A');
  992. #endif
  993.         }
  994.  
  995. #ifdef MSDOS
  996.     if (!havedot && lastname != p) {
  997.         if (tolen++ == MAXPATLEN) {
  998.             printf(PATLONG, to);
  999.             return(-1);
  1000.         }
  1001.         strcpy(p++, ".");
  1002.     }
  1003. #endif
  1004.  
  1005.     return(0);
  1006. }
  1007.  
  1008.  
  1009. static int dostage(lastend, pathend, start1, len1, stage, anylev)
  1010.     char *lastend, *pathend;
  1011.     char **start1;
  1012.     int *len1;
  1013.     int stage;
  1014.     int anylev;
  1015. {
  1016.     DIRINFO *di;
  1017.     HANDLE *h, *hto;
  1018.     int prelen, litlen, nfils, i, k, flags, try;
  1019.     FILEINFO **pf, *fdel;
  1020.     char *nto, *firstesc;
  1021.     REP *p;
  1022.     int wantdirs, ret = 1, laststage = (stage + 1 == nstages);
  1023.  
  1024.     wantdirs = !laststage ||
  1025.         (op & (DIRMOVE | SYMLINK)) ||
  1026.         (nwilds[nstages - 1] == 0);
  1027.  
  1028.     if (!anylev) {
  1029.         prelen = stagel[stage] - lastend;
  1030.         if (pathend - pathbuf + prelen >= MAXPATH) {
  1031.             printf("%s -> %s : search path after %s too long.\n",
  1032.                 from, to, pathbuf);
  1033.             paterr = 1;
  1034.             return(1);
  1035.         }
  1036.         memmove(pathend, lastend, prelen);
  1037.         pathend += prelen;
  1038.         *pathend = '\0';
  1039.         lastend = stagel[stage];
  1040.     }
  1041.  
  1042.     if ((h = checkdir(pathbuf, pathend, 0)) == NULL) {
  1043.         if (stage == 0 || direrr == H_NOREADDIR) {
  1044.             printf("%s -> %s : directory %s does not %s.\n",
  1045.                 from, to, pathbuf, direrr == H_NOREADDIR ?
  1046.                 "allow reads/searches" : "exist");
  1047.             paterr = 1;
  1048.         }
  1049.         return(stage);
  1050.     }
  1051.     di = h->h_di;
  1052.  
  1053.     if (*lastend == ';') {
  1054.         anylev = 1;
  1055.         *start1 = pathend;
  1056.         *len1 = 0;
  1057.         lastend++;
  1058.     }
  1059.  
  1060.     nfils = di->di_nfils;
  1061.  
  1062. #ifndef MSDOS
  1063.     if ((op & MOVE) && !dwritable(h)) {
  1064.         printf("%s -> %s : directory %s does not allow writes.\n",
  1065.             from, to, pathbuf);
  1066.         paterr = 1;
  1067.         goto skiplev;
  1068.     }
  1069. #endif
  1070.  
  1071.     firstesc = strchr(lastend, ESC);
  1072.     if (firstesc == NULL || firstesc > firstwild[stage])
  1073.         firstesc = firstwild[stage];
  1074.     litlen = firstesc - lastend;
  1075.     pf = di->di_fils + (i = ffirst(lastend, litlen, di));
  1076.     if (i < nfils)
  1077.     do {
  1078.         if (
  1079.             (try = trymatch(*pf, lastend)) != 0 &&
  1080.             (
  1081.                 try == 1 ||
  1082.                 match(lastend + litlen, (*pf)->fi_name + litlen,
  1083.                     start1 + anylev, len1 + anylev)
  1084.             ) &&
  1085.             keepmatch(*pf, pathend, &k, 0, wantdirs, laststage)
  1086.         ) {
  1087.             if (!laststage)
  1088.                 ret &= dostage(stager[stage], pathend + k,
  1089.                     start1 + nwilds[stage], len1 + nwilds[stage],
  1090.                     stage + 1, 0);
  1091.             else {
  1092.                 ret = 0;
  1093.                 makerep();
  1094.                 if (badrep(h, *pf, &hto, &nto, &fdel, &flags))
  1095.                     (*pf)->fi_rep = MISTAKE;
  1096.                 else {
  1097.                     (*pf)->fi_rep = p = (REP *)challoc(sizeof(REP), 1);
  1098.                     p->r_flags = flags | patflags;
  1099.                     p->r_hfrom = h;
  1100.                     p->r_ffrom = *pf;
  1101.                     p->r_hto = hto;
  1102.                     p->r_nto = nto;
  1103.                     p->r_fdel = fdel;
  1104.                     p->r_first = p;
  1105.                     p->r_thendo = NULL;
  1106.                     p->r_next = NULL;
  1107.                     lastrep->r_next = p;
  1108.                     lastrep = p;
  1109.                     nreps++;
  1110.                 }
  1111.             }
  1112.         }
  1113.         i++, pf++;
  1114.     } while (i < nfils && strncmp(lastend, (*pf)->fi_name, litlen) == 0);
  1115.  
  1116. skiplev:
  1117.     if (anylev)
  1118.         for (pf = di->di_fils, i = 0; i < nfils; i++, pf++)
  1119.             if (
  1120.                 *((*pf)->fi_name) != '.' &&
  1121. #ifdef MSDOS
  1122.                 ((*pf)->fi_attrib & FA_DIREC) &&
  1123. #endif
  1124.                 keepmatch(*pf, pathend, &k, 1, 1, 0)
  1125.             ) {
  1126.                 *len1 = pathend - *start1 + k;
  1127.                 ret &= dostage(lastend, pathend + k, start1, len1, stage, 1);
  1128.             }
  1129.  
  1130.     return(ret);
  1131. }
  1132.  
  1133.  
  1134. static int trymatch(ffrom, pat)
  1135.     FILEINFO *ffrom;
  1136.     char *pat;
  1137. {
  1138.     char *p;
  1139.  
  1140.     if (ffrom->fi_rep != NULL)
  1141.         return(0);
  1142.  
  1143.     p = ffrom->fi_name;
  1144.  
  1145. #ifdef MSDOS
  1146.     if (*p == '.' || (!matchall && ffrom->fi_attrib & (FA_HIDDEN | FA_SYSTEM)))
  1147.         return(strcmp(pat, p) == 0);
  1148. #else
  1149.     if (*p == '.')
  1150.         if (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))
  1151.             return(strcmp(pat, p) == 0);
  1152.         else if (!matchall && *pat != '.')
  1153.             return(0);
  1154. #endif
  1155.     return(-1);
  1156. }
  1157.  
  1158.  
  1159. static int keepmatch(ffrom, pathend, pk, needslash, dirs, fils)
  1160.     FILEINFO *ffrom;
  1161.     char *pathend;
  1162.     int *pk;
  1163.     int needslash;
  1164.     int dirs, fils;
  1165. {
  1166.     *pk = strlen(ffrom->fi_name);
  1167.     if (pathend - pathbuf + *pk + needslash >= MAXPATH) {
  1168.         *pathend = '\0';
  1169.         printf("%s -> %s : search path %s%s too long.\n",
  1170.             from, to, pathbuf, ffrom->fi_name);
  1171.         paterr = 1;
  1172.         return(0);
  1173.     }
  1174.     strcpy(pathend, ffrom->fi_name);
  1175. #ifdef MSDOS
  1176.     if ((ffrom->fi_attrib & FA_DIREC) ? !dirs : !fils)
  1177. #else
  1178.     getstat(pathbuf, ffrom);
  1179.     if ((ffrom->fi_stflags & FI_ISDIR) ? !dirs : !fils)
  1180. #endif
  1181.         return(0);
  1182.  
  1183.     if (needslash) {
  1184.         strcpy(pathend + *pk, SLASHSTR);
  1185.         (*pk)++;
  1186.     }
  1187.     return(1);
  1188. }
  1189.  
  1190.  
  1191. static int badrep(hfrom, ffrom, phto, pnto, pfdel, pflags)
  1192.     HANDLE *hfrom;
  1193.     FILEINFO *ffrom;
  1194.     HANDLE **phto;
  1195.     char **pnto;
  1196.     FILEINFO **pfdel;
  1197.     int *pflags;
  1198. {
  1199.     char *f = ffrom->fi_name;
  1200.  
  1201.     *pflags = 0;
  1202.     if (
  1203. #ifdef MSDOS
  1204.         (ffrom->fi_attrib & FA_DIREC) &&
  1205. #else
  1206.         (ffrom->fi_stflags & FI_ISDIR) &&
  1207. #endif
  1208.         !(op & (DIRMOVE | SYMLINK))
  1209.     )
  1210.         printf("%s -> %s : source file is a directory.\n", pathbuf, fullrep);
  1211. #ifndef MSDOS
  1212. #ifndef SYSV
  1213.     else if ((ffrom->fi_stflags & FI_LINKERR) && !(op & (MOVE | SYMLINK)))
  1214.         printf("%s -> %s : source file is a badly aimed symbolic link.\n",
  1215.             pathbuf, fullrep);
  1216.     else if ((ffrom->fi_stflags & FI_NODEL) && (op & MOVE))
  1217.         printf("%s -> %s : no delete permission for source file.\n",
  1218.             pathbuf, fullrep);
  1219. #endif
  1220.     else if ((op & (COPY | APPEND)) && access(pathbuf, R_OK))
  1221.         printf("%s -> %s : no read permission for source file.\n",
  1222.             pathbuf, fullrep);
  1223. #endif
  1224.     else if (
  1225.         *f == '.' &&
  1226.         (f[1] == '\0' || strcmp(f, "..") == 0) &&
  1227.         !(op & SYMLINK)
  1228.     )
  1229.         printf("%s -> %s : . and .. can't be renamed.\n", pathbuf, fullrep);
  1230.     else if (repbad || checkto(hfrom, f, phto, pnto, pfdel) || badname(*pnto))
  1231.         printf("%s -> %s : bad new name.\n", pathbuf, fullrep);
  1232.     else if (*phto == NULL)
  1233.         printf("%s -> %s : %s.\n", pathbuf, fullrep,
  1234. #ifndef MSDOS
  1235.             direrr == H_NOREADDIR ?
  1236.             "no read or search permission for target directory" :
  1237. #endif
  1238.             "target directory does not exist");
  1239. #ifndef MSDOS
  1240.     else if (!dwritable(*phto))
  1241.         printf("%s -> %s : no write permission for target directory.\n",
  1242.             pathbuf, fullrep);
  1243. #endif
  1244.     else if (
  1245.         (*phto)->h_di->di_vid != hfrom->h_di->di_vid &&
  1246.         (*pflags = R_ISX, (op & (NORMMOVE | HARDLINK)))
  1247.     )
  1248.         printf("%s -> %s : cross-device move.\n",
  1249.             pathbuf, fullrep);
  1250. #ifndef MSDOS
  1251.     else if (
  1252.         *pflags && (op & MOVE) &&
  1253.         !(ffrom->fi_stflags & FI_ISLNK) &&
  1254.         access(pathbuf, R_OK)
  1255.     )
  1256.         printf("%s -> %s : no read permission for source file.\n",
  1257.             pathbuf, fullrep);
  1258. #ifndef SYSV
  1259.     else if (
  1260.         (op & SYMLINK) &&
  1261.         !(
  1262.             ((*phto)->h_di->di_vid == cwdv && (*phto)->h_di->di_did == cwdd) ||
  1263.             *(hfrom->h_name) == SLASH ||
  1264.             (*pflags |= R_ONEDIRLINK, hfrom->h_di == (*phto)->h_di)
  1265.         )
  1266.     )
  1267.         printf("%s -> %s : symbolic link would be badly aimed.\n",
  1268.             pathbuf, fullrep);
  1269. #endif
  1270. #endif
  1271.     else
  1272.         return(0);
  1273.     badreps++;
  1274.     return(-1);
  1275. }
  1276.  
  1277.  
  1278. static int checkto(hfrom, f, phto, pnto, pfdel)
  1279.     HANDLE *hfrom;
  1280.     char *f;
  1281.     HANDLE **phto;
  1282.     char **pnto;
  1283.     FILEINFO **pfdel;
  1284. {
  1285.     char tpath[MAXPATH + 1];
  1286.     char *pathend;
  1287.     FILEINFO *fdel;
  1288.     int hlen, tlen;
  1289.  
  1290.     if (op & DIRMOVE) {
  1291.         *phto = hfrom;
  1292.         hlen = strlen(hfrom->h_name);
  1293.         pathend = fullrep + hlen;
  1294.         memmove(pathend, fullrep, strlen(fullrep) + 1);
  1295.         memmove(fullrep, hfrom->h_name, hlen);
  1296.         if ((fdel = *pfdel = fsearch(pathend, hfrom->h_di)) != NULL) {
  1297.             *pnto = fdel->fi_name;
  1298. #ifndef MSDOS
  1299.             getstat(fullrep, fdel);
  1300. #endif
  1301.         }
  1302.         else
  1303.             *pnto = mydup(pathend);
  1304.     }
  1305.     else {
  1306.         pathend = getpath(tpath);
  1307.         hlen = pathend - fullrep;
  1308.         *phto = checkdir(tpath, tpath + hlen, 1);
  1309.         if (
  1310.             *phto != NULL &&
  1311.             *pathend != '\0' &&
  1312.             (fdel = *pfdel = fsearch(pathend, (*phto)->h_di)) != NULL &&
  1313. #ifdef MSDOS
  1314.             (fdel->fi_attrib & FA_DIREC)
  1315. #else
  1316.             (getstat(fullrep, fdel), fdel->fi_stflags & FI_ISDIR)
  1317. #endif
  1318.         ) {
  1319.             tlen = strlen(pathend);
  1320.             strcpy(pathend + tlen, SLASHSTR);
  1321.             tlen++;
  1322.             strcpy(tpath + hlen, pathend);
  1323.             pathend += tlen;
  1324.             hlen += tlen;
  1325.             *phto = checkdir(tpath, tpath + hlen, 1);
  1326.         }
  1327.  
  1328.         if (*pathend == '\0') {
  1329.             *pnto = f;
  1330.             if (pathend - fullrep + strlen(f) >= MAXPATH) {
  1331.                 strcpy(fullrep, TOOLONG);
  1332.                 return(-1);
  1333.             }
  1334.             strcat(pathend, f);
  1335.             if (*phto != NULL) {
  1336.                 fdel = *pfdel = fsearch(f, (*phto)->h_di);
  1337. #ifndef MSDOS
  1338.                 if (fdel != NULL)
  1339.                     getstat(fullrep, fdel);
  1340. #endif
  1341.             }
  1342.         }
  1343.         else if (fdel != NULL)
  1344.             *pnto = fdel->fi_name;
  1345.         else
  1346.             *pnto = mydup(pathend);
  1347.     }
  1348.     return(0);
  1349. }
  1350.  
  1351.  
  1352. static char *getpath(tpath)
  1353.     char *tpath;
  1354. {
  1355.     char *pathstart, *pathend, c;
  1356.  
  1357. #ifdef MSDOS
  1358.     if (*fullrep != '\0' && fullrep[1] == ':')
  1359.         pathstart = fullrep + 2;
  1360.     else
  1361. #endif
  1362.         pathstart = fullrep;
  1363.  
  1364.     pathend = pathstart + strlen(pathstart) - 1;
  1365.     while (pathend >= pathstart && *pathend != SLASH)
  1366.         --pathend;
  1367.     pathend++;
  1368.  
  1369.     c = *pathend;
  1370.     *pathend = '\0';
  1371.     strcpy(tpath, fullrep);
  1372.     *pathend = c;
  1373.     return(pathend);
  1374. }
  1375.  
  1376.  
  1377. static int badname(s)
  1378.     char *s;
  1379. {
  1380.     char *ext;
  1381.  
  1382.     return (
  1383. #ifdef MSDOS
  1384.         *s == ' ' ||
  1385.         *s == '.' ||
  1386.         (ext = strchr(s, '.')) - s >= MAXFILE ||
  1387.         (*ext == '.' && strchr(ext + 1, '.') != NULL) ||
  1388.         strlen(ext) >= MAXEXT ||
  1389.         strncmp(s, IDF, STRLEN(IDF)) == 0
  1390. #else
  1391.         (*s == '.' && (s[1] == '\0' || strcmp(s, "..") == 0)) ||
  1392.         strlen(s) > MAXNAMLEN
  1393. #endif
  1394.     );
  1395. }
  1396.  
  1397.  
  1398. #ifndef MSDOS
  1399. static int getstat(ffull, f)
  1400.     char *ffull;
  1401.     FILEINFO *f;
  1402. {
  1403.     struct stat fstat;
  1404.     int flags;
  1405.  
  1406.     if ((flags = f->fi_stflags) & FI_STTAKEN)
  1407.         return(flags & FI_LINKERR);
  1408.     flags |= FI_STTAKEN;
  1409. #ifdef SYSV
  1410.     if (stat(ffull, &fstat)) {
  1411.         fprintf(stderr, "Strange, couldn't stat %s.\n", ffull);
  1412.         quit();
  1413.     }
  1414. #else
  1415.     if (lstat(ffull, &fstat)) {
  1416.         fprintf(stderr, "Strange, couldn't lstat %s.\n", ffull);
  1417.         quit();
  1418.     }
  1419.     if ((flags & FI_INSTICKY) && fstat.st_uid != uid && uid != 0)
  1420.         flags |= FI_NODEL;
  1421.     if ((fstat.st_mode & S_IFMT) == S_IFLNK) {
  1422.         flags |= FI_ISLNK;
  1423.         if (stat(ffull, &fstat)) {
  1424.             f->fi_stflags = flags | FI_LINKERR;
  1425.             return(1);
  1426.         }
  1427.     }
  1428. #endif
  1429.     if ((fstat.st_mode & S_IFMT) == S_IFDIR)
  1430.         flags |= FI_ISDIR;
  1431.     f->fi_stflags = flags;
  1432.     f->fi_mode = fstat.st_mode;
  1433.     return(0);
  1434. }
  1435.  
  1436.  
  1437. static int dwritable(h)
  1438.     HANDLE *h;
  1439. {
  1440.     char *p = h->h_name, *myp, *lastslash = NULL, *pathend;
  1441.     char *pw = &(h->h_di->di_flags), r;
  1442.  
  1443.     if (uid == 0)
  1444.         return(1);
  1445.  
  1446.     if (*pw & DI_KNOWWRITE)
  1447.         return(*pw & DI_CANWRITE);
  1448.  
  1449.     pathend = p + strlen(p);
  1450.     if (*p == '\0')
  1451.         myp = ".";
  1452.     else if (pathend == p + 1)
  1453.         myp = SLASHSTR;
  1454.     else {
  1455.         lastslash = pathend - 1;
  1456.         *lastslash = '\0';
  1457.         myp = p;
  1458.     }
  1459.     r = !access(myp, W_OK) ? DI_CANWRITE : 0;
  1460.     *pw |= DI_KNOWWRITE | r;
  1461.  
  1462.     if (lastslash != NULL)
  1463.         *lastslash = SLASH;
  1464.     return(r);
  1465. }
  1466.  
  1467.  
  1468. static int fwritable(hname, f)
  1469.     char *hname;
  1470.     FILEINFO *f;
  1471. {
  1472.     int r;
  1473.  
  1474.     if (f->fi_stflags & FI_KNOWWRITE)
  1475.         return(f->fi_stflags & FI_CANWRITE);
  1476.  
  1477.     strcpy(fullrep, hname);
  1478.     strcat(fullrep, f->fi_name);
  1479.     r = !access(fullrep, W_OK) ? FI_CANWRITE : 0;
  1480.     f->fi_stflags |= FI_KNOWWRITE | r;
  1481.     return(r);
  1482. }
  1483. #endif
  1484.  
  1485.  
  1486. static FILEINFO *fsearch(s, d)
  1487.     char *s;
  1488.     DIRINFO *d;
  1489. {
  1490.     FILEINFO **fils = d->di_fils;
  1491.     int nfils = d->di_nfils;
  1492.     int first, k, last, res;
  1493.  
  1494.     for(first = 0, last = nfils - 1;;) {
  1495.         if (last < first)
  1496.             return(NULL);
  1497.         k = (first + last) >> 1;
  1498.         if ((res = strcmp(s, fils[k]->fi_name)) == 0)
  1499.             return(fils[k]);
  1500.         if (res < 0)
  1501.             last = k - 1;
  1502.         else
  1503.             first = k + 1;
  1504.     }
  1505. }
  1506.  
  1507.  
  1508. static int ffirst(s, n, d)
  1509.     char *s;
  1510.     int n;
  1511.     DIRINFO *d;
  1512. {
  1513.     int first, k, last, res;
  1514.     FILEINFO **fils = d->di_fils;
  1515.     int nfils = d->di_nfils;
  1516.  
  1517.     if (nfils == 0 || n == 0)
  1518.         return(0);
  1519.     first = 0;
  1520.     last = nfils - 1;
  1521.     for(;;) {
  1522.         k = (first + last) >> 1;
  1523.         res = strncmp(s, fils[k]->fi_name, n);
  1524.         if (first == last)
  1525.             return(res == 0 ? k : nfils);
  1526.         else if (res > 0)
  1527.             first = k + 1;
  1528.         else
  1529.             last = k;
  1530.     }
  1531. }
  1532.  
  1533.  
  1534. #ifdef MSDOS
  1535. /* checkdir and takedir for MS-D*S */
  1536.  
  1537. static HANDLE *checkdir(p, pathend, which)
  1538.     char *p, *pathend;
  1539.     int which;
  1540. {
  1541.     struct ffblk de;
  1542.     DIRID d;
  1543.     DEVID v;
  1544.     HANDLE *h;
  1545.     char *dirstart = p;
  1546.     int fd;
  1547.     int firstfound;
  1548.     DIRINFO *di;
  1549.  
  1550.     if (hsearch(p, which, &h))
  1551.         if (h->h_di == NULL) {
  1552.             direrr = h->h_err;
  1553.             return(NULL);
  1554.         }
  1555.         else
  1556.             return(h);
  1557.  
  1558.     if (*p == '\0' || p[1] != ':')
  1559.         v = curdisk;
  1560.     else {
  1561.         dirstart += 2;
  1562.         v = mylower(p[0]) - 'a';
  1563.         if (v < 0 || v >= maxdisk)
  1564.             return(NULL);
  1565.     }
  1566.  
  1567.     if (patch.ph_safeid) {
  1568.         strcpy(pathend, IDF);
  1569.         strcpy(pathend + STRLEN(IDF), "*");
  1570.         if (findfirst(p, &de, 0)) {
  1571.             if ((d = ndirs) == 1000) {
  1572.                 fprintf(stderr, "Too many different directories.\n");
  1573.                 quit();
  1574.             }
  1575.             sprintf(pathend + STRLEN(IDF), "%03d", d);
  1576.             if ((fd = _creat(p, 0)) < 0) {
  1577.                 direrr = h->h_err = H_NODIR;
  1578.                 return(NULL);
  1579.             }
  1580.             _close(fd);
  1581.             strcpy(pathend, "*.*");
  1582.             if (findfirst(p, &de, FA_DIREC | FA_SYSTEM | FA_HIDDEN))
  1583.                 h->h_di = dadd(v, d);
  1584.             else
  1585.                 takedir(&de, h->h_di = dadd(v, d));
  1586.         }
  1587.         else if ((d = atoi(de.ff_name + STRLEN(IDF))) < ndirs)
  1588.             h->h_di = dirs[d];
  1589.         else {
  1590.             strcpy(pathend, de.ff_name);
  1591.             fprintf(stderr, "Strange dir-id file encountered: %s.\n", p);
  1592.             quit();
  1593.         }
  1594.         *pathend = '\0';
  1595.     }
  1596.     else {
  1597.         strcpy(pathend, "*.*");
  1598.         firstfound = !findfirst(p, &de, FA_DIREC | FA_SYSTEM | FA_HIDDEN);
  1599.         *pathend = '\0';
  1600.         if (firstfound) {
  1601.             v = DRIVENO(&de);
  1602.             d = CLUSTNO(&de);
  1603.         }
  1604.         else {
  1605.             strcpy(pathend, "T.D");
  1606.             if (mkdir(p)) {
  1607.                 *pathend = '\0';
  1608.                 direrr = h->h_err = H_NODIR;
  1609.                 return(NULL);
  1610.             }
  1611.             strcpy(pathend, "*.*");
  1612.             firstfound = !findfirst(p, &de, FA_DIREC | FA_SYSTEM | FA_HIDDEN);
  1613.             *pathend = '\0';
  1614.             v = DRIVENO(&de);
  1615.             d = CLUSTNO(&de);
  1616.             rmdir(p);
  1617.             if (!firstfound || d != 0) {
  1618.                 fprintf(stderr,
  1619.                     "Strange, %s does not seem to be a root dir.\n",
  1620.                     p);
  1621.                 quit();
  1622.             }
  1623.         }
  1624.  
  1625.         if ((di = dsearch(v, d)) == NULL)
  1626.             if (firstfound)
  1627.                 takedir(&de, h->h_di = dadd(v, d));
  1628.             else
  1629.                 h->h_di = dadd(v, d);
  1630.         else
  1631.             h->h_di = di;
  1632.     }
  1633.  
  1634.     return(h);
  1635. }
  1636.  
  1637.  
  1638. static void takedir(pff, di)
  1639.     struct ffblk *pff;
  1640.     DIRINFO *di;
  1641. {
  1642.     int cnt, room, namlen, needdot;
  1643.     FILEINFO **fils, *f;
  1644.     char c, *p, *p1;
  1645.  
  1646.     room = INITROOM;
  1647.     di->di_fils = fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1648.     cnt = 0;
  1649.     do {
  1650.         if (strnicmp(pff->ff_name, IDF, STRLEN(IDF)) == 0)
  1651.             continue;
  1652.         if (cnt == room) {
  1653.             room *= 2;
  1654.             fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1655.             memcpy(fils, di->di_fils, cnt * sizeof(FILEINFO *));
  1656.             chgive(di->di_fils, cnt * sizeof(FILEINFO *));
  1657.             di->di_fils = fils;
  1658.             fils = di->di_fils + cnt;
  1659.         }
  1660.         needdot = 1;
  1661.         for (p = pff->ff_name, namlen = 0; (c = *p) != '\0'; p++, namlen++)
  1662.             if (c == '.')
  1663.                 needdot = 0;
  1664.         *fils = f = (FILEINFO *)challoc(sizeof(FILEINFO), 1);
  1665.         f->fi_name = p = (char *)challoc(namlen + needdot + 1, 0);
  1666.         for (p1 = pff->ff_name; (c = *p1) != '\0'; p1++)
  1667.             *(p++) = mylower(c);
  1668.         if (needdot)
  1669.             *(p++) = '.';
  1670.         *p = '\0';
  1671.         f->fi_attrib = pff->ff_attrib;
  1672.         f->fi_rep = NULL;
  1673.         cnt++;
  1674.         fils++;
  1675.     } while (findnext(pff) == 0);
  1676.     qsort(di->di_fils, cnt, sizeof(FILEINFO *), fcmp);
  1677.     di->di_nfils = cnt;
  1678. }
  1679.  
  1680. #else
  1681. /* checkdir, takedir for Un*x */
  1682.  
  1683. static HANDLE *checkdir(p, pathend, which)
  1684.     char *p, *pathend;
  1685.     int which;
  1686. {
  1687.     struct stat dstat;
  1688.     DIRID d;
  1689.     DEVID v;
  1690.     DIRINFO **newdirs, *di;
  1691.     int nfils;
  1692.     FILEINFO **fils;
  1693.     char *myp, *lastslash = NULL;
  1694.     int sticky;
  1695.     HANDLE *h;
  1696.  
  1697.     if (hsearch(p, which, &h))
  1698.         if (h->h_di == NULL) {
  1699.             direrr = h->h_err;
  1700.             return(NULL);
  1701.         }
  1702.         else
  1703.             return(h);
  1704.  
  1705.     if (*p == '\0')
  1706.         myp = ".";
  1707.     else if (pathend == p + 1)
  1708.         myp = SLASHSTR;
  1709.     else {
  1710.         lastslash = pathend - 1;
  1711.         *lastslash = '\0';
  1712.         myp = p;
  1713.     }
  1714.  
  1715.     if (stat(myp, &dstat) || (dstat.st_mode & S_IFMT) != S_IFDIR)
  1716.         direrr = h->h_err = H_NODIR;
  1717.     else if (access(myp, R_OK | X_OK))
  1718.         direrr = h->h_err = H_NOREADDIR;
  1719.     else {
  1720.         direrr = 0;
  1721.         sticky = (dstat.st_mode & S_ISVTX) && uid != 0 && uid != dstat.st_uid ?
  1722.             FI_INSTICKY : 0;
  1723.         v = dstat.st_dev;
  1724.         d = dstat.st_ino;
  1725.  
  1726.         if ((di = dsearch(v, d)) == NULL)
  1727.             takedir(myp, di = dadd(v, d), sticky);
  1728.     }
  1729.  
  1730.     if (lastslash != NULL)
  1731.         *lastslash = SLASH;
  1732.     if (direrr != 0)
  1733.         return(NULL);
  1734.     h->h_di = di;
  1735.     return(h);
  1736. }
  1737.  
  1738.  
  1739. static void takedir(p, di, sticky)
  1740.     char *p;
  1741.     DIRINFO *di;
  1742.     int sticky;
  1743. {
  1744.     int cnt, room;
  1745.     DIRENTRY *dp;
  1746.     FILEINFO *f, **fils;
  1747.     DIR *dirp;
  1748.  
  1749.     if ((dirp = opendir(p)) == NULL) {
  1750.         fprintf(stderr, "Strange, can't scan %s.\n", p);
  1751.         quit();
  1752.     }
  1753.     room = INITROOM;
  1754.     di->di_fils = fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1755.     cnt = 0;
  1756.     while ((dp = readdir(dirp)) != NULL) {
  1757.         if (cnt == room) {
  1758.             room *= 2;
  1759.             fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1760.             memcpy(fils, di->di_fils, cnt * sizeof(FILEINFO *));
  1761.             chgive(di->di_fils, cnt * sizeof(FILEINFO *));
  1762.             di->di_fils = fils;
  1763.             fils = di->di_fils + cnt;
  1764.         }
  1765.         *fils = f = (FILEINFO *)challoc(sizeof(FILEINFO), 1);
  1766.         f->fi_name = mydup(dp->d_name);
  1767.         f->fi_stflags = sticky;
  1768.         f->fi_rep = NULL;
  1769.         cnt++;
  1770.         fils++;
  1771.     }
  1772.     closedir(dirp);
  1773.     qsort(di->di_fils, cnt, sizeof(FILEINFO *), fcmp);
  1774.     di->di_nfils = cnt;
  1775. }
  1776.  
  1777. /* end of Un*x checkdir, takedir; back to general program */
  1778. #endif
  1779.  
  1780.  
  1781. static int fcmp(pf1, pf2)
  1782.     FILEINFO **pf1, **pf2;
  1783. {
  1784.         return(strcmp((*pf1)->fi_name, (*pf2)->fi_name));
  1785. }
  1786.  
  1787.  
  1788. static HANDLE *hadd(n)
  1789.     char *n;
  1790. {
  1791.     HANDLE **newhandles, *h;
  1792.  
  1793.     if (nhandles == handleroom) {
  1794.         handleroom *= 2;
  1795.         newhandles = (HANDLE **)myalloc(handleroom * sizeof(HANDLE *));
  1796.         memcpy(newhandles, handles, nhandles * sizeof(HANDLE *));
  1797.         chgive(handles, nhandles * sizeof(HANDLE *));
  1798.         handles = newhandles;
  1799.     }
  1800.     handles[nhandles++] = h = (HANDLE *)challoc(sizeof(HANDLE), 1);
  1801.     h->h_name = (char *)challoc(strlen(n) + 1, 0);
  1802.     strcpy(h->h_name, n);
  1803.     h->h_di = NULL;
  1804.     return(h);
  1805. }
  1806.  
  1807.  
  1808. static int hsearch(n, which, pret)
  1809.     char *n;
  1810.     int which;
  1811.     HANDLE **pret;
  1812. {
  1813.     int i;
  1814.     HANDLE **ph;
  1815.  
  1816.     if (strcmp(n, lasthandle[which]->h_name) == 0) {
  1817.         *pret = lasthandle[which];
  1818.         return(1);
  1819.     }
  1820.  
  1821.     for(i = 0, ph = handles; i < nhandles; i++, ph++)
  1822.         if (strcmp(n, (*ph)->h_name) == 0) {
  1823.             lasthandle[which] = *pret = *ph;
  1824.             return(1);
  1825.         }
  1826.  
  1827.     lasthandle[which] = *pret = hadd(n);
  1828.     return(0);
  1829. }
  1830.  
  1831.  
  1832. static DIRINFO *dadd(v, d)
  1833.     DEVID v;
  1834.     DIRID d;
  1835. {
  1836.     DIRINFO *di;
  1837.     DIRINFO **newdirs;
  1838.  
  1839.     if (ndirs == dirroom) {
  1840.         dirroom *= 2;
  1841.         newdirs = (DIRINFO **)myalloc(dirroom * sizeof(DIRINFO *));
  1842.         memcpy(newdirs, dirs, ndirs * sizeof(DIRINFO *));
  1843.         chgive(dirs, ndirs * sizeof(DIRINFO *));
  1844.         dirs = newdirs;
  1845.     }
  1846.     dirs[ndirs++] = di = (DIRINFO *)challoc(sizeof(DIRINFO), 1);
  1847.     di->di_vid = v;
  1848.     di->di_did = d;
  1849.     di->di_nfils = 0;
  1850.     di->di_fils = NULL;
  1851.     di->di_flags = 0;
  1852.     return(di);
  1853. }
  1854.  
  1855.  
  1856. static DIRINFO *dsearch(v, d)
  1857.     DEVID v;
  1858.     DIRID d;
  1859. {
  1860.     int i;
  1861.     DIRINFO *di;
  1862.  
  1863.     for(i = 0, di = *dirs; i < ndirs; i++, di++)
  1864.         if (v == di->di_vid && d == di->di_did)
  1865.             return(di);
  1866.     return(NULL);
  1867. }
  1868.  
  1869.  
  1870. static int match(pat, s, start1, len1)
  1871.     char *pat, *s, **start1;
  1872.     int *len1;
  1873. {
  1874.     char c, *olds;
  1875.  
  1876.     *start1 = 0;
  1877.     for(;;)
  1878.         switch (c = *pat) {
  1879.         case '\0':
  1880.         case SLASH:
  1881.             return(*s == '\0');
  1882. #ifdef MSDOS
  1883.         case '!':
  1884.             *start1 = olds = s;
  1885.             if ((s = strchr(s, '.')) == NULL)
  1886.                 return(0);
  1887.             s++;
  1888.             *len1 = s - olds;
  1889.             if ((c = *(++pat)) == '\0') {
  1890.                 *len1 += strlen(s);
  1891.                 return(1);
  1892.             }
  1893.             for ( ; !match(pat, s, start1 + 1, len1 + 1); (*len1)++, s++)
  1894.                 if (*s == '\0')
  1895.                     return(0);
  1896.             return(1);
  1897. #endif
  1898.         case '*':
  1899.             *start1 = s;
  1900.             if ((c = *(++pat)) == '\0') {
  1901.                 *len1 = strlen(s);
  1902.                 return(1);
  1903.             }
  1904.             else {
  1905.                 for (*len1=0; !match(pat, s, start1+1, len1+1); (*len1)++, s++)
  1906.                     if (
  1907. #ifdef MSDOS
  1908.                         *s == '.' ||
  1909. #endif
  1910.                         *s == '\0'
  1911.                     )
  1912.                         return(0);
  1913.                 return(1);
  1914.             }
  1915.         case '?':
  1916.             if (
  1917. #ifdef MSDOS
  1918.                 *s == '.' ||
  1919. #endif
  1920.                 *s == '\0'
  1921.             )
  1922.                 return(0);
  1923.             *(start1++) = s;
  1924.             *(len1++) = 1;
  1925.             pat++;
  1926.             s++;
  1927.             break;
  1928.         case '[':
  1929.             {
  1930.                 int matched = 0, notin = 0, inrange = 0;
  1931.                 char prevc = '\0';
  1932.  
  1933.                 if ((c = *(++pat)) == '^') {
  1934.                     notin = 1;
  1935.                     c = *(++pat);
  1936.                 }
  1937.                 while (c != ']') {
  1938.                     if (c == '-' && !inrange)
  1939.                         inrange = 1;
  1940.                     else {
  1941.                         if (c == ESC) {
  1942.                             c = *(++pat);
  1943.                         }
  1944.                         if (inrange) {
  1945.                             if (*s >= prevc && *s <= c)
  1946.                                 matched = 1;
  1947.                             inrange = 0;
  1948.                         }
  1949.                         else if (c == *s)
  1950.                             matched = 1;
  1951.                         prevc = c;
  1952.                     }
  1953.                     c = *(++pat);
  1954.                 }
  1955.                 if (inrange && *s >= prevc)
  1956.                     matched = 1;
  1957.                 if (!(matched ^ notin))
  1958.                     return(0);
  1959.                 *(start1++) = s;
  1960.                 *(len1++) = 1;
  1961.                 pat++;
  1962.                 s++;
  1963.             }
  1964.             break;
  1965.         case ESC:
  1966.             c = *(++pat);
  1967.         default:
  1968.             if (c == *s) {
  1969.                  pat++;
  1970.                 s++;
  1971.             }
  1972.             else
  1973.                 return(0);
  1974.         }
  1975. }
  1976.  
  1977.  
  1978. static void makerep()
  1979. {
  1980.     int l, x;
  1981. #ifndef MSDOS
  1982.     int i, cnv;
  1983.     char *q;
  1984. #endif
  1985.     char *p, *pat, c, pc;
  1986.  
  1987.     repbad = 0;
  1988.     p = fullrep;
  1989.     for (pat = to, l = 0; (c = *pat) != '\0'; pat++, l++) {
  1990.         if (c == '=') {
  1991.             c = *(++pat);
  1992. #ifndef MSDOS
  1993.             if (c == 'l') {
  1994.                 cnv = LOWER;
  1995.                 c = *(++pat);
  1996.             }
  1997.             else if (c == 'u') {
  1998.                 cnv = UPPER;
  1999.                 c = *(++pat);
  2000.             }
  2001.             else
  2002.                 cnv = STAY;
  2003. #endif
  2004.             for(x = 0; ;x *= 10) {
  2005.                 x += c - '0';
  2006.                 c = *(pat+1);
  2007.                 if (!isdigit(c))
  2008.                     break;
  2009.                 pat++;
  2010.             }
  2011.             --x;
  2012.             if (l + len[x] >= MAXPATH)
  2013.                 goto toolong;
  2014. #ifdef MSDOS
  2015.             if (
  2016.                 *(start[x]) == '.' &&
  2017.                 (
  2018.                     p == fullrep ||
  2019.                     *(p - 1) == SLASH
  2020.                 )
  2021.             ) {
  2022.                 repbad = 1;
  2023.                 if (l + STRLEN(EMPTY) >= MAXPATH)
  2024.                     goto toolong;
  2025.                 strcpy(p, EMPTY);
  2026.                 p += STRLEN(EMPTY);
  2027.                 l += STRLEN(EMPTY);
  2028.             }
  2029. #else
  2030.             switch (cnv) {
  2031.             case STAY:
  2032. #endif
  2033.                 memmove(p, start[x], len[x]);
  2034.                 p += len[x];
  2035. #ifndef MSDOS
  2036.                 break;
  2037.             case LOWER:
  2038.                 for (i = len[x], q = start[x]; i > 0; i--, p++, q++)
  2039.                     *p = mylower(*q);
  2040.                 break;
  2041.             case UPPER:
  2042.                 for (i = len[x], q = start[x]; i > 0; i--, p++, q++)
  2043.                     *p = myupper(*q);
  2044.             }
  2045. #endif
  2046.         }
  2047.         else {
  2048.             if (c == ESC)
  2049.                 c = *(++pat);
  2050.             if (l == MAXPATH)
  2051.                 goto toolong;
  2052.             if (
  2053.                 (
  2054. #ifdef MSDOS
  2055.                     c == '.' ||
  2056. #endif
  2057.                     c == SLASH
  2058.                 ) &&
  2059.                 (
  2060.                     p == fullrep ? pat != to :
  2061.                     (
  2062.                         (
  2063.                             (pc = *(p - 1)) == SLASH
  2064. #ifdef MSDOS
  2065.                             || pc == ':'
  2066. #endif
  2067.                         ) &&
  2068.                          *(pat - 1) != pc
  2069.                     )
  2070.                 )
  2071.             ) {
  2072.                 repbad = 1;
  2073.                 if (l + STRLEN(EMPTY) >= MAXPATH)
  2074.                     goto toolong;
  2075.                 strcpy(p, EMPTY);
  2076.                 p += STRLEN(EMPTY);
  2077.                 l += STRLEN(EMPTY);
  2078.             }
  2079.             *(p++)= c;
  2080.         }
  2081.     }
  2082.     if (p == fullrep) {
  2083.         strcpy(fullrep, EMPTY);
  2084.         repbad = 1;
  2085.     }
  2086.     *(p++) = '\0';
  2087.     return;
  2088.  
  2089. toolong:
  2090.     repbad = 1;
  2091.     strcpy(fullrep, TOOLONG);
  2092. }
  2093.  
  2094.  
  2095. static void checkcollisions()
  2096. {
  2097.     REPDICT *rd, *prd;
  2098.     REP *p, *q;
  2099.     int i, mult, oldnreps;
  2100.  
  2101.     if (nreps == 0)
  2102.         return;
  2103.     rd = (REPDICT *)myalloc(nreps * sizeof(REPDICT));
  2104.     for (
  2105.         q = &hrep, p = q->r_next, prd = rd, i = 0;
  2106.         p != NULL;
  2107.         q = p, p = p->r_next, prd++, i++
  2108.     ) {
  2109.         prd->rd_p = p;
  2110.         prd->rd_dto = p->r_hto->h_di;
  2111.         prd->rd_nto = p->r_nto;
  2112.         prd->rd_i = i;
  2113.     }
  2114.     qsort(rd, nreps, sizeof(REPDICT), rdcmp);
  2115.     mult = 0;
  2116.     for (i = 0, prd = rd, oldnreps = nreps; i < oldnreps; i++, prd++)
  2117.         if (
  2118.             i < oldnreps - 1 &&
  2119.             prd->rd_dto == (prd + 1)->rd_dto &&
  2120.             strcmp(prd->rd_nto, (prd + 1)->rd_nto) == 0
  2121.         ) {
  2122.             if (!mult)
  2123.                 mult = 1;
  2124.             else
  2125.                 printf(" , ");
  2126.             printf("%s%s", prd->rd_p->r_hfrom->h_name,
  2127.                 prd->rd_p->r_ffrom->fi_name);
  2128.             prd->rd_p->r_flags |= R_SKIP;
  2129.             prd->rd_p->r_ffrom->fi_rep = MISTAKE;
  2130.             nreps--;
  2131.             badreps++;
  2132.         }
  2133.         else if (mult) {
  2134.             prd->rd_p->r_flags |= R_SKIP;
  2135.             prd->rd_p->r_ffrom->fi_rep = MISTAKE;
  2136.             nreps--;
  2137.             badreps++;
  2138.             printf(" , %s%s -> %s%s : collision.\n",
  2139.                 prd->rd_p->r_hfrom->h_name, prd->rd_p->r_ffrom->fi_name,
  2140.                 prd->rd_p->r_hto->h_name, prd->rd_nto);
  2141.             mult = 0;
  2142.         }
  2143.     chgive(rd, oldnreps * sizeof(REPDICT));
  2144. }
  2145.  
  2146.  
  2147. static int rdcmp(rd1, rd2)
  2148.     REPDICT *rd1, *rd2;
  2149. {
  2150.     int ret;
  2151.  
  2152.     if (
  2153.         (ret = rd1->rd_dto - rd2->rd_dto) == 0 &&
  2154.         (ret = strcmp(rd1->rd_nto, rd2->rd_nto)) == 0
  2155.     )
  2156.         ret = rd1->rd_i - rd2->rd_i;
  2157.     return(ret);
  2158. }
  2159.  
  2160.  
  2161. static void findorder()
  2162. {
  2163.     REP *p, *q, *t, *first, *pred;
  2164.     FILEINFO *fi;
  2165.  
  2166.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next)
  2167.         if (p->r_flags & R_SKIP) {
  2168.             q->r_next = p->r_next;
  2169.             p = q;
  2170.         }
  2171.         else if (
  2172.             (fi = p->r_fdel) == NULL ||
  2173.             (pred = fi->fi_rep) == NULL ||
  2174.             pred == MISTAKE
  2175.         )
  2176.             continue;
  2177.         else if ((first = pred->r_first) == p) {
  2178.             p->r_flags |= R_ISCYCLE;
  2179.             pred->r_flags |= R_ISALIASED;
  2180.             if (op & MOVE)
  2181.                 p->r_fdel = NULL;
  2182.         }
  2183.         else {
  2184.             if (op & MOVE)
  2185.                 p->r_fdel = NULL;
  2186.             while (pred->r_thendo != NULL)
  2187.                 pred = pred->r_thendo;
  2188.             pred->r_thendo = p;
  2189.             for (t = p; t != NULL; t = t->r_thendo)
  2190.                 t->r_first = first;
  2191.             q->r_next = p->r_next;
  2192.             p = q;
  2193.         }
  2194. }
  2195.  
  2196.  
  2197. static void nochains()
  2198. {
  2199.     REP *p, *q;
  2200.  
  2201.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next)
  2202.         if (p->r_flags & R_ISCYCLE || p->r_thendo != NULL) {
  2203.             printchain(p);
  2204.             printf("%s%s : no chain copies allowed.\n",
  2205.                 p->r_hto->h_name, p->r_nto);
  2206.             q->r_next = p->r_next;
  2207.             p = q;
  2208.         }
  2209. }
  2210.  
  2211.  
  2212. static void printchain(p)
  2213.     REP *p;
  2214. {
  2215.     if (p->r_thendo != NULL)
  2216.         printchain(p->r_thendo);
  2217.     printf("%s%s -> ", p->r_hfrom->h_name, p->r_ffrom->fi_name);
  2218.     badreps++;
  2219.     nreps--;
  2220.     p->r_ffrom->fi_rep = MISTAKE;
  2221. }
  2222.  
  2223.  
  2224. static void scandeletes(pkilldel)
  2225.     int (*pkilldel)();
  2226. {
  2227.     REP *p, *q, *n;
  2228.  
  2229.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next) {
  2230.         if (p->r_fdel != NULL)
  2231.             while ((*pkilldel)(p)) {
  2232.                 nreps--;
  2233.                 p->r_ffrom->fi_rep = MISTAKE;
  2234.                 if ((n = p->r_thendo) != NULL) {
  2235.                     if (op & MOVE)
  2236.                         n->r_fdel = p->r_ffrom;
  2237.                     n->r_next = p->r_next;
  2238.                     q->r_next = p = n;
  2239.                 }
  2240.                 else {
  2241.                     q->r_next = p->r_next;
  2242.                     p = q;
  2243.                     break;
  2244.                 }
  2245.             }
  2246.     }
  2247. }
  2248.  
  2249.  
  2250. static int baddel(p)
  2251.     REP *p;
  2252. {
  2253.     HANDLE *hfrom = p->r_hfrom, *hto = p->r_hto;
  2254.     FILEINFO *fto = p->r_fdel;
  2255.     char *t = fto->fi_name, *f = p->r_ffrom->fi_name;
  2256.     char *hnf = hfrom->h_name, *hnt = hto->h_name;
  2257.  
  2258.     if (delstyle == NODEL && !(p->r_flags & R_DELOK) && !(op & APPEND))
  2259.         printf("%s%s -> %s%s : old %s%s would have to be %s.\n",
  2260.             hnf, f, hnt, t, hnt, t,
  2261.             (op & OVERWRITE) ? "overwritten" : "deleted");
  2262.     else if (fto->fi_rep == MISTAKE)
  2263.         printf("%s%s -> %s%s : old %s%s was to be done first.\n",
  2264.             hnf, f, hnt, t, hnt, t);
  2265.     else if (
  2266. #ifdef MSDOS
  2267.         fto->fi_attrib & FA_DIREC
  2268. #else
  2269.         fto->fi_stflags & FI_ISDIR
  2270. #endif
  2271.     )
  2272.         printf("%s%s -> %s%s : %s%s%s is a directory.\n",
  2273.             hnf, f, hnt, t, (op & APPEND) ? "" : "old ", hnt, t);
  2274. #ifndef MSDOS
  2275.     else if ((fto->fi_stflags & FI_NODEL) && !(op & (APPEND | OVERWRITE)))
  2276.         printf("%s%s -> %s%s : old %s%s lacks delete permission.\n",
  2277.             hnf, f, hnt, t, hnt, t);
  2278. #endif
  2279.     else if (
  2280.         (op & (APPEND | OVERWRITE)) &&
  2281. #ifdef MSDOS
  2282.         fto->fi_attrib & FA_RDONLY
  2283. #else
  2284.         !fwritable(hnt, fto)
  2285. #endif
  2286.     ) {
  2287.         printf("%s%s -> %s%s : %s%s %s.\n",
  2288.             hnf, f, hnt, t, hnt, t,
  2289. #ifndef MSDOS
  2290. #ifndef SYSV
  2291.             fto->fi_stflags & FI_LINKERR ?
  2292.             "is a badly aimed symbolic link" :
  2293. #endif
  2294. #endif
  2295.             "lacks write permission");
  2296.     }
  2297.     else
  2298.         return(0);
  2299.     badreps++;
  2300.     return(1);
  2301. }
  2302.  
  2303.  
  2304. static int skipdel(p)
  2305.     REP *p;
  2306. {
  2307.     if (p->r_flags & R_DELOK)
  2308.         return(0);
  2309.     fprintf(stderr, "%s%s -> %s%s : ",
  2310.         p->r_hfrom->h_name, p->r_ffrom->fi_name,
  2311.         p->r_hto->h_name, p->r_nto);
  2312.     if (
  2313. #ifdef MSDOS
  2314.         p->r_fdel->fi_attrib & FA_RDONLY
  2315. #else
  2316. #ifndef SYSV
  2317.         !(p->r_ffrom->fi_stflags & FI_ISLNK) &&
  2318. #endif
  2319.         !fwritable(p->r_hto->h_name, p->r_fdel)
  2320. #endif
  2321.     )
  2322.         fprintf(stderr, "old %s%s lacks write permission. delete it",
  2323.             p->r_hto->h_name, p->r_nto);
  2324.     else
  2325.         fprintf(stderr, "%s old %s%s",
  2326.             (op & OVERWRITE) ? "overwrite" : "delete",
  2327.             p->r_hto->h_name, p->r_nto);
  2328.     return(!getreply("? ", -1));
  2329. }
  2330.  
  2331.  
  2332. static void goonordie()
  2333. {
  2334.     if ((paterr || badreps) && nreps > 0) {
  2335.         fprintf(stderr, "Not everything specified can be done.");
  2336.         if (badstyle == ABORTBAD) {
  2337.             fprintf(stderr, " Aborting.\n");
  2338.             exit(1);
  2339.         }
  2340.         else if (badstyle == SKIPBAD)
  2341.             fprintf(stderr, " Proceeding with the rest.\n");
  2342.         else if (!getreply(" Proceed with the rest? ", -1))
  2343.             exit(1);
  2344.     }
  2345. }
  2346.  
  2347.  
  2348. static void doreps()
  2349. {
  2350.     char *fstart;
  2351.     int k, printaliased = 0, alias;
  2352.     REP *first, *p;
  2353.     long aliaslen;
  2354.  
  2355. #ifdef MSDOS
  2356.     ctrlbrk(breakrep);
  2357. #else
  2358.     signal(SIGINT, breakrep);
  2359. #endif
  2360.  
  2361.     for (first = hrep.r_next, k = 0; first != NULL; first = first->r_next) {
  2362.         for (p = first; p != NULL; p = p->r_thendo, k++) {
  2363.             if (gotsig) {
  2364.                 fflush(stdout);
  2365.                 fprintf(stderr, "User break.\n");
  2366.                 printaliased = snap(first, p);
  2367.                 gotsig = 0;
  2368.             }
  2369.             strcpy(fullrep, p->r_hto->h_name);
  2370.             strcat(fullrep, p->r_nto);
  2371.             if (!noex && (p->r_flags & R_ISCYCLE))
  2372.                 if (op & APPEND)
  2373.                     aliaslen = appendalias(first, p, &printaliased);
  2374.                 else
  2375.                     alias = movealias(first, p, &printaliased);
  2376.             strcpy(pathbuf, p->r_hfrom->h_name);
  2377.             fstart = pathbuf + strlen(pathbuf);
  2378.             if ((p->r_flags & R_ISALIASED) && !(op & APPEND))
  2379.                 sprintf(fstart, "%s%03d", TEMP, alias);
  2380.             else
  2381.                 strcpy(fstart, p->r_ffrom->fi_name);
  2382.             if (!noex) {
  2383.                 if (p->r_fdel != NULL && !(op & (APPEND | OVERWRITE)))
  2384.                     myunlink(fullrep, p->r_fdel);
  2385.                 if (
  2386.                     (op & (COPY | APPEND)) ?
  2387.                         copy(p->r_ffrom,
  2388.                             p->r_flags & R_ISALIASED ? aliaslen : -1L) :
  2389. #ifndef MSDOS
  2390.                     (op & HARDLINK) ?
  2391.                         link(pathbuf, fullrep) :
  2392. #ifndef SYSV
  2393.                     (op & SYMLINK) ?
  2394.                         symlink((p->r_flags & R_ONEDIRLINK) ? fstart : pathbuf,
  2395.                             fullrep) :
  2396. #endif
  2397. #endif
  2398.                     p->r_flags & R_ISX ?
  2399.                         copymove(p) :
  2400.                     /* move */
  2401.                         rename(pathbuf, fullrep)
  2402.                 ) {
  2403.                     fprintf(stderr,
  2404.                         "%s -> %s has failed.\n", pathbuf, fullrep);
  2405.                     printaliased = snap(first, p);
  2406.                 }
  2407.             }
  2408.             if (verbose || noex) {
  2409.                 if (p->r_flags & R_ISALIASED && !printaliased)
  2410.                     strcpy(fstart, p->r_ffrom->fi_name);
  2411.                 fprintf(outfile, "%s %c%c %s%s%s\n",
  2412.                     pathbuf,
  2413.                     p->r_flags & R_ISALIASED ? '=' : '-',
  2414.                     p->r_flags & R_ISCYCLE ? '^' : '>',
  2415.                     fullrep,
  2416.                     (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "",
  2417.                     noex ? "" : " : done");
  2418.             }
  2419.         }
  2420.         printaliased = 0;
  2421.     }
  2422.     if (k != nreps)
  2423.         fprintf(stderr, "Strange, did %d reps; %d were expected.\n",
  2424.             k, nreps);
  2425.     if (k == 0)
  2426.         fprintf(stderr, "Nothing done.\n");
  2427. }
  2428.  
  2429.  
  2430. static long appendalias(first, p, pprintaliased)
  2431.     REP *first, *p;
  2432.     int *pprintaliased;
  2433. {
  2434.     long ret;
  2435.  
  2436. #ifdef MSDOS
  2437.     int fd;
  2438.  
  2439.     if ((fd = open(fullrep, O_RDONLY | O_BINARY, 0)) < 0) {
  2440.         fprintf(stderr, "stat on %s has failed.\n", fullrep);
  2441.         *pprintaliased = snap(first, p);
  2442.     }
  2443.     else {
  2444.         ret = filelength(fd);
  2445.         close(fd);
  2446.     }
  2447. #else
  2448.     struct stat fstat;
  2449.  
  2450.     if (stat(fullrep, &fstat)) {
  2451.         fprintf(stderr, "append cycle stat on %s has failed.\n", fullrep);
  2452.         *pprintaliased = snap(first, p);
  2453.     }
  2454.     else
  2455.         ret = fstat.st_size;
  2456. #endif
  2457.  
  2458.     return(ret);
  2459. }
  2460.  
  2461.  
  2462. static int movealias(first, p, pprintaliased)
  2463.     REP *first, *p;
  2464.     int *pprintaliased;
  2465. {
  2466.     char *fstart;
  2467.     int ret;
  2468.  
  2469.     strcpy(pathbuf, p->r_hto->h_name);
  2470.     fstart = pathbuf + strlen(pathbuf);
  2471.     strcpy(fstart, TEMP);
  2472.     for (
  2473.         ret = 0;
  2474.         sprintf(fstart + STRLEN(TEMP), "%03d", ret),
  2475.         fsearch(fstart, p->r_hto->h_di) != NULL;
  2476.         ret++
  2477.     )
  2478.         ;
  2479.     if (rename(fullrep, pathbuf)) {
  2480.         fprintf(stderr,
  2481.             "%s -> %s has failed.\n", fullrep, pathbuf);
  2482.         *pprintaliased = snap(first, p);
  2483.     }
  2484.     return(ret);
  2485. }
  2486.  
  2487.  
  2488. static int snap(first, p)
  2489.     REP *first, *p;
  2490. {
  2491.     char fname[80];
  2492.     int redirected = 0;
  2493.  
  2494.     if (noex)
  2495.         exit(1);
  2496.  
  2497.     failed = 1;
  2498. #ifdef MSDOS
  2499.     ctrlbrk((int (*)())breakstat);
  2500. #else
  2501.     signal(SIGINT, breakstat);
  2502. #endif
  2503.     if (
  2504.         badstyle == ASKBAD &&
  2505.         isatty(fileno(stdout)) &&
  2506.         getreply("Redirect standard output to file? ", 0)
  2507.     ) {
  2508.         redirected = 1;
  2509. #ifndef MSDOS
  2510.         umask(oldumask);
  2511. #endif
  2512.         while (
  2513.             fprintf(stderr, "File name> "),
  2514.             (outfile = fopen(mygets(fname, 80), "w")) == NULL
  2515.         )
  2516.             fprintf(stderr, "Can't open %s.\n", fname);
  2517.     }
  2518.     if (redirected || !verbose)
  2519.         showdone(p);
  2520.     fprintf(outfile, "The following left undone:\n");
  2521.     noex = 1;
  2522.     return(first != p);
  2523. }
  2524.  
  2525.  
  2526. static void showdone(fin)
  2527.     REP *fin;
  2528. {
  2529.     REP *first, *p;
  2530.  
  2531.     for (first = hrep.r_next; ; first = first->r_next)
  2532.         for (p = first; p != NULL; p = p->r_thendo) {
  2533.             if (p == fin)
  2534.                 return;
  2535.             fprintf(outfile, "%s%s %c%c %s%s : done%s\n",
  2536.                 p->r_hfrom->h_name, p->r_ffrom->fi_name,
  2537.                 p->r_flags & R_ISALIASED ? '=' : '-',
  2538.                 p->r_flags & R_ISCYCLE ? '^' : '>',
  2539.                 p->r_hto->h_name, p->r_nto,
  2540.                 (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "");
  2541.         }
  2542. }
  2543.  
  2544.  
  2545. static void breakout()
  2546. {
  2547.     fflush(stdout);
  2548.     fprintf(stderr, "Aborting, nothing done.\n");
  2549.     exit(1);
  2550. }
  2551.  
  2552.  
  2553. static int breakrep()
  2554. {
  2555.     gotsig = 1;
  2556.     return(1);
  2557. }
  2558.  
  2559.  
  2560. static void breakstat()
  2561. {
  2562.     exit(1);
  2563. }
  2564.  
  2565.  
  2566. static void quit()
  2567. {
  2568.     fprintf(stderr, "Aborting, nothing done.\n");
  2569.     exit(1);
  2570. }
  2571.  
  2572.  
  2573. static int copymove(p)
  2574.     REP *p;
  2575. {
  2576. #ifndef MSDOS
  2577. #ifndef SYSV
  2578.     {
  2579.         int llen;
  2580.         char linkbuf[MAXPATH];
  2581.  
  2582.         if ((llen = readlink(pathbuf, linkbuf, MAXPATH - 1)) >= 0) {
  2583.             linkbuf[llen] = '\0';
  2584.             return(symlink(linkbuf, fullrep) || myunlink(pathbuf, p->r_ffrom));
  2585.         }
  2586.     }
  2587. #endif
  2588. #endif
  2589.     return(copy(p->r_ffrom, -1L) || myunlink(pathbuf, p->r_ffrom));
  2590. }
  2591.  
  2592.  
  2593.  
  2594. #define IRWMASK (S_IREAD | S_IWRITE)
  2595. #define RWMASK (IRWMASK | (IRWMASK >> 3) | (IRWMASK >> 6))
  2596.  
  2597. static int copy(ff, len)
  2598.     FILEINFO *ff;
  2599.     long len;
  2600. {
  2601.     char buf[BUFSIZE], c;
  2602.     int f, t, k, mode, perm;
  2603. #ifdef MSDOS
  2604.     struct ftime tim;
  2605. #else
  2606. #ifdef SYSV
  2607.     struct utimbuf tim;
  2608. #else
  2609.     struct timeval tim[2];
  2610. #endif
  2611.     struct stat fstat;
  2612. #endif
  2613.  
  2614.     if ((f = open(pathbuf, O_RDONLY | O_BINARY, 0)) < 0)
  2615.         return(-1);
  2616.     perm =
  2617. #ifdef MSDOS
  2618.         IRWMASK        /* will _chmod it later (to get all the attributes) */
  2619. #else
  2620.         (op & (APPEND | OVERWRITE)) ?
  2621.             (~oldumask & RWMASK) | (ff->fi_mode & ~RWMASK) :
  2622.             ff->fi_mode
  2623. #endif
  2624.         ;
  2625.  
  2626. #ifdef V7
  2627.     if (
  2628.         !(op & APPEND) ||
  2629.         (((t = open(fullrep, O_RDWR)) < 0 && errno == ENOENT)
  2630.     )
  2631.         t = creat(fullrep, perm);
  2632. #else
  2633.     mode = O_CREAT | (op & APPEND ? 0 : O_TRUNC) |
  2634. #ifdef MSDOS
  2635.         O_BINARY | (op & ZAPPEND ? O_RDWR : O_WRONLY)
  2636. #else
  2637.         O_WRONLY
  2638. #endif
  2639.         ;
  2640.     t = open(fullrep, mode, perm);
  2641. #endif
  2642.     if (t < 0) {
  2643.         close(f);
  2644.         return(-1);
  2645.     }
  2646.     if (op & APPEND)
  2647.         lseek(t, 0L, 2);
  2648. #ifdef MSDOS
  2649.     if (op & ZAPPEND && filelength(t) != 0) {
  2650.         if (lseek(t, -1L, 1) == -1L || read(t, &c, 1) != 1) {
  2651.             close(f);
  2652.             close(t);
  2653.             return(-1);
  2654.         }
  2655.         if (c == 26)
  2656.             lseek(t, -1L, 1);
  2657.     }
  2658. #endif
  2659.     if ((op & APPEND) && len != -1L) {
  2660.         while (
  2661.             len != 0 &&
  2662.             (k = read(f, buf, len > BUFSIZE ? BUFSIZE : (unsigned)len)) > 0 &&
  2663.             write(t, buf, k) == k
  2664.         )
  2665.             len -= k;
  2666.         if (len == 0)
  2667.             k = 0;
  2668.     }
  2669.     else
  2670.         while ((k = read(f, buf, BUFSIZE)) > 0 && write(t, buf, k) == k)
  2671.             ;
  2672.     if (!(op & (APPEND | OVERWRITE)))
  2673.         if (
  2674. #ifdef MSDOS
  2675.             getftime(f, &tim) ||
  2676.             setftime(t, &tim) ||
  2677.             _chmod(fullrep, 1, ff->fi_attrib) == -1
  2678. #else
  2679.             stat(pathbuf, &fstat) ||
  2680.             (
  2681. #ifdef SYSV
  2682.                 tim.actime = fstat.st_atime,
  2683.                 tim.modtime = fstat.st_mtime,
  2684. #else
  2685.                 tim[0].tv_sec = fstat.st_atime,
  2686.                 tim[1].tv_sec = fstat.st_mtime,
  2687. #endif
  2688.                 utimes(fullrep, tim)
  2689.             )
  2690. #endif
  2691.         )
  2692.             fprintf(stderr, "Strange, couldn't transfer time from %s to %s.\n",
  2693.                 pathbuf, fullrep);
  2694.  
  2695.     close(f);
  2696.     close(t);
  2697.     if (k != 0) {
  2698.         if (!(op & APPEND))
  2699.             unlink(fullrep);
  2700.         return(-1);
  2701.     }
  2702.     return(0);
  2703. }
  2704.  
  2705.  
  2706. #ifndef RENAME
  2707. static int rename(from, to)
  2708.     char *from, *to;
  2709. {
  2710.     if (link(from, to))
  2711.         return(-1);
  2712.     if (unlink(from)) {
  2713.         unlink(to);
  2714.         return(-1);
  2715.     }
  2716.     return(0);
  2717. }
  2718. #endif
  2719.  
  2720.  
  2721. static int myunlink(n, f)
  2722.     char *n;
  2723.     FILEINFO *f;
  2724. {
  2725. #ifdef MSDOS
  2726.     int a;
  2727.  
  2728.     if (((a = f->fi_attrib) & FA_RDONLY) && _chmod(n, 1, a & ~FA_RDONLY) < 0) {
  2729.         fprintf(stderr, "Strange, can not _chmod (or unlink) %s.\n", f);
  2730.         return(-1);
  2731.     }
  2732. #endif
  2733.     if (unlink(n)) {
  2734.         fprintf(stderr, "Strange, can not unlink %s.\n", n);
  2735.         return(-1);
  2736.     }
  2737.     return(0);
  2738. }
  2739.  
  2740.  
  2741. static int getreply(m, failact)
  2742.     char *m;
  2743.     int failact;
  2744. {
  2745.     static FILE *tty = NULL;
  2746.     int c, r;
  2747.  
  2748.     fprintf(stderr, m);
  2749.     if (tty == NULL && (tty = fopen(TTY, "r")) == NULL) {
  2750.         fprintf(stderr, "Can not open %s to get reply.\n", TTY);
  2751.         if (failact == -1)
  2752.             quit();
  2753.         else
  2754.             return(failact);
  2755.     }
  2756.     for (;;) {
  2757.         r = fgetc(tty);
  2758.         if (r == EOF) {
  2759.             fprintf(stderr, "Can not get reply.\n");
  2760.             if (failact == -1)
  2761.                 quit();
  2762.             else
  2763.                 return(failact);
  2764.         }
  2765.         if (r != '\n')
  2766.             while ((c = fgetc(tty)) != '\n' && c != EOF)
  2767.                 ;
  2768.         r = mylower(r);
  2769.         if (r == 'y' || r == 'n')
  2770.             return(r == 'y');
  2771.         fprintf(stderr, "Yes or No? ");
  2772.     }
  2773. }
  2774.  
  2775.  
  2776. static void *myalloc(k)
  2777.     unsigned k;
  2778. {
  2779.     void *ret;
  2780.  
  2781.     if (k == 0)
  2782.         return(NULL);
  2783.     if ((ret = (void *)malloc(k)) == NULL) {
  2784.         fprintf(stderr, "Insufficient memory.\n");
  2785.         quit();
  2786.     }
  2787.     return(ret);
  2788. }
  2789.  
  2790.  
  2791. static void *challoc(k, which)
  2792.     int which;
  2793.     int k;
  2794. {
  2795.     void *ret;
  2796.     CHUNK *p, *q;
  2797.     SLICER *sl = &(slicer[which]);
  2798.  
  2799.     if (k > sl->sl_len) {
  2800.         for (
  2801.             q = NULL, p = freechunks;
  2802.             p != NULL && (sl->sl_len = p->ch_len) < k;
  2803.             q = p, p = p->ch_next
  2804.         )
  2805.             ;
  2806.         if (p == NULL) {
  2807.             sl->sl_len = CHUNKSIZE - sizeof(CHUNK *);
  2808.             p = (CHUNK *)myalloc(CHUNKSIZE);
  2809.         }
  2810.         else if (q == NULL)
  2811.             freechunks = p->ch_next;
  2812.         else
  2813.             q->ch_next = p->ch_next;
  2814.         p->ch_next = sl->sl_first;
  2815.         sl->sl_first = p;
  2816.         sl->sl_unused = (char *)&(p->ch_len);
  2817.     }
  2818.     sl->sl_len -= k;
  2819.     ret = (void *)sl->sl_unused;
  2820.     sl->sl_unused += k;
  2821.     return(ret);
  2822. }
  2823.  
  2824.  
  2825. static void chgive(p, k)
  2826.     void *p;
  2827.     unsigned k;
  2828. {
  2829.     ((CHUNK *)p)->ch_len = k - sizeof(CHUNK *);
  2830.     ((CHUNK *)p)->ch_next = freechunks;
  2831.     freechunks = (CHUNK *)p;
  2832. }
  2833.  
  2834.  
  2835. #ifndef MSDOS
  2836. static void memmove(to, from, k)
  2837.     char *to, *from;
  2838.     unsigned k;
  2839. {
  2840.     if (from > to)
  2841.         while (k-- != 0)
  2842.             *(to++) = *(from++);
  2843.     else {
  2844.         from += k;
  2845.         to += k;
  2846.         while (k-- != 0)
  2847.             *(--to) = *(--from);
  2848.     }
  2849. }
  2850. #endif
  2851.  
  2852.  
  2853. static int mygetc()
  2854. {
  2855.     static int lastc = 0;
  2856.  
  2857.     if (lastc == EOF)
  2858.         return(EOF);
  2859.     return(lastc = getchar());
  2860. }
  2861.  
  2862.  
  2863. static char *mygets(s, l)
  2864.     char *s;
  2865.     int l;
  2866. {
  2867.     char *nl;
  2868.  
  2869.     for (;;) {
  2870.         if (fgets(s, l, stdin) == NULL)
  2871.             return(NULL);
  2872.         if ((nl = strchr(s, '\n')) != NULL)
  2873.             break;
  2874.         fprintf(stderr, "Input string too long. Try again> ");
  2875.     }
  2876.     *nl = '\0';
  2877.     return(s);
  2878. }
  2879.  
  2880.  
  2881. #ifdef MSDOS
  2882. static int leave()
  2883. {
  2884.     return(0);
  2885. }
  2886.  
  2887. static void cleanup()
  2888. {
  2889.     int i;
  2890.  
  2891.     if (patch.ph_safeid) {
  2892.         for (i = 0; i < nhandles; i++) {
  2893.             if (!(handles[i]->h_di->di_flags & DI_CLEANED)) {
  2894.                 sprintf(pathbuf, "%s%s%03d",
  2895.                     handles[i]->h_name, IDF, handles[i]->h_di->di_did);
  2896.                 if (unlink(pathbuf))
  2897.                     fprintf(stderr, "Strange, couldn't unlink %s.\n", pathbuf);
  2898.                 handles[i]->h_di->di_flags |= DI_CLEANED;
  2899.             }
  2900.         }
  2901.     }
  2902. /*
  2903.     Write device availability: undocumented internal MS-D*S function.
  2904.     Restore previous value.
  2905. */
  2906.     bdos(0x37, olddevflag, 3);
  2907. }
  2908.  
  2909. #endif
  2910.