home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Crawly Crypt Collection 1
/
crawlyvol1.bin
/
program
/
compiler
/
sozobon
/
scsrc20
/
tools
/
cc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-22
|
23KB
|
1,129 lines
/* Copyright (c) 1988,89,91 by Sozobon, Limited. Author: Tony Andrews
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
static char Version[] =
"cc: version 2.0 Copyright (c) 1988,89,91 by Sozobon, Limited.";
/*
* cc - C compiler driver program
*
* Parses command line for options and file names. Then calls the
* various passes of the compiler as needed.
*/
#include <stdio.h>
#if MINIX || UNIXHOST
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#else
#include <types.h>
#include <stat.h>
#include <osbind.h>
#endif
#if MINIX || UNIXHOST
#define SEPCHAR '/'
#else
#define SEPCHAR '\\'
#endif
#ifndef MINIX
#define rindex strrchr
#define index strchr
#endif
#ifndef TRUE
#define FALSE (0)
#define TRUE !FALSE
#endif
#define MAXOPT 16 /* max. number of options to any one pass */
/*
* Compiler pass information
*/
#if MINIX || UNIXHOST
#define CC "hcc"
#else
#define CC "hcc.ttp"
#endif
char *hccopt[MAXOPT];
int hcc_cnt = 0; /* number of options to hcc */
/*
* Optimizer information
*/
#if MINIX || UNIXHOST
#define OPT "top"
#else
#define OPT "top.ttp"
#endif
char *topopt[MAXOPT];
int top_cnt = 0; /* number of options to top */
/*
* Assembler information
*/
#if MINIX || UNIXHOST
#define ASM "jas"
#define CPP "cpp"
#else
#define ASM "jas.ttp"
#endif
/*
* Loader information
*/
#ifdef MINIX
#define LD "sld"
#else
#ifdef UNIXHOST
#define LD "xld"
#else
#define LD "ld.ttp"
#endif
#endif
char *lsize = NULL; /* process size (from the =N option) */
#ifdef MINIX
#define CSU (pflag ? "mcrtso.o" : "crtso.o") /* C startup code */
#define LIBC (pflag ? "libp/libc.a" : "libc.a") /* C runtime library */
#define LIBM (pflag ? "libp/libm.a" : "libm.a") /* math library */
#else
#define CSU (pflag ? "dstartp.o" : "dstart.o") /* C startup code */
#define LIBC (pflag ? "dlibsp.a" : "dlibs.a") /* C runtime library */
#define LIBM (pflag ? "libmp.a" : "libm.a") /* math library */
#endif
/*
* Path information
*/
char *path; /* where to find executables */
char *lib = NULL; /* where to find library stuff */
char *tmp = NULL; /* where to put temporary files */
/*
* Temp file names
*/
char Sfile[128]; /* temp file for assembly code */
char OSfile[128]; /* temp file for optimized assembly */
char Lfile[128]; /* the loader command file */
/*
* Default paths for executables and libraries
*/
#ifdef MINIX
#define DEFPATH "/usr/sozobon/bin"
#define DEFLIB "/usr/sozobon/lib"
#define DEFTMP "/tmp"
#else
#ifdef UNIXHOST
#define DEFPATH "/home/hans/sozobon/bin"
#define DEFLIB "/home/hans/sozobon/lib"
#define DEFTMP "/tmp"
#else
#define DEFPATH "\\sozobon\\bin"
#define DEFLIB "\\sozobon\\lib"
#define DEFTMP "."
#endif
#endif
/*
* Boolean options
*/
int mflag = 0; /* generate a load map */
int vflag = 0; /* show what we're doing w/ version numbers */
int nflag = 0; /* ...but don't really do it */
int Sflag = 0; /* generate assembly files */
int cflag = 0; /* generate ".s" files only */
int Oflag = 0; /* run the optimizer */
int sflag = 0; /* don't generate a symbol table in executables */
int pflag = 0; /* enable execution profiling */
int rflag = 0; /* enable floating point (Real numbers) */
int fflag = 0; /* scan given file for file names */
int tflag = 0; /* don't remove temporary files */
int gflag = 0; /* disable certain confusing optimizations */
/*
* We build lists of the various file types we're given. Within each
* type, MAXF says how many we can deal with.
*/
#define MAXF 60
int ncfiles = 0; /* .c files */
char *cfiles[MAXF];
int nsfiles = 0; /* .s files */
char *sfiles[MAXF];
int nofiles = 0; /* .o files */
char *ofiles[MAXF];
int nlfiles = 0; /* .a or .lib files (or files with no suffix) */
char *lfiles[MAXF];
#ifdef MINIX
#define DEFOUT "a.out" /* default output file */
#else
#define DEFOUT "a.ttp" /* default output file */
#endif
char *output = NULL; /* output file */
/*
* Argument vectors for the programs we'll run.
*/
#define MAXARG 60
char *av[MAXARG];
int ac;
#define BEGARG() (ac = 0)
#define ADDARG(x) (av[ac++] = (x))
#define ENDARG() (av[ac++] = NULL)
extern int errno;
int got_sig = FALSE; /* TRUE if we got a signal */
usage()
{
#define P(s) fprintf(stderr, s)
P("Sozobon C Compiler Options:\n");
P("-c compile, but don't link\n");
P("-S don't assemble, leave .s files around (-A)\n");
P("-O run the assembly code optimizer\n");
P("-v show what cc is doing\n");
P("-n like -v, but don't really run anything\n");
P("-f file read a list of input files from 'file'\n");
P("-Tdir put temp files in 'dir' (-K)\n");
P("-t don't remove temp files when done (-H)\n");
P("-p enable execution profiling\n");
P("-g compile program for use with the debugger\n");
P("-Ilib add dir. 'lib' to the header search list\n");
P("-Dsym define the pre-processor symbol 'sym' as 1\n");
P("-Dsym=val or as 'val'\n");
P("-Usym un-define the built-in symbol 'sym'\n");
P("-o file use the file 'f' for the loader output (-X)\n");
P("-r link the floating point library (-Q)\n");
P("-lxx load the library libxx.a (-J)\n");
P("-m generate a load map\n");
P("-s don't generate a symbol table (-Y)\n");
P("=nnn make the stack/heap size nnn bytes (Minix only)\n");
P("-R ignored (for Minix compatibility)\n");
P("-w ignored (for Minix compatibility)\n");
#undef P
exit(1);
}
main(argc, argv)
int argc;
char *argv[];
{
#if MINIX || UNIXHOST
int catch(); /* signal handler */
#endif
extern char *chsuf();
register int i;
register char *s;
register int endopt;
int domsg = FALSE;
if (argc == 1)
usage();
#ifdef MINIX
/*
* This is one of the places where ACK blew it. We have to check
* to see if we're in the background before setting up our own
* signal handler. ACK catches the signal anyway, so interrupting
* a foreground process kills any background compiles, too.
*/
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, catch);
#endif
#ifdef UNIXHOST
signal(SIGINT, catch);
#endif
for (i=1; i < argc ;i++) {
if (argv[i][0] == '-') { /* option */
endopt = FALSE;
for (s = &argv[i][1]; *s && !endopt ;s++) {
switch (*s) {
case 'c': case 'C':
cflag = TRUE;
break;
case 'S': case 'a': case 'A':
Sflag = TRUE;
break;
case 'v': case 'V':
vflag = TRUE;
break;
case 'n': case 'N':
nflag = TRUE;
break;
case 'm': case 'M':
mflag = TRUE;
break;
case 's': case 'y': case 'Y':
sflag = TRUE;
break;
case 'r': case 'q': case 'Q':
rflag = TRUE;
break;
case 'p': case 'P':
pflag = TRUE;
break;
case 'g': case 'G':
gflag = TRUE;
break;
case 'o': case 'x': case 'X':
output = argv[++i];
endopt = TRUE;
break;
case 'l': case 'j': case 'J':
keeplib(s+1);
endopt = TRUE;
break;
case 'f': case 'F':
getfiles(argv[++i]);
endopt = TRUE;
break;
/*
* Minix compatibility
*/
case 'R': /* ignored */
case 'w': case 'W':
break;
case 'T': case 'k': case 'K':
tmp = s+1;
endopt = TRUE;
break;
case 't': case 'h': case 'H':
tflag = TRUE;
break;
/*
* Options for other passes.
*/
case 'I': /* compiler options */
case 'D':
case 'U':
hccopt[hcc_cnt++] = argv[i];
endopt = TRUE;
break;
case 'z': case 'Z':
*s = 'O';
/* fall through */
case 'O':
/*
* Enable the optimizer, possibly with
* options specifically for it.
*/
Oflag = TRUE;
if (s[1] != '\0')
topopt[top_cnt++] = argv[i];
endopt = TRUE;
break;
default:
usage();
}
}
} else if (argv[i][0] == '=') { /* heap/stack size for ld */
lsize = argv[i];
} else /* input file */
keepfile(argv[i]);
}
doinit();
if ((ncfiles + nsfiles) > 1)
domsg = TRUE;
if (vflag && !nflag)
printf("%s\n", Version);
for (i = 0; i < ncfiles ;i++) {
if (domsg)
printf("%s:\n", cfiles[i]);
docomp(cfiles[i]);
doopt(cfiles[i]);
doasm(cfiles[i], TRUE);
}
for (i = 0; i < nsfiles ;i++) {
if (domsg)
printf("%s:\n", sfiles[i]);
doasm(sfiles[i], FALSE);
}
dold(); /* run the loader */
exit(0);
}
/*
* doinit() - set up some variables before getting started
*/
doinit()
{
char *getenv();
if ((path = getenv("PATH")) == NULL)
path = DEFPATH;
if ((lib = getenv("LIB")) == NULL)
lib = DEFLIB;
if (tmp == NULL) {
if ((tmp = getenv("TMPDIR")) == NULL)
tmp = DEFTMP;
}
sprintf(Sfile, "%s%cC%05d.s", tmp, SEPCHAR, getpid());
sprintf(OSfile, "%s%cCO%05d.s", tmp, SEPCHAR, getpid());
sprintf(Lfile, "%s%cCL%05d.ld", tmp, SEPCHAR, getpid());
}
#if MINIX || UNIXHOST
catch()
{
signal(SIGINT, catch);
got_sig = TRUE;
}
#endif
/*
* getfiles(f) - read file names from the given file
*/
getfiles(f)
char *f;
{
char *strsave();
char name[64];
FILE *fp;
if ((fp = fopen(f, "r")) == NULL) {
fprintf(stderr, "cc: can't open file '%s'\n", f);
return;
}
while (scanf("%s", name))
keepfile(strsave(name));
fclose(fp);
}
/*
* keeplib(l) - save a library reference
*
* Given an option like "-lm", keeplib saves a reference to a library file
* named "libm.a". The usual places will be searched for the library when
* the time comes. keeplib() should be called with the "-l" stripped off.
*/
keeplib(l)
char *l;
{
char *strsave();
char name[32];
sprintf(name, "lib%s.a", l);
keepfile(strsave(name));
}
/*
* keepfile(f) - remember the filename 'f' in the appropriate place
*/
keepfile(f)
char *f;
{
char *p, *rindex();
if ((p = rindex(f, '.')) == NULL) { /* no suffix */
lfiles[nlfiles++] = f;
return;
}
if ((strcmp(p, ".c") == 0) || (strcmp(p, ".C") == 0)) {
cfiles[ncfiles++] = f;
return;
}
if ((strcmp(p, ".s") == 0) || (strcmp(p, ".S") == 0)) {
sfiles[nsfiles++] = f;
return;
}
if ((strcmp(p, ".o") == 0) || (strcmp(p, ".O") == 0)) {
ofiles[nofiles++] = f;
return;
}
if ((strcmp(p, ".a") == 0) || (strcmp(p, ".A") == 0)) {
lfiles[nlfiles++] = f;
return;
}
fprintf(stderr, "cc: unknown file suffix '%s'\n", f);
exit(1);
}
/*
* chsuf(f, suf) - change the suffix of file 'f' to 'suf'.
*
* Space for the new string is obtained using malloc().
*/
char *
chsuf(f, suf)
char *f;
char *suf;
{
char *malloc();
char *s, *p;
p = s = malloc(strlen(f) + strlen(suf) + 1);
strcpy(p, f);
for (; *p ; p++) {
if (*p == '.')
break;
}
while (*suf)
*p++ = *suf++;
*p = '\0';
return s;
}
/*
* isfile(f) - return true if the given file exists
*/
int
isfile(f)
char *f;
{
struct stat sbuf;
if (stat(f, &sbuf) < 0)
return FALSE;
return TRUE;
}
/*
* findfile(e, b)
*
* Finds a file in one of the directories given in the environment
* variable whose value is pointed to by 'e'. Looks for the file
* given by the name 'b'.
*
* Returns a pointer to a static area containing the pathname of the
* file, if found, NULL otherwise.
*/
char *
findfile(e, b)
char *e;
register char *b;
{
static char file[256];
char env[256];
register char *p;
/*
* Make a copy of the value of the env. variable. Convert all
* delimiters to nulls.
*/
if (e != NULL) {
strcpy(env, e);
for (p = env; *p ;p++) {
#if MINIX || UNIXHOST
if (*p == ':')
#else
if (*p == ';' || *p == ',')
#endif
*p = '\0';
}
p[1] = '\0'; /* double null terminator */
} else
env[1] = env[0] = '\0';
p = env;
/*
* An initial null means to try the current directory.
*/
if (*p == '\0') {
if (isfile(b))
return b;
p++;
}
while (*p) {
sprintf(file, "%s%c%s", p, SEPCHAR, b);
if (isfile(file))
return file;
while (*p++ != '\0')
;
}
return NULL; /* give up */
}
#if MINIX || UNIXHOST
/*
* docmd(path, argv) - run a command
*
* We check for an interrupt before and after executing the command.
* The sub-processes we run are the only very time-consuming thing we
* do in 'cc', so there's not much point in checking for signals in
* other places. When a signal comes in, we just delete the temp files.
*/
int
docmd(path, argv)
char *path;
char *argv[];
{
void cleanup();
int i;
int pid, status;
char buf[512];
int dosystem = FALSE;
if (vflag || nflag) {
fprintf(stderr, "%s", path);
for (i=1; argv[i] != NULL ;i++)
fprintf(stderr, " %s", argv[i]);
fputc('\n', stderr);
fflush(stderr);
if (nflag)
return 0;
}
/*
* Figure out whether exec() is okay or we need a shell.
*/
for (i=1; argv[i] != NULL ;i++)
if (argv[i][0] == '>' || argv[i][0] == '<')
dosystem = TRUE;
if (got_sig)
cleanup();
if (dosystem) {
strcpy(buf, path);
for (i=1; argv[i] != NULL ;i++) {
strcat(buf, " ");
strcat(buf, argv[i]);
}
return system(buf);
} else {
/*
* Fork and exec the command.
*/
if ((pid = fork()) < 0) {
fprintf(stderr, "cc: can't fork\n");
return -1;
}
if (pid == 0) { /* the child */
execv(path, argv);
fprintf(stderr, "cc: Can't exec '%s'\n", path);
exit(1);
} else { /* the parent */
if (wait(&status) == -1 && errno != EINTR) {
fprintf(stderr,"cc: wait failed (%d)\n", errno);
return -1;
} else if ((status & 0xff) == 0)
return (status >> 8);
}
}
if (got_sig)
cleanup();
return -1;
}
void
cleanup()
{
unlink(Sfile);
unlink(OSfile);
unlink(Lfile);
exit(1);
}
#else
/*
* docmd(path, argv) - run a command
*/
int
docmd(path, argv)
char *path;
char *argv[];
{
int i;
char cmdline[130];
char *cmd;
cmd = &cmdline[1];
*cmd = '\0';
for (i=1; argv[i] != NULL ;i++) {
if (i > 1)
strcat(cmd, " ");
strcat(cmd, argv[i]);
}
cmdline[0] = strlen(cmd);
if (vflag || nflag) {
fprintf(stderr, "%s %s\n", path, cmd);
fflush(stderr);
if (nflag)
return 0;
}
i = Pexec(0, path, cmdline, 0L);
return i;
}
#endif
/*
* docomp(f) - run the compiler on the given .c file
*/
docomp(f)
char *f;
{
int i;
char *cpath, *sf;
char tbuf[128];
char sbuf[128];
int notmp; /* don't use temp directory */
/*
* Don't use a temp directory if all we want is the assembly file,
* and we're not optimizing.
*/
notmp = (Sflag && !Oflag);
if ((cpath = findfile(path, CC)) == NULL) {
fprintf(stderr, "cc: can't find compiler program '%s'\n", CC);
exit(1);
}
BEGARG();
ADDARG(CC);
if (!notmp) {
sprintf(tbuf, "-T%s", tmp);
ADDARG(tbuf);
}
if (pflag)
ADDARG("-P");
for (i=0; i < hcc_cnt ;i++)
ADDARG(hccopt[i]);
ADDARG(f);
ENDARG();
sf = chsuf(f, ".s");
if (notmp)
strcpy(sbuf, sf);
else
sprintf(sbuf, "%s%c%s", tmp, SEPCHAR, sf);
free(sf);
if (docmd(cpath, av)) {
fremove(sbuf);
fprintf(stderr, "cc: compiler failed\n");
exit(1);
}
if (!notmp)
frename(sbuf, Sfile); /* fix the temp file name */
}
/*
* doopt(f) - run the optimizer
*
* Only optimize files that were produced by the compiler.
*/
doopt(f)
char *f;
{
int i;
char *opath;
char *sf;
char *of; /* the output file name */
if (!Oflag)
return;
if ((opath = findfile(path, OPT)) == NULL) {
fprintf(stderr, "cc: can't find optimizer program '%s'\n", OPT);
exit(1);
}
sf = chsuf(f, ".s");
BEGARG();
ADDARG(OPT);
for (i=0; i < top_cnt ;i++)
ADDARG(topopt[i]);
/*
* The -g option turns off certain optimizations that make the
* debugger more difficult to use. These mostly involve messing
* with the stack frame, and make it harder to get accurate
* stack backtraces while stepping through a program.
*/
if (gflag)
ADDARG("-g");
ADDARG(Sfile); /* the input file */
of = (Sflag) ? sf : OSfile; /* what's the output file name? */
ADDARG(of);
ENDARG();
if (docmd(opath, av)) {
if (Sflag) { /* error is fatal if we wanted the assembly */
fremove(Sfile);
fremove(of);
fprintf(stderr, "cc: optimizer failed (aborting)\n");
exit(1);
} else { /* try to press on... */
/*
* We continue by pretending we optimized the
* assembly file when we really didn't.
*/
frename(Sfile, of);
fprintf(stderr, "cc: optimizer failed (continuing)\n");
}
}
free(sf);
fremove(Sfile);
}
/*
* doasm() - run the assembler
*
* If 'istmp' is TRUE, the file we were given is a temporary. If we aren't
* working on a temp file, we may need to run the assembly through the C
* preprocessor. If the first character in the file is '#', we do it.
*/
doasm(f, istmp)
char *f;
int istmp;
{
char *strrchr(), *getenv();
int i;
char *dpath;
char *sf; /* file.s */
char *infile; /* the assembler input file */
char *outfile; /* the assembler output */
if (Sflag)
return;
outfile = chsuf(f, ".o");
/*
* We want the -o option to be able to specify the output file
* from the assembler. This only makes sense if -c is given, and
* there is only one input file.
*/
if (cflag && (output != NULL) && ((ncfiles+nsfiles) == 1))
outfile = output;
/*
* Assume a temp file for now. May change...
*/
infile = (Oflag) ? OSfile : Sfile;
/*
* If this isn't a temp file, we may have to run the C preprocessor
* on it. If the first character of the file isn't '#', then we can
* skip it and just run the assembler.
*/
if (!istmp) {
#ifdef MINIX
int fd;
char c;
if ((fd = open(f, 0)) < 0) {
fprintf(stderr, "cc: can't open file '%s'\n", f);
exit(1);
}
if (read(fd, &c, 1) != 1) {
fprintf(stderr, "cc: can't read file '%s'\n", f);
exit(1);
}
close(fd);
if (c == '#') {
if ((dpath = findfile(lib, CPP)) == NULL) {
fprintf(stderr,
"cc: can't find C preprocessor '%s'\n",
CPP);
exit(1);
}
BEGARG();
ADDARG(dpath);
/*
* The -P option removes "#file" and "#line" directives
* from the generated output.
*/
ADDARG("-P");
/*
* Include any pre-processor directives (-D, -I, or -U)
*/
for (i=0; i < hcc_cnt ;i++)
ADDARG(hccopt[i]);
ADDARG(f);
ADDARG(">");
ADDARG(Sfile);
ENDARG();
if (docmd(dpath, av)) {
fprintf(stderr,
"cc: preprocessor failed '%s'\n", f);
fremove(Sfile);
exit(1);
}
infile = Sfile;
} else
infile = f;
#else
infile = f;
#endif
}
if ((dpath = findfile(path, ASM)) == NULL) {
fprintf(stderr, "cc: can't find assembler program '%s'\n", ASM);
exit(1);
}
BEGARG();
ADDARG(ASM);
ADDARG(infile);
ADDARG("-o");
ADDARG(outfile);
ENDARG();
if (docmd(dpath, av)) {
fprintf(stderr, "cc: assembler failed '%s'\n", infile);
if (infile != f)
fremove(infile);
exit(1);
}
free(outfile);
if (infile != f)
fremove(infile);
}
/*
* dold() - run the loader
*/
dold()
{
FILE *fp, *fopen();
int i;
char *lpath;
char *s;
char *l;
if (cflag || Sflag)
return;
/*
* Construct loader command file
*/
if ((fp = fopen(Lfile, "w")) == NULL) {
fprintf(stderr, "cc: can't open loader temp file\n");
exit(1);
}
if ((lpath = findfile(lib, CSU)) == NULL) {
fprintf(stderr, "cc: can't find C startup code '%s'\n", CSU);
exit(1);
}
fprintf(fp, "%s\n", lpath);
for (i = 0; i < ncfiles ;i++) {
s = chsuf(cfiles[i], ".o");
fprintf(fp, "%s\n", s);
free(s);
}
for (i = 0; i < nsfiles ;i++) {
s = chsuf(sfiles[i], ".o");
fprintf(fp, "%s\n", s);
free(s);
}
for (i = 0; i < nofiles ;i++)
fprintf(fp, "%s\n", ofiles[i]);
for (i = 0; i < nlfiles ;i++) {
if (isfile(lfiles[i])) {
fprintf(fp, "%s\n", lfiles[i]);
} else {
lpath = findfile(lib, lfiles[i]);
if (lpath == NULL) {
fprintf(stderr, "cc: can't find library '%s'\n", lfiles[i]);
exit(1);
}
fprintf(fp, "%s\n", lpath);
}
}
if (rflag) {
if ((lpath = findfile(lib, LIBM)) == NULL) {
fprintf(stderr, "cc: can't find floating point library '%s'\n", LIBM);
exit(1);
}
fprintf(fp, "%s\n", lpath);
}
if ((lpath = findfile(lib, LIBC)) == NULL) {
fprintf(stderr, "cc: can't find C runtime library '%s'\n",LIBC);
exit(1);
}
fprintf(fp, "%s\n", lpath);
fclose(fp);
if ((lpath = findfile(path, LD)) == NULL) {
fprintf(stderr, "cc: can't find loader program '%s'\n", LD);
exit(1);
}
BEGARG();
ADDARG(LD);
ADDARG("-p");
ADDARG("-b");
if (lsize != NULL)
ADDARG(lsize);
if (mflag)
ADDARG("-m");
if (!sflag)
ADDARG("-t");
if (rflag) {
ADDARG("-u");
ADDARG("__printf");
ADDARG("-u");
ADDARG("__scanf");
}
ADDARG("-o");
ADDARG((output != NULL) ? output : DEFOUT);
ADDARG("-f");
ADDARG(Lfile);
if (docmd(lpath, av)) {
fprintf(stderr, "cc: loader failed\n");
fremove(Lfile);
fremove(output);
exit(1);
}
for (i = 0; i < ncfiles ;i++) {
s = chsuf(cfiles[i], ".o");
fremove(s);
free(s);
}
for (i = 0; i < nsfiles ;i++) {
s = chsuf(sfiles[i], ".o");
fremove(s);
free(s);
}
fremove(Lfile);
}
int
frename(f1, f2)
char *f1, *f2;
{
if (vflag || nflag)
fprintf(stderr, "mv %s %s\n", f1, f2);
#if MINIX || UNIXHOST
unlink(f2);
link(f1, f2);
unlink(f1);
#else
rename(f1, f2);
#endif
}
fremove(f)
char *f;
{
if (vflag || nflag)
fprintf(stderr, "rm %s\n", f);
if (!tflag)
unlink(f);
}
char *
strsave(string)
char *string;
{
char *malloc(), *strcpy();
return (strcpy(malloc((unsigned)(strlen(string)+1)), string));
}