From 55231081887368683690388fda78b0c668b574d9 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 30 Jul 2018 20:26:50 -0400 Subject: [PATCH] add Rename command. --- FileCommon.c | 72 ++++++++++++++++++++++++++ FileCommon.h | 3 ++ Rename-flags.c | 91 +++++++++++++++++++++++++++++++++ Rename-flags.h | 21 ++++++++ Rename.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 4 +- 6 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 FileCommon.c create mode 100644 FileCommon.h create mode 100644 Rename-flags.c create mode 100644 Rename-flags.h create mode 100644 Rename.c diff --git a/FileCommon.c b/FileCommon.c new file mode 100644 index 0000000..20f5b75 --- /dev/null +++ b/FileCommon.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include "FileCommon.h" + +unsigned char *c2p(const char *cp) +{ + int length; + unsigned char *p; + + if (!cp) return NULL; + length = strlen(cp); + if (length > 255) + { + fprintf(stderr, "# Error: Pathname is too long.\n"); + exit(1); + return NULL; + } + + p = malloc(length + 2); // + 2 for \0 and length. + if (!p) + { + fprintf(stderr, "# Error: unable to allocate memory.\n"); + exit(1); + return NULL; + } + + p[0] = length; + memcpy(p + 1, cp, length + 1); + return p; +} + +// -1 - error. +// 0 - no file +// 1 - regular file +// 2 - directory. +int mode(const unsigned char *pname, OSErr *ec) +{ + //char *pname; + CInfoPBRec rec; + OSErr err; + + memset(&rec, 0, sizeof(rec)); + + rec.hFileInfo.ioNamePtr = (unsigned char *)pname; + err = PBGetCatInfo(&rec, false); + if (ec) *ec = err; + if (err) return err = fnfErr ? 0 : -1; + + if (rec.hFileInfo.ioFlAttrib & kioFlAttribDirMask) + return 2; + + return 1; +} + +int prompt(const unsigned char *pname, const char *verb) { + char ch; + char first; + + fprintf(stderr, "%s %s? ", verb, pname+1); + fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) ch = getchar(); + if (first == 'y' || first == 'Y') return 1; + if (first == 'c' || first == 'C') return -1; + return 0; +} + + diff --git a/FileCommon.h b/FileCommon.h new file mode 100644 index 0000000..9bb4ee5 --- /dev/null +++ b/FileCommon.h @@ -0,0 +1,3 @@ +int mode(const unsigned char *pname, OSErr *ec); +unsigned char *c2p(const char *cp); +int prompt(const unsigned char *pname, const char *verb); diff --git a/Rename-flags.c b/Rename-flags.c new file mode 100644 index 0000000..9a84945 --- /dev/null +++ b/Rename-flags.c @@ -0,0 +1,91 @@ + +#ifdef __ORCAC__ +#pragma optimize 79 +#pragma noroot +#endif + +#include +#include +#include + +#include "Rename-flags.h" + +void FlagsHelp(void) +{ + fputs("Rename [options] oldName newName\n", stdout); + fputs("-y overwrite existing files (avoids dialog)\n", stdout); + fputs("-n don't overwrite existing file (avoids dialog)\n", stdout); + fputs("-c cancel if conflict occurs (avoids dialog)\n", stdout); + fputs("\n", stdout); + exit(0); +} + +struct Flags flags; +int FlagsParse(int argc, char **argv) +{ + char *cp; + char *optarg; + + char c; + int i; + int j; + int eof; // end-of-flags + int mindex; // mutation index. + + memset(&flags, 0, sizeof(flags)); + + for (i = 1, mindex = 1, eof = 0; i < argc; ++i) + { + cp = argv[i]; + c = cp[0]; + + if (c != '-' || eof) + { + if (i != mindex) argv[mindex] = argv[i]; + mindex++; + continue; + } + + // -- = end of options. + if (cp[1] == '-' && cp[2] == 0) + { + eof = 1; + continue; + } + + // now scan all the flags in the string... + optarg = NULL; + for (j = 1; ; ++j) + { + c = cp[j]; + if (c == 0) break; + + switch (c) + { + case 'h': + FlagsHelp(); + exit(0); + case 'y': + case 'Y': + flags._y = 1; + break; + case 'n': + case 'N': + flags._n = 1; + break; + case 'c': + case 'C': + flags._c = 1; + break; + + default: + fprintf(stderr, "### Rename - \"-%c\" is not an option.\n", c); + exit(1); + } + + if (optarg) break; + } + } + + return mindex; +} diff --git a/Rename-flags.h b/Rename-flags.h new file mode 100644 index 0000000..9294bec --- /dev/null +++ b/Rename-flags.h @@ -0,0 +1,21 @@ + +#ifndef __flags_h__ +#define __flags_h__ + +typedef struct Flags { + + unsigned _y:1; + unsigned _n:1; + unsigned _c:1; + +} Flags; + + +extern struct Flags flags; + +int FlagsParse(int argc, char **argv); + +void FlagsHelp(void); + +#endif + diff --git a/Rename.c b/Rename.c new file mode 100644 index 0000000..2c32b0b --- /dev/null +++ b/Rename.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018, Kelvin W Sherlock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "FileCommon.h" +#include "Rename-flags.h" + +/* +Rename # rename files and directories +Rename [-y | -n | -c] oldName newName + -resolve # resolve leaf aliases in oldName + -y # overwrite existing file (avoids dialog) + -n # don't overwrite existing file (avoids dialog) + -c # cancel if conflict occurs (avoids dialog) +*/ + + + + +static char error_message[255]; + + +/* + * -1: cancel + * 0: no + * 1: yes + */ +int check(const unsigned char *pname) { + int m = mode(pname, NULL); + if (m <= 0) return 1; /* error or does not exist */ + + if (flags._y) return 1; + if (flags._n) return 0; + if (flags._c) return -1; + + return prompt(pname, "overwrite"); +} + +int do_rename(const unsigned char *src, const unsigned char *dest) { + + /* n.b. - does not move into a directory (use Move for that) */ + int st; + OSErr err; + + st = mode(src, &err); + if (st <= 0) { + + fprintf(stderr, "### Rename - unable to rename %s to %s\n", src+1, dest+1); + fprintf(stderr, "# %s\n", GetSysErrText(err, error_message)); + + if (err == fnfErr) return 2; + return 3; + } + + st = check(dest); + if (st < 0) return 4; + if (st == 0) return 1; + + err = FSDelete((const unsigned char *)dest, 0); + if (err && err != fnfErr) { + fprintf(stderr, "### Rename - unable to delete %s\n", dest+1); + fprintf(stderr, "# %s\n", GetSysErrText(err, error_message)); + return 2; + } + err = Rename((const unsigned char *)src, 0, (const unsigned char *)dest); + if (err) { + fprintf(stderr, "### Rename - unable to rename %s to %s\n", src+1, dest+1); + fprintf(stderr, "# %s\n", GetSysErrText(err, error_message)); + return 3; + } + return 0; +} + +int main(int argc, char **argv) { + + unsigned char *src; + unsigned char *dest; + int status; + + pascalStrings = false; + InitErrMgr(NULL, NULL, true); + + argc = FlagsParse(argc, argv); + + if (flags._c + flags._n + flags._y > 1) { + fprintf(stderr, "### Rename - Conflicting options were specified.\n"); + FlagsHelp(); + return 1; + } + + + if (argc != 3) { + FlagsHelp(); + return 1; + } + + + src = c2p(argv[1]); + dest = c2p(argv[2]); + status = do_rename(src, dest); + free(src); + free(dest); + CloseErrMgr(); + + return status; +} diff --git a/makefile b/makefile index a32c678..13754e5 100644 --- a/makefile +++ b/makefile @@ -33,7 +33,7 @@ LIBS = \ # LDFLAGS = -d -c 'MPS ' -t MPST TARGETS = Help GetEnv Delete Duplicate Files SetFile OverlayIIgs ListRez ListRezIIgs\ - LSegIIgs MakeEnums ReadGlobal Parameters Echo md5 + LSegIIgs MakeEnums ReadGlobal Parameters Echo md5 Rename all: $(TARGETS) @@ -74,6 +74,8 @@ OverlayIIgs: OverlayIIgs.c.o OverlayIIgs-flags.c.o $(LIBRARIES) $(MPW) Link $(LDFLAGS) -o $@ $^ $(LIBS) +Rename: Rename.c.o Rename-flags.c.o FileCommon.c.o $(LIBRARIES) + $(MPW) Link $(LDFLAGS) -o $@ $^ $(LIBS) LTC_H = libtomcrypt/src/hashes/ lib/libtomcrypt : \