home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / directry / mmv / mmv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-22  |  58.4 KB  |  2,855 lines

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