rsalz@uunet.uu.net (Rich Salz) (04/10/90)
Submitted-by: Vladimir Lanin <lanin@csd4.cs.nyu.edu> Posting-number: Volume 21, Issue 87 Archive-name: mmv/part01 [ I use ren, the predecessor to mmv, all the time. This is even better! --r$ ] This is mmv, a program to move/copy/append/link multiple files according to a set of wildcard patterns. This multiple action is performed safely, i.e., without any unexpected deletion of files due to collisions of target names with existing filenames or with other target names. Furthermore, before doing anything, mmv attempts to detect any errors that would result from the entire set of actions specified and gives the user the choice of either aborting before beginning, or proceeding by avoiding the offending parts. Improvements over mmv's predecessor, ren: Support for BSD, System 5, and MS-DOS Source and target files may (usually) reside in different directories Paths may contain wildcards Supports all csh wildcards: '*', '?', '['...']', and '~' The ';' wildcard finds files at any level in the tree Can copy, append, or link instead of moving/renaming Reads multiple patterns from standard input (or one from command line) No-execute option (whose output can be fed back in on standard input) #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 2)." # Contents: MANIFEST Makefile PACKNOTES announce mmv.1 mmv.c.2 # Wrapped by rsalz@litchi.bbn.com on Mon Apr 9 17:05:22 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'MANIFEST' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'MANIFEST'\" else echo shar: Extracting \"'MANIFEST'\" \(359 characters\) sed "s/^X//" >'MANIFEST' <<'END_OF_FILE' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 X Makefile 1 X PACKNOTES 1 Warnings about long lines, etc X announce 1 X mmv.1 1 X mmv.c.1 2 (part 1) X mmv.c.2 1 (part 2) END_OF_FILE if test 359 -ne `wc -c <'MANIFEST'`; then echo shar: \"'MANIFEST'\" unpacked with wrong size! fi # end of 'MANIFEST' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(281 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' Xall: mmv mmv.1 X Xmmv: mmv.c X $(CC) -o mmv $(CFLAGS) mmv.c Xinstall: all X @echo "Install mmv according to local convention," X @echo "then make links named mcp, mad, and mln to mmv." X @echo "Under System V, edit mmv.1 to uncomment the .nr O 1 line." Xclean: X rm -f core a.out mmv mmv.o END_OF_FILE if test 281 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'PACKNOTES' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'PACKNOTES'\" else echo shar: Extracting \"'PACKNOTES'\" \(82 characters\) sed "s/^X//" >'PACKNOTES' <<'END_OF_FILE' X XFile "mmv.c" was split because of its size; to create it, do X cat mmv.c.? >mmv.c END_OF_FILE if test 82 -ne `wc -c <'PACKNOTES'`; then echo shar: \"'PACKNOTES'\" unpacked with wrong size! fi # end of 'PACKNOTES' fi if test -f 'announce' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'announce'\" else echo shar: Extracting \"'announce'\" \(1588 characters\) sed "s/^X//" >'announce' <<'END_OF_FILE' XCopyright (c) 1989 Vladimir Lanin X XThis is mmv, a program to move/copy/append/link multiple files Xaccording to a set of wildcard patterns. This multiple action is Xperformed safely, i.e. without any unexpected deletion of files due to Xcollisions of target names with existing filenames or with other Xtarget names. Furthermore, before doing anything, mmv attempts to Xdetect any errors that would result from the entire set of actions Xspecified and gives the user the choice of either aborting before Xbeginning, or proceeding by avoiding the offending parts. X XImprovements over mmv's predecessor, ren: X X. support for BSD, System 5, and MS-DOS X X. source and target files may (usually) reside in different directories X X. paths may contain wildcards X X. supports all csh wildcards: '*', '?', '['...']', and '~' X X. the ';' wildcard finds files at any level in the tree X X. can copy, append, or link instead of moving/renaming X X. reads multiple patterns from standard input (or one from command line) X X. no-execute option (whose output can be fed back in on standard input) X XNote to users familiar with ren: the -a and -k options have been renamed Xto -t and -g, respectively, and their semantics have somewhat changed. X X XMmv is freeware. That means that the entire package of software and Xdocumentation is copyrighted, and may not be distributed with any Xmodifications or for any charge (without the author's explicit written Xpermission). Other than that, it may be used and distributed freely. X X XVladimir Lanin X330 Wadsworth Ave, Apt 6F XNew York, NY 10040 X Xlanin@csd2.nyu.edu X...!cmcl2!csd2!lanin END_OF_FILE if test 1588 -ne `wc -c <'announce'`; then echo shar: \"'announce'\" unpacked with wrong size! fi # end of 'announce' fi if test -f 'mmv.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mmv.1'\" else echo shar: Extracting \"'mmv.1'\" \(17091 characters\) sed "s/^X//" >'mmv.1' <<'END_OF_FILE' X.\" Under BSD, just give to nroff or troff (with -man). X.\" To print the MS-DOS version, use option -rO2. X.\" Under System V, take out the '.\" ' from the next line. X.\" .nr O 1 X.TH MMV 1 "November 20, 1989 (v1.0)" X.ie !'\nO'2' \{\ X.SH NAME Xmmv \- move/copy/append/link multiple files by wildcard patterns X\} X.el \{ X.SH NAME Xmmv \- move/copy/append multiple files by wildcard patterns X\} X.ie '\nO'2' \{\ X.ds SL \\\\ X.ds ES ' X\} X.el \{\ X.ds SL / X.ds ES \\\\ X\} X.SH SYNOPSIS X.B mmv X.if '\nO'2' [\fB-m\fP|\fBx\fP|\fBr\fP|\fBc\fP|\fBo\fP|\fBa\fP|\fBz\fP] X.if '\nO'0' [\fB-m\fP|\fBx\fP|\fBr\fP|\fBc\fP|\fBo\fP|\fBa\fP|\fBl\fP|\fBs\fP] X.if '\nO'1' [\fB-m\fP|\fBx\fP|\fBr\fP|\fBc\fP|\fBo\fP|\fBa\fP|\fBl\fP] X[\fB-h\fP] X[\fB-d\fP|\fBp\fP] X[\fB-g\fP|\fBt\fP] X[\fB-v\fP|\fBn\fP] X[\fBfrom to\fP] X.if '\nO'2' \{\ X.br X.B mmvpatch X[\fBexecutable\fP] X\} X.SH "DESCRIPTION" X.I Mmv Xmoves (or copies, X.ie '\nO'2' or appends, X.el appends, or links, Xas specified) Xeach source file matching a X.I from Xpattern to the target name specified by the X.I to Xpattern. XThis multiple action is performed safely, Xi.e. without any unexpected deletion of files Xdue to collisions of target names with existing filenames Xor with other target names. XFurthermore, before doing anything, X.I mmv Xattempts to detect any errors that would result Xfrom the entire set of actions specified Xand gives the user the choice of either Xproceeding by avoiding the offending parts Xor aborting. X X.ce XThe Task Options X.PP XWhether X.I mmv Xmoves, copies, X.ie '\nO'2' or appends X.el appends, or links Xis governed by the first set of options given Xabove. XIf none of these are specified, X.ie '\nO'2' \{\ Xa default (patchable by X.IR mmvpatch , Xand initially -x) Xdetermines the task. X\} X.el \{\ Xthe task is given by the command name under which X.I mmv Xwas invoked (argv[0]): X X command name default task X X mmv -x X.br X mcp -c X.br X mad -a X.br X mln -l X\} X.PP XThe task option choices are: X.TP X-m : Xmove source file to target name. XBoth must be on the same device. XWill not move directories. X.if '\nO'0' \{\ XIf the source file is a symbolic link, Xmoves the link without checking if the link's target from the new Xdirectory is different than the old. X\} X.TP X-x : Xsame as -m, except cross-device moves are done Xby copying, then deleting source. XWhen copying, sets the X.ie !'\nO'2' permission bits X.el attributes Xand file modification time Xof the target file to that of the source file. X.TP X-r : Xrename source file or directory to target name. XThe target name must not include a path: Xthe file remains in the same directory in all cases. XThis option is the only way of renaming directories under X.IR mmv . X.if '\nO'2' It is only available under DOS version 3.0 or higher. X.TP X-c : Xcopy source file to target name. XSets the file modification time and X.ie !'\nO'2' permission bits X.el attributes Xof the target file to that of the source file, Xregardless of whether the target file already exists. XChains and cycles (to be explained below) are not allowed. X.TP X-o : Xoverwrite target name with source file. X.ie '\nO'2' \{\ XIf target file exists, its attributes are left unchanged. XIf not, it is created with ordinary attributes Xunrelated to the source file's attributes. XIn either case, the file modification time is set to the current time. X\} X.el \{\ XIf target file exists, it is overwritten, Xkeeping its original owner and permission bits. XIf it does not exist, it is created, with read-write permission bits Xset according to X.IR umask (1), Xand the execute permission bits copied from the source file. XIn either case, the file modification time is set to the current time. X\} X.TP X-a : Xappend contents of source file to target name. XTarget file modification time is set to the current time. XIf target file does not exist, Xit is created with X.ie '\nO'2' attributes X.el permission bits Xset as under -o. XUnlike all other options, -a allows multiple source files to have the Xsame target name, e.g. "mmv -a X.ie '\nO'2' *.c X.el \\*.c Xbig" will append all ".c" files to "big". XChains and cycles are also allowed, so "mmv -a f f" will double up "f". X.ie '\nO'2' \{\ X.TP X-z : Xsame as -a, but if the target file exists, and its last character is a ^Z, Xand the source file is not empty, Xthis ^Z is truncated before doing the append. X\} X.el \{\ X.TP X-l : Xlink target name to source file. XBoth must be on the same device, Xand the source must not be a directory. XChains and cycles are not allowed. X.if '\nO'0' \{\ X.TP X-s : Xsame as -l, but use symbolic links instead of hard links. XFor the resulting link to aim back at the source, Xeither the source name must begin with a '/', Xor the target must reside in either the current or the source directory. XIf none of these conditions are met, the link is refused. XHowever, source and target can reside on different devices, Xand the source can be a directory. X\} X\} X.PP XOnly one of these option may be given, Xand it applies to all matching files. XRemaining options need not be given separately, Xi.e. "mmv -mk" is allowed. X X.ce XMultiple Pattern Pairs X.PP XMultiple X.I from X-- X.I to Xpattern pairs may be specified by omitting Xthe pattern pair on the command line, Xand entering them on the standard input, Xone pair per line. X(If a pattern pair is given on the command line, Xthe standard input is not read.) XThus, X X.in +3 Xmmv X.br Xa b X.br Xc d X.in -3 X Xwould rename "a" to "b" and "c" to "d". XIf a file can be matched to several of the given X.I from Xpatterns, Xthe X.I to Xpattern of the first matching pair is used. XThus, X X.in +3 Xmmv X.br Xa b X.br Xa c X.in -3 X Xwould give the error message "a -> c : no match" because file "a" X(even if it exists) Xwas already matched by the first pattern pair. X X.ce XThe \fIFrom\fP Pattern X.PP XThe X.I from Xpattern is a filename Xwith embedded wildcards: '*', '?', '['...']', X.if '\nO'2' \{\ X\'!', X\} Xand ';'. XThe first three have their usual X.IR sh (1) Xmeanings of, respectively, Xmatching any string of characters, Xmatching any single character, Xand matching any one of a set of characters. X.PP XBetween the '[' and ']', a range from character 'a' through character 'z' Xis specified with "a-z". XThe set of matching characters can be negated by inserting Xa '^' after the '['. XThus, "[^b-e2-5_]" Xwill match any character but 'b' through 'e', '2' through '5', and '_'. X.if '\nO'2' \{\ X.PP XUnlike DOS wildcards, Xall mmv wildcards (except for cases listed below) Xcan occur anywhere in the pattern, Xwhether preceding or following explicit characters or other wildcards. XFor example, the pattern "*z\\foo.bar" will search Xfor files named "foo.bar" in all subdirectories whose names end in 'z'. XHowever, no wildcards can occur in the drive letter. X.PP XThe character '.' is not matched by any of '*', '?', or '['...']'. XThus, the pattern "*" will only match files with a null extension. XTo save yourself some typing, use the '!' wildcard instead, Xwhich matches the same as "*.*", Xexcept it is assigned only one wildcard index (see below). XThus, both "f!" and "f*.*" Xwill match all of "f", "f.ext", "foo", and "foo.ext", Xwhile "f*" will match only the first and the third. X\} X.PP XNote that paths are allowed in the patterns, Xand wildcards may be intermingled with slashes arbitrarily. XThe ';' wildcard Xis useful for matching files at any depth in the directory tree. XIt matches the same as "*\*(SL" repeated any number of times, including zero, Xand can only occur either at the beginning of the pattern Xor following a '\*(SL'. XThus ";*.c" will match all ".c" files in or below the current directory, Xwhile "\*(SL;*.c" will match them anywhere on the file system. X.if !'\nO'2' \{\ X.PP XIn addition, if the X.I from Xpattern X(or the X.I to Xpattern) Xbegins with "~/", the '~' is replaced with the home directory name. X(Note that the "~user" feature of X.IR csh (1) Xis not implemented.) XHowever, the '~' is not treated as a wildcard, Xin the sense that it is not assigned a wildcard index (see below). X\} X.PP XSince matching a directory under a task option other than -r or -s Xwould result in an error, Xtasks other than -r and -s Xmatch directories only against completely explicit X.I from Xpatterns (i.e. not containing wildcards). XUnder -r and -s, this applies only to "." and "..". X.PP X.ie '\nO'2' \{\ XHidden and system files are also only matched Xagainst completely explicit X.I from Xpatterns. X\} X.el \{\ XFiles beginning with '.' are only matched against X.I from Xpatterns that begin with an explicit '.'. X\} XHowever, if -h is specified, they are matched normally. X.if !'\nO'2' \{\ X.PP XWarning: since the shell normally expands wildcards Xbefore passing the command-line arguments to X.IR mmv , Xit is usually necessary to enclose the command-line X.I from Xpattern Xin quotes. X\} X X.ce XThe \fITo\fP Pattern X.PP XThe X.I to Xpattern is a filename Xwith embedded X.I wildcard X.IR indexes , Xwhere an index consists of the character '=' Xfollowed by a string of digits. XWhen a source file matches a X.I from Xpattern, Xa target name for the file is constructed out of the X.I to Xpattern by Xreplacing the wildcard indexes by the Xactual characters that matched the referenced wildcards Xin the source name. XThus, if the X.I from Xpattern is "abc*.*" and the X.I to Xpattern is "xyz=2.=1", Xthen "abc.txt" is targeted to "xyztxt.". X(The first '*' matched "", and the second matched "txt".) XSimilarly, for the pattern pair ";*.[clp]" -> "=1=3\*(SL=2", X"foo1\*(SLfoo2\*(SLprog.c" is targeted to "foo1\*(SLfoo2\*(SLc\*(SLprog". XNote that there is no '\*(SL' following the "=1" in the X.I to Xpattern, Xsince the string matched by any ';' is always either empty Xor ends in a '\*(SL'. XIn this case, it matches "foo1\*(SLfoo2\*(SL". X.if !'\nO'2' \{\ X.PP XTo convert the string matched by a wildcard Xto either lowercase or uppercase before embedding it in the target name, Xinsert 'l' or 'u', respectively, Xbetween the '=' and the string of digits. X.PP XThe X.I to Xpattern, Xlike the X.I from Xpattern, Xcan begin with a "~/" (see above). XThis does not necessitate enclosing the X.I to Xpattern in quotes on the command line Xsince X.IR csh (1) Xexpands the '~' in the exact same manner as X.I mmv X(or, in the case of X.IR sh (1), Xdoes not expand it at all). X\} X.PP XFor all task options other than -r, if the target name is a directory, Xthe real target name is formed by appending Xa '\*(SL' followed by the last component Xof the source file name. XFor example, "mmv dir1\*(SLa dir2" will, Xif "dir2" is indeed a directory, actually move "dir1\*(SLa" to "dir2\*(SLa". XHowever, if "dir2\*(SLa" already exists and is itself a directory, Xthis is considered an error. X.PP XTo strip any character (e.g. '*', '?', or '=') Xof its special meaning to X.IR mmv , Xas when the actual replacement name must contain the character '=', Xprecede the special character with a X.ie '\nO'2' \{\ Xsingle quote ('). X\} X.el \{\ X\'\\' X(and enclose the argument in quotes because of the shell). X\} XThis also works to terminate a wildcard index Xwhen it has to be followed by a digit in the filename, e.g. "a=1\*(ES1". X X.ce XChains and Cycles X.PP XA chain is a sequence of specified actions where the target name of Xone action refers to the source file of another action. XFor example, X Xmmv X.br Xa b X.br Xb c X Xspecifies the chain "a" -> "b" -> "c". XA cycle is a chain where the last target name Xrefers back to the first source file, Xe.g. "mmv a a". X.I Mmv Xdetects chains and cycles regardless of the order in which Xtheir constituent actions are actually given. XWhere allowed, i.e. in moving, renaming, and appending files, Xchains and cycles are handled gracefully, by performing them in the proper Xorder. XCycles are broken by first renaming one of the files to a temporary name X(or just remembering its original size when doing appends). X X.ce XCollisions and Deletions X.PP XWhen any two or more matching files Xwould have to be X.ie '\nO'2' moved or copied X.el moved, copied, or linked Xto the same target filename, X.I mmv Xdetects the condition as an error before performing any actions. XFurthermore, X.I mmv Xchecks if any of its actions will result Xin the destruction of existing files. XIf the -d (delete) option is specified, Xall file deletions or overwrites are done silently. XUnder -p (protect), all deletions or overwrites X(except those specified with "(*)" on the standard input, see below) Xare treated as errors. XAnd if neither option is specified, Xthe user is queried about each deletion or overwrite separately. X(A new stream to X.ie '\nO'2' "\\dev\\con" X.el "/dev/tty" Xis used for all interactive queries, Xnot the standard input.) X X.ce XError Handling X.PP XWhenever any error in the user's action specifications is detected, Xan error message is given on the standard output, Xand X.I mmv Xproceeds to check the rest of the specified actions. XOnce all errors are detected, X.I mmv Xqueries the user whether he wishes Xto continue by avoiding the erroneous actions or to abort altogether. XThis and all other queries may be avoided by specifying either the X-g (go) or -t (terminate) option. XThe former will resolve all difficulties by avoiding the erroneous actions; Xthe latter will abort X.I mmv Xif any errors are detected. XSpecifying either of them defaults X.I mmv Xto -p, unless -d is specified X(see above). XThus, -g and -t are most useful when running X.I mmv Xin the background or in Xa shell script, Xwhen interactive queries are undesirable. X X.ce XReports X.PP XOnce the actions to be performed are determined, X.I mmv Xperforms them silently, Xunless either the -v (verbose) or -n (no-execute) option is specified. XThe former causes X.I mmv Xto report each performed action Xon the standard output as X Xa -> b : done. X XHere, "a" and "b" would be replaced by the source and target names, Xrespectively. XIf the action deletes the old target, Xa "(*)" is inserted after the the target name. XAlso, the "->" symbol is modified when a cycle has to be broken: Xthe '>' is changed to a '^' on the action prior to which the old target Xis renamed to a temporary, Xand the '-' is changed to a '=' on the action where the temporary is used. X.PP XUnder -n, none of the actions are performed, Xbut messages like the above are printed on the standard output Xwith the ": done." omitted. X.PP XThe output generated by -n can (after editing, if desired) Xbe fed back to X.I mmv Xon the standard input X(by omitting the X.I from X-- X.I to Xpair on the X.I mmv Xcommand line). XTo facilitate this, X.I mmv Xignores lines on the standard input that look Xlike its own error and "done" messages, Xas well as all lines beginning with white space, Xand will accept pattern pairs with or without the intervening "->" X(or "-^", "=>", or "=^"). XLines with "(*)" after the target pattern have the effect of enabling -d Xfor the files matching this pattern only, Xso that such deletions are done silently. XWhen feeding X.I mmv Xits own output, Xone must remember to specify again the task option (if any) Xoriginally used to generate it. X.PP XAlthough X.I mmv Xattempts to predict all mishaps prior to performing any specified actions, Xaccidents may happen. XFor example, X.I mmv Xdoes not check for adequate free space when copying. XThus, despite all efforts, Xit is still possible for an action to fail Xafter some others have already been done. XTo make recovery as easy as possible, X.I mmv Xreports which actions have already been done and Xwhich are still to be performed Xafter such a failure occurs. XIt then aborts, not attempting to do anything else. XOnce the user has cleared up the problem, Xhe can feed this report back to X.I mmv Xon the standard input Xto have it complete the task. X(The user is queried for a file name to dump this report Xif the standard output has not been redirected.) X.if '\nO'2' \{\ X X.ce X\fIMmvpatch\fP X.PP XYou can customize a copy of X.I mmv Xvia the X.I mmvpatch Xutility. XIf you wish to change the default task option, Xrun X.I mmvpatch Xon a copy of X.I mmv Xnamed as follows: X X -x, -m, -r mmv.exe X.br X -c, -o mcp.exe X.br X -a, -z mad.exe X.PP X.I Mmvpatch Xalso determines the best way to uniquely identify directories. XAs distributed, X.I mmv Xis set to use a method that is guaranteed to work the same way Xfor all versions of DOS, Xbut is both slow Xand unable to correctly handle drives Xaffected by the X.I join Xand X.I subst XDOS commands. XAlternatively, Xthere is a method that is fast and correct, Xbut uses an undocumented DOS feature Xthat may not work properly under all versions of DOS. X(However, 2.0 and 3.3 are known to work.) X.I Mmv Xdoes X.I not Xdetermine the best method to use on your system Xat run-time since this is too slow. XThe choice is left to X.I mmvpatch, Xwhich determines if the fast method works, Xbut also allows you to return to the slow method. X\} X.SH "EXIT STATUS" X.I Mmv Xexits with status 1 if it aborts before doing anything, Xwith status 2 if it aborts due to failure after completing some of the Xactions, Xand with status 0 otherwise. X.if !'\nO'2' \{\ X.SH "SEE ALSO" Xmv(1), cp(1), ln(1), umask(1) X\} X.SH "AUTHOR" XVladimir Lanin X.br Xlanin@csd2.nyu.edu X.SH "BUGS" X.if !'\nO'2' \{\ XIf the search pattern is not quoted, Xthe shell expands the wildcards. X.I Mmv Xthen (usually) gives some error message, Xbut can not determine that the lack of quotes is the cause. X.PP X\}\ XTo avoid difficulties in semantics and error checking, X.I mmv Xrefuses to move or create directories. END_OF_FILE if test 17091 -ne `wc -c <'mmv.1'`; then echo shar: \"'mmv.1'\" unpacked with wrong size! fi # end of 'mmv.1' fi if test -f 'mmv.c.2' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mmv.c.2'\" else echo shar: Extracting \"'mmv.c.2'\" \(7214 characters\) sed "s/^X//" >'mmv.c.2' <<'END_OF_FILE' Xstatic int movealias(first, p, pprintaliased) X REP *first, *p; X int *pprintaliased; X{ X char *fstart; X int ret; X X strcpy(pathbuf, p->r_hto->h_name); X fstart = pathbuf + strlen(pathbuf); X strcpy(fstart, TEMP); X for ( X ret = 0; X sprintf(fstart + STRLEN(TEMP), "%03d", ret), X fsearch(fstart, p->r_hto->h_di) != NULL; X ret++ X ) X ; X if (rename(fullrep, pathbuf)) { X fprintf(stderr, X "%s -> %s has failed.\n", fullrep, pathbuf); X *pprintaliased = snap(first, p); X } X return(ret); X} X X Xstatic int snap(first, p) X REP *first, *p; X{ X char fname[80]; X int redirected = 0; X X if (noex) X exit(1); X X failed = 1; X#ifdef MSDOS X ctrlbrk((int (*)())breakstat); X#else X signal(SIGINT, breakstat); X#endif X if ( X badstyle == ASKBAD && X isatty(fileno(stdout)) && X getreply("Redirect standard output to file? ", 0) X ) { X redirected = 1; X#ifndef MSDOS X umask(oldumask); X#endif X while ( X fprintf(stderr, "File name> "), X (outfile = fopen(gets(fname), "w")) == NULL X ) X fprintf(stderr, "Can't open %s.\n", fname); X } X if (redirected || !verbose) X showdone(p); X fprintf(outfile, "The following left undone:\n"); X noex = 1; X return(first != p); X} X X Xstatic void showdone(fin) X REP *fin; X{ X REP *first, *p; X X for (first = hrep.r_next; ; first = first->r_next) X for (p = first; p != NULL; p = p->r_thendo) { X if (p == fin) X return; X fprintf(outfile, "%s%s %c%c %s%s : done%s\n", X p->r_hfrom->h_name, p->r_ffrom->fi_name, X p->r_flags & R_ISALIASED ? '=' : '-', X p->r_flags & R_ISCYCLE ? '^' : '>', X p->r_hto->h_name, p->r_nto, X (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : ""); X } X} X X Xstatic void breakout() X{ X fflush(stdout); X fprintf(stderr, "Aborting, nothing done.\n"); X exit(1); X} X X Xstatic int breakrep() X{ X gotsig = 1; X return(1); X} X X Xstatic void breakstat() X{ X exit(1); X} X X Xstatic void quit() X{ X fprintf(stderr, "Aborting, nothing done.\n"); X exit(1); X} X X Xstatic int copymove(p) X REP *p; X{ X#ifndef MSDOS X#ifndef SYSV X { X int llen; X char linkbuf[MAXPATH]; X X if ((llen = readlink(pathbuf, linkbuf, MAXPATH - 1)) != 1) { X linkbuf[llen] = '\0'; X return(symlink(linkbuf, fullrep) || myunlink(pathbuf, p->r_ffrom)); X } X } X#endif X#endif X return(copy(p->r_ffrom, -1) || myunlink(pathbuf, p->r_ffrom)); X} X X X X#define IRWMASK (S_IREAD | S_IWRITE) X#define RWMASK (IRWMASK | (IRWMASK >> 3) | (IRWMASK >> 6)) X Xstatic int copy(ff, len) X FILEINFO *ff; X long len; X{ X char buf[BUFSIZE], c; X int f, t, k, mode, perm; X#ifdef MSDOS X struct ftime tim; X#else X#ifdef SYSV X struct utimbuf tim; X#else X struct timeval tim[2]; X#endif X struct stat fstat; X#endif X X if ((f = open(pathbuf, O_RDONLY | O_BINARY, 0)) < 0) X return(-1); X perm = X#ifdef MSDOS X IRWMASK /* will _chmod it later (to get all the attributes) */ X#else X (op & (APPEND | OVERWRITE)) ? X (~oldumask & RWMASK) | (ff->fi_mode & ~RWMASK) : X ff->fi_mode X#endif X ; X mode = O_CREAT | X#ifdef MSDOS X O_BINARY | (op & ZAPPEND ? O_RDWR : O_WRONLY) X#else X O_WRONLY X#endif X ; X if (!(op & APPEND)) X mode |= O_TRUNC; X if ((t = open(fullrep, mode, perm)) < 0) { X close(f); X return(-1); X } X if (op & APPEND) X lseek(t, 0, 2); X#ifdef MSDOS X if (op & ZAPPEND && filelength(t) != 0) { X if (lseek(t, -1, 1) == -1L || read(t, &c, 1) != 1) { X close(f); X close(t); X return(-1); X } X if (c == 26) X lseek(t, -1, 1); X } X#endif X if ((op & APPEND) && len != -1L) { X while ( X len != 0 && X (k = read(f, buf, len > BUFSIZE ? BUFSIZE : (unsigned)len)) > 0 && X write(t, buf, k) == k X ) X len -= k; X if (len == 0) X k = 0; X } X else X while ((k = read(f, buf, BUFSIZE)) > 0 && write(t, buf, k) == k) X ; X if (!(op & (APPEND | OVERWRITE))) X if ( X#ifdef MSDOS X getftime(f, &tim) || X setftime(t, &tim) || X _chmod(fullrep, 1, ff->fi_attrib) == -1 X#else X stat(pathbuf, &fstat) || X ( X#ifdef SYSV X tim.actime = fstat.st_atime, X tim.modtime = fstat.st_mtime, X#else X tim[0].tv_sec = fstat.st_atime, X tim[1].tv_sec = fstat.st_mtime, X#endif X utimes(fullrep, tim) X ) X#endif X ) X fprintf(stderr, "Strange, couldn't transfer time from %s to %s.\n", X pathbuf, fullrep); X X close(f); X close(t); X if (k != 0) { X if (!(op & APPEND)) X unlink(fullrep); X return(-1); X } X return(0); X} X X X#ifndef RENAME Xstatic int rename(from, to) X char *from, *to; X{ X if (link(from, to)) X return(-1); X if (unlink(from)) { X unlink(to); X return(-1); X } X return(0); X} X#endif X X Xstatic int myunlink(n, f) X char *n; X FILEINFO *f; X{ X#ifdef MSDOS X int a; X X if (((a = f->fi_attrib) & FA_RDONLY) && _chmod(n, 1, a & ~FA_RDONLY) < 0) { X fprintf(stderr, "Strange, can not _chmod (or unlink) %s.\n", f); X return(-1); X } X#endif X if (unlink(n)) { X fprintf(stderr, "Strange, can not unlink %s.\n", n); X return(-1); X } X return(0); X} X X Xstatic int getreply(m, failact) X char *m; X int failact; X{ X static FILE *tty = NULL; X int c, r; X X fprintf(stderr, m); X if (tty == NULL && (tty = fopen(TTY, "r")) == NULL) { X fprintf(stderr, "Can not open %s to get reply.\n", TTY); X if (failact == -1) X quit(); X else X return(failact); X } X for (;;) { X r = fgetc(tty); X if (r == EOF) { X fprintf(stderr, "Can not get reply.\n"); X if (failact == -1) X quit(); X else X return(failact); X } X if (r != '\n') X while ((c = fgetc(tty)) != '\n' && c != EOF) X ; X r = mylower(r); X if (r == 'y' || r == 'n') X return(r == 'y'); X fprintf(stderr, "Yes or No? "); X } X} X X Xstatic void *myalloc(k) X unsigned k; X{ X void *ret; X X if (k == 0) X return(NULL); X if ((ret = (void *)malloc(k)) == NULL) { X fprintf(stderr, "Insufficient memory.\n"); X quit(); X } X return(ret); X} X X Xstatic void *challoc(k, which) X int which; X int k; X{ X void *ret; X CHUNK *p, *q; X SLICER *sl = &(slicer[which]); X X if (k > sl->sl_len) { X for ( X q = NULL, p = freechunks; X p != NULL && (sl->sl_len = p->ch_len) < k; X q = p, p = p->ch_next X ) X ; X if (p == NULL) { X sl->sl_len = CHUNKSIZE - sizeof(CHUNK *); X p = (CHUNK *)myalloc(CHUNKSIZE); X } X else if (q == NULL) X freechunks = p->ch_next; X else X q->ch_next = p->ch_next; X p->ch_next = sl->sl_first; X sl->sl_first = p; X sl->sl_unused = (char *)&(p->ch_len); X } X sl->sl_len -= k; X ret = (void *)sl->sl_unused; X sl->sl_unused += k; X return(ret); X} X X Xstatic void chgive(p, k) X void *p; X unsigned k; X{ X ((CHUNK *)p)->ch_len = k - sizeof(CHUNK *); X ((CHUNK *)p)->ch_next = freechunks; X freechunks = (CHUNK *)p; X} X X X#ifndef MSDOS Xstatic void memmove(to, from, k) X char *to, *from; X unsigned k; X{ X if (from > to) X while (k-- != 0) X *(to++) = *(from++); X else { X from += k; X to += k; X while (k-- != 0) X *(--to) = *(--from); X } X} X#endif X X Xstatic int mygetc() X{ X static int lastc = 0; X X if (lastc == EOF) X return(EOF); X return(lastc = getchar()); X} X X X#ifdef MSDOS Xstatic int leave() X{ X return(0); X} X Xstatic void cleanup() X{ X int i; X X if (patch.ph_safeid) { X for (i = 0; i < nhandles; i++) { X if (!(handles[i]->h_di->di_flags & DI_CLEANED)) { X sprintf(pathbuf, "%s%s%03d", X handles[i]->h_name, IDF, handles[i]->h_di->di_did); X if (unlink(pathbuf)) X fprintf(stderr, "Strange, couldn't unlink %s.\n", pathbuf); X handles[i]->h_di->di_flags |= DI_CLEANED; X } X } X } X/* X Write device availability: undocumented internal MS-D*S function. X Restore previous value. X*/ X bdos(0x37, olddevflag, 3); X} X X#endif END_OF_FILE if test 7214 -ne `wc -c <'mmv.c.2'`; then echo shar: \"'mmv.c.2'\" unpacked with wrong size! fi # end of 'mmv.c.2' fi echo shar: End of archive 1 \(of 2\). cp /dev/null ark1isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.