home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
- / cio.c - This is a C program to replace the over-grown shell script
- / that started as something small...
- /
- / Authors: Jason P. Winters and Craig J. Kim
- /
- / We hereby declare this software to be Public Domain. That means we don't
- / care what you do with it. We _would_ prefer that you at least leave our
- / names in it, as befits Authors, but we can't force you. Of course, since
- / it's public domain, all risks/gains using it are your problems. You don't
- / have any reason to call us up and complain about it deleting 30megs of
- / your source code without telling you. ( Software should at least *tell* you
- / when it does something like that, right? ) :)
- /
- / Start Date: November 23, 1988
- / Revisions: 29-Nov-88 jpw - initial coding completed.
- / 29-Nov-88 cjk - rewrite of front-end logic
- / 30-Nov-88 jpw - Added signals, cleanup of temp files.
- / 30-Nov-88 cjk - added -N option
- / 01-Dec-88 cjk - added usage
- / 01-Dec-88 jpw - added SUID controls for secure files.
- / 02-Dec-88 jpw - added -A option
- / 05-Dec-88 cjk - added '~' commands for message entering
- / 05-Dec-88 cjk - fixed cp to check file status before copying
- / 06-Dec-88 cjk - use separate process for user file input
- / 06-Dec-88 jpw - source now passes System V.2 lint
- / 07-Dec-88 cjk - added environment variable check routine
- / 20-Dec-88 cjk - chmod files in source dir to 0640
- / 21-Dec-88 cjk - put RCS header if not exists
- / 08-Mar-89 cjk - SCCS version
- / 02-Oct-89 jpw - Fixed parsing for header type to insert
- / Fixed small bug in directory creation routine
- / 10-May-90 jpw - Changed st += sprintf() code to allow for
- / broken sprint() calls. Failed on Sun
- / machines.
- /
- / Known bugs:
- / On some systems, the Control-D as end of input in the log entry
- / routines will cause stdin to be closed, which means the next call
- / to get an entry (such as a Title file) will fail. A call to clearerr()
- / has been added to fix this, but it has not been tested.
- /
- / To be done:
- / 1. When -U is used, the destination directory should be created if
- / it does not exist already. Also, the file mode should be changed to
- / 0640 so that overwriting is not possible by anyone other than
- / $RCSOWN for security.
- / 2. Full "interactive" mode support
- / 3. Actually use the SCCS version. (Ugh!)
- /---------------------------------------------------------------------------*/
-
- /*#define DEBUG /* wanna know what's goin' on? */
- /*#define INTERACTIVE /* enable -I option (incomplete) */
- /*#define void int /* if system can't handle void types. */
- #define V_RCS /* RCS version */
- /*#define V_SCCS /* SCCS version */
-
- /*--------------------------------------------------- includes -------------*/
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <signal.h>
- #include <fcntl.h>
-
- /* #ifdef OS2
- #define popen _popen
- #define pclose _pclose
- #endif */
-
- #ifndef OS2
- #define stricmp strcmp
- #define strnicmp strncmp
- #endif
-
- /*--------------------------------------------------- externals ------------*/
- extern FILE *fopen(); /* open a stream (should be in stdio.h) */
- extern FILE *popen(); /* open a pipe (should be in stdio.h) */
- extern char *getenv(); /* read an environment variable */
- extern char *tmpnam(); /* create a temporary file name */
- extern char *mktemp(); /* create temp file with a template */
- extern char *malloc(); /* allocate a chunk of memory */
- extern char *getcwd(); /* get current directory */
- extern int unlink(); /* unlink (delete) a file */
- extern void exit(); /* define these for LINT!!!! */
- extern void perror(); /* define these for LINT!!!! */
- extern void free(); /* define these for LINT!!!! */
-
- /*--------------------------------------------------- defines --------------*/
- #ifndef TRUE
- # define TRUE 1
- # define FALSE 0
- #endif
-
- #define TYPE_LOG 0 /* log message */
- #define TYPE_TITLE 1 /* title message */
- #define MAX_LOG 1020 /* max # of characters for a log */
-
- /*--------------------------------------------------- forwards -------------*/
- void usage(/*_ void _*/); /* print program usage message */
- int getfinput(/*_ char *name, int type _*/); /* get title file */
- int child_getfinput(/*_ char *name, int type _*/); /* actual get file */
- void doincmds(/*_ char *argv[], int argc, int in _*/); /* perform user wish */
- void do_ciodir(/*_ char *filenm _*/); /* do user wish in recursive if -R */
- int cio(/*_ char *filenme _*/); /* the work horse */
- int addrcsext(/*_ char *fname _*/); /* add RCS file name extension */
- int rmrcsext(/*_ char *fname _*/); /* remove RCS file name extension */
- void inshdr(/*_ char *fname _*/); /* insert RCS header */
- int makedir(/*_ char *path _*/); /* make a directory and all its parent */
- char *strstr(/*_ char *s1, char *s2 _*/); /* find a string within a string */
- char *strlwr(/*_ char *s _*/); /* convert upper case to lower */
- int asciifile(/*_ char *filename _*/); /* check file type */
- int rcsfile(/*_ char *filename _*/); /* check file is RCS file */
- int strrd(/*_ char *buf, int max_size, FILE *fle _*/);/* read from a file */
- void getdir(/*_ void _*/); /* obtain necessary directory information */
- int fix_envstr(/*_ char *cs _*/); /* remove leading/trailing blanks, etc. */
- void getrcsdir(/*_ char *dir _*/); /* build rcs dir out of working */
- void getworkdir(/*_ char *dir _*/); /* build working dir out of rcs */
- void getsrcdir(/*_ char *dir _*/); /* build source dir out of working */
- char *justname(/*_ char *fpath _*/); /* return just filename portion */
- char *memalloc(/*_ int size _*/); /* allocate memory and check for success */
- void sigcleanup(/*_ void _*/); /* cleanup in case interrupt */
- void get_final_id(/*_ void _*/); /* get user id of RCS file owner */
- int nextent(/*_ FILE *fp _*/); /* read next entry from /etc/passwd file */
-
- /*--------------------------------------------------- globals --------------*/
- #ifdef V_RCS
- char *ci_cmd = "ci"; /* command to use to check in a module. */
- char *co_cmd = "co"; /* command to use to check out a module. */
- #else
- char *ici_cmd = "admin"; /* command to check in a module for 1st time. */
- char *ci_cmd = "delta"; /* command to check in a module. */
- char *co_cmd = "get"; /* command to check out a module. */
- #endif
- char *currentdir; /* current directory. */
- char *homedir; /* user's home directory. */
- char *rcswrk; /* $RCSWORK. */
- char *rcsown; /* $RCSOWN. */
- char *rcsdir; /* $RCSDIR. */
- char *srcdir; /* $RCSSRC. */
- char *headdir; /* $RCSHEAD. */
- char *path; /* $PATH. */
- char *pwdfile = "/etc/passwd"; /* default passwd file. */
- char cioopt[100]; /* large buffer for command options. */
- char d_ent[90]; /* small buffer for file reads. */
- char final[400]; /* final dir to pass on as destination. */
- #ifdef V_SCCS
- char finalfile[400]; /* final file without SCCS extension. */
- #endif
- char logstr[MAX_LOG + 4]; /* log string to pass. */
- char title[100]; /* log string to pass. */
- char cmdbuf[2400]; /* do a single file. */
- char editfile[400]; /* temp edit file, makes cleanup easy. */
- char pwdname[20]; /* Name found in file. */
- char ftypestr[82]; /* command file(1) output. */
- char cii = FALSE; /* if set, we are in check in mode. */
- char recurse = FALSE; /* if set, do recursive check in/out's. */
- char usertitle = FALSE; /* user specified title file. */
- char interactive = FALSE; /* user friendly interactive mode. */
- char allfiles = FALSE; /* set it TRUE to copy all files. */
- char insertheader = FALSE; /* insert RCS header at the top of the file. */
- #ifdef DEBUG
- char noexec = TRUE; /* set it FALSE for execution mode. */
- char verbose = TRUE; /* be a chatterbox. */
- #else
- char noexec = FALSE; /* set it TRUE for no execution mode. */
- char verbose = FALSE; /* not a chatterbox. */
- #endif
- char updsrcdir = FALSE; /* update master source directory on cii. */
- #ifdef V_SCCS
- char do_admin = FALSE; /* set it TRUE if first check in. */
- #endif
- char *prognam; /* name of this program. */
- struct stat filestat; /* file status info. */
- int s_currentdir; /* length of current directory. */
- int s_homedir; /* length of user's home directory. */
- int s_rcswrk; /* length of $RCSWORK. */
- int s_rcsdir; /* length of $RCSDIR. */
- int s_srcdir; /* length of $RCSSRC. */
- int s_path; /* length of $PATH. */
- int s_rcsown; /* length of $RCSOWN. */
- int s_headdir; /* length of $RCSHEAD. */
- int user_id; /* Effective user id to use if ROOT process. */
- int real_user_id; /* Save buffer for original user_id. */
- int do_unlink; /* add -l option if not set to avoid unlink of source file. */
-
- /*--------------------------------------------------- main() ----------------
- / where we begin!
- /---------------------------------------------------------------------------*/
- main(argc, argv)
- int argc;
- char *argv[];
- {
- register int in;
- register char *cp; /* used in string updates. */
-
- prognam = justname(argv[0]); /* program name */
- #ifdef OS2
- if ( stricmp(prognam + 3, ".exe") == 0 )
- prognam[3] = 0;
- #endif
- getdir(); /* go get the enviroment pointers. */
-
- /*
- * figure what the user wants us to be by reading program name
- */
- if (!stricmp("ciitest", prognam) || !stricmp("cootest", prognam))
- {
- getrcsdir(final, currentdir); /* setup variables. */
- /*
- * print out our variables here.
- */
- #ifdef V_RCS
- (void) printf("Homedir:%s: rcsdir:%s: rcswrk:%s: rcssrc:%s:\n",
- #else
- (void) printf("HOME:%s: SCCSDIR:%s: SCCSWRK:%s: SCCSSRC:%s:\n",
- #endif
- homedir ? homedir : "",
- rcsdir ? rcsdir : "",
- rcswrk ? rcswrk : "",
- srcdir ? srcdir : "");
- (void) printf("Final dir:%s:\n", final);
- return(0);
- }
- if (!stricmp("cii", prognam)) /* this is input.. */
- cii = TRUE; /* show we are inputs. */
- else if (stricmp("coo", prognam))/* it's not this either.. */
- {
- (void) printf("Just what did you think this program was, anyway??\n");
- return(-1);
- }
-
- #ifndef OS2
- if (!(user_id = geteuid())) /* we are a root process.. */
- {
- (void) umask(027); /* set general mask to private modes. */
- real_user_id = getuid();
- if (cii) /* only set this if we are in checkin mode. */
- get_final_id(); /* go get the final user ID for file creation. */
- else
- user_id = real_user_id; /* otherwise, use owners real one. */
- (void) setuid(user_id); /* and, fix up the user id now. */
- #ifdef DEBUG
- (void) printf("Using Uid:%d:\n", user_id);
- #endif
- }
- else
- real_user_id = user_id; /* else they should match. */
- #else
- real_user_id = 1; /* else they should match. */
- #endif
-
- /* prepare for disasters */
- (void) signal(SIGINT, (int (*)()) sigcleanup);
- #ifndef OS2
- (void) signal(SIGQUIT, (int (*)()) sigcleanup);
- #else
- (void) signal(SIGBREAK, (int (*)()) sigcleanup); /* OS/2 */
- (void) signal(SIGTERM, (int (*)()) sigcleanup); /* signals */
- #endif
-
- if ( argc <= 1 )
- {
- usage();
- return(0);
- }
-
- cp = cioopt;
- title[0] = '\0'; /* make sure no titles are required. */
- for (in = 1; argv[in][0] == '-'; in++) /* while chars here.. */
- {
- switch ((int) argv[in][1]) /* what option? */
- {
- case '?': /* print program usage */
- case '-':
- usage();
- return(0);
- case 'A': /* copy all files */
- allfiles = !allfiles;
- break;
- #ifdef INTERACTIVE
- case 'I': /* interactive mode */
- interactive = !interactive;
- break;
- #endif
- case 'H': /* RCS/SCCS header */
- insertheader = !insertheader;
- break;
- case 'N': /* do not execute */
- noexec = !noexec;
- break;
- case 'R': /* Recursion flag. */
- recurse = !recurse;
- break;
- case 'T': /* get Title flag. */
- if(cii) /* get a title file and name. */
- (void) getfinput(title, TYPE_TITLE);
- break;
- case 'U': /* update working directory */
- updsrcdir = !updsrcdir;
- break;
- case 'V': /* verbose */
- verbose = !verbose;
- break;
- #ifdef V_RCS
- case 'm': /* they gave us one */
- #else
- case 'y': /* they gave us one */
- #endif
- (void) strcpy(logstr, &argv[in][1]); /* copy across. */
- break;
- case 't': /* user gave us one */
- (void) strcpy(title, &argv[in][1]);
- usertitle = TRUE;
- break;
- default: /* must be a ci or co command */
- (void) sprintf(cp, " %s", argv[in]); /* append */
- cp += strlen(cp); /* skip to end of string. */
- break;
- }
- }
- #ifdef INTERACTIVE
- if (noexec && interactive) /* resolve conflict of interest */
- interactive = FALSE;
- #endif
- doincmds(argv, argc, in); /* do the check in command. */
- if (title[0] && !usertitle) /* if file is here. */
- (void) unlink(title); /* zap it! */
- return(0); /* we did it good! */
- }
-
- /*--------------------------------------------------- usage() ---------------
- / print program usage information
- /---------------------------------------------------------------------------*/
- void
- usage()
- {
- char *inout = cii ? "in" : "out";
-
- #ifdef INTERACTIVE
- (void) fprintf(stderr, "Usage: %s [-A] %s[-I] [-N] [-R] %s",
- #else
- (void) fprintf(stderr, "Usage: %s [-A] %s[-N] [-R] %s",
- #endif
- prognam, cii ? "[-H] " : "",
- cii ? "[-T] [-U] " : "");
- (void) fprintf(stderr, "[-V] [%s options] [[filename]...]\n",
- cii ? ci_cmd : co_cmd);
- (void) fprintf(stderr, " -A : check %s all files\n", inout);
- #ifdef INTERACTIVE
- (void) fprintf(stderr, " -I : interactive mode\n");
- #endif
- if (cii)
- #ifdef V_RCS
- (void) fprintf(stderr, " -H : attach RCS header\n");
- #else
- (void) fprintf(stderr, " -H : attach SCCS header\n");
- #endif
- (void) fprintf(stderr, " -N : no execute mode\n");
- (void) fprintf(stderr, " -R : recursive check %s\n", inout);
- if (cii)
- {
- (void) fprintf(stderr, " -T : create title file\n");
- (void) fprintf(stderr, " -U : update source directory\n");
- }
- (void) fprintf(stderr, " -V : verbose mode\n");
- }
-
- /*--------------------------------------------------- sigcleanup() ----------
- / cleanup before exiting.
- /---------------------------------------------------------------------------*/
- void
- sigcleanup()
- {
- (void) printf("\n[%s: Interrupted]\n", prognam);
- if (title[0] && !usertitle) /* remove title file, if here. */
- (void) unlink(title);
- if (editfile[0]) /* if a temp file might be here. */
- (void) unlink(editfile); /* attempt to remove it.*/
- exit(0);
- }
-
- /*--------------------------------------------------- doincmds() ------------
- / actual do routine
- /---------------------------------------------------------------------------*/
- void
- doincmds(argv, argc, in)
- char *argv[];
- int argc, in;
- {
- register char *cp;
- char entry[400];
-
- if (cii)
- {
- if (argc == in) /* no arguments given */
- {
- do_ciodir(currentdir);
- return /* void */;
- }
- for ( ; in < argc; in++)
- {
- #ifdef OS2
- UnixFileName(argv[in]);
- #endif
- (void) sprintf(entry, "%s%s", currentdir, argv[in]);
- #ifdef DEBUG
- (void) printf("Processing %s\n", entry);
- #endif
- if (stat(entry, &filestat))
- {
- #ifdef DEBUG
- (void) printf("Unable to stat(2) %s\n", entry);
- #endif
- continue;
- }
- do_unlink = (filestat.st_uid == real_user_id);
- if ((filestat.st_mode & S_IFMT) == S_IFDIR)
- do_ciodir(entry);
- else
- (void) cio(entry);
- }
- }
- else /* coo */
- {
- char *ep;
-
- getrcsdir(entry, currentdir);
- if (argc == in)
- {
- do_ciodir(entry);
- return /* void */;
- }
- for (ep = entry; *ep; ep++)
- ;
- for ( ; in < argc; in++)
- {
- #ifdef OS2
- UnixFileName(argv[in]);
- #endif
- (void) sprintf(ep, "%s", argv[in]);
- #ifdef DEBUG
- (void) printf("Processing %s\n", entry);
- #endif
- if (stat(entry, &filestat))
- {
- if (!addrcsext(entry))
- continue;
- if (stat(entry, &filestat))
- continue;
- }
- do_unlink = (filestat.st_uid == real_user_id);
- if ((filestat.st_mode & S_IFMT) == S_IFDIR)
- do_ciodir(entry);
- else
- (void) cio(entry);
- }
-
- }
- return /* void */;
- }
-
- /*--------------------------------------------------- do_ciodir() -----------
- / actual do routine - Warning: RECURSIVE
- /---------------------------------------------------------------------------*/
- void
- do_ciodir(dir)
- char *dir;
- {
- FILE *pp;
- char *cmd, *entry;
-
- if ( dir[strlen(dir) - 1] == '/' )
- dir[strlen(dir) - 1] = 0;
- (void) sprintf(cmd = memalloc(strlen(dir) + 4), "ls %s", dir);
- pp = popen(cmd, "r");
- free(cmd);
- if (!pp)
- return /* void */;
- entry = memalloc(strlen(dir) + 30);
- while (strrd(d_ent, 80, pp) != -1)
- {
- (void) sprintf(entry, "%s/%s", dir, d_ent);
- if (stat(entry, &filestat))
- {
- #ifdef DEBUG
- (void) printf("Unable to stat(2) %s\n", entry);
- #endif
- continue;
- }
- do_unlink = (filestat.st_uid == real_user_id);
- if ((filestat.st_mode & S_IFMT) == S_IFDIR)
- {
- if (recurse)
- do_ciodir(entry);
- else
- continue;
- }
- else
- (void) cio(entry);
- }
- free(entry);
- (void) pclose(pp);
- return /* void */;
- }
-
- /*--------------------------------------------------- cio() -----------------
- / do this to file, if we can.
- /---------------------------------------------------------------------------*/
- int
- cio(filename)
- char *filename;
- {
- register char *cp, *st; /* some char pointers */
- int do_copy = FALSE; /* do cp(1) */
- char titlest[100]; /* for file names. */
-
- if (cii)
- {
- if (!asciifile(filename)) /* if not ascii file */
- {
- if (!allfiles)
- return(FALSE); /* don't if not forced copy */
- do_copy = TRUE;
- }
- else if (insertheader) /* inserting default header */
- {
- inshdr(filename);
- }
- }
- else if (!rcsfile(filename)) /* not an RCS file */
- {
- if (!allfiles)
- return(FALSE);
- do_copy = TRUE; /* simply cp(1) it */
- }
-
- if (cii && !do_copy && !logstr[0]) /* we don't have a log entry yet. */
- {
- if (noexec)
- {
- (void) printf("Logfile entry bypassed.\n");
- (void) strcpy(logstr, ""); /* fake it */
- }
- else if (!getfinput(titlest, TYPE_LOG)) /* if we entered anything */
- {
- FILE *fp;
- char buf[100];
- register char *bp;
- register int numchars = 0;
-
- if (fp = fopen(titlest, "r"))
- {
- st = logstr;
- #ifdef V_RCS
- (void) sprintf(st, " -m\"");
- #else
- (void) sprintf(st, " -y\"");
- #endif
- st += strlen(st); /* skip to end of string. */
- while (strrd(buf, 80, fp) != -1)
- { /*
- * escape quotes (") characters
- */
- bp = buf;
- while (*bp)
- {
- if (*bp == '"')
- if (numchars < MAX_LOG)
- {
- numchars++;
- *st++ = '\\'; /*escape*/
- }
- if (numchars < MAX_LOG)
- {
- numchars++;
- *st++ = *bp++; /* append */
- }
- }
- *st++ = '\n'; /* add end of line now. */
- }
- if (*(st - 1) == '\n')
- *(st - 1) = '"';
- else
- *st++ = '"';
- *st = '\0';
- (void) fclose(fp);
- if (numchars >= MAX_LOG)
- (void) printf("Log entry truncated.\n");
- }
- (void) unlink(titlest); /* cleanup. */
- }
- }
-
- titlest[0] = '\0'; /* cleanup string reference. */
- if (cii)
- getrcsdir(final, filename);
- else
- getworkdir(final, filename);
-
- if (st = strrchr(final, '/')) /* if this has a sub dir. */
- {
- *st = '\0'; /* terminate it at the directoy level. */
- if (access(final, 0)) /* it's not here... */
- if (!makedir(final)) /* so try and make it. */
- {
- (void) printf("Could not create directory: %s:\n", final);
- return(FALSE);
- }
- *st = '/'; /* restore the rest of the file name. */
- }
-
- if (cii)
- {
- if (!do_copy) /* not in binary mode. */
- { /*
- * make the new file name and check if it's here
- */
- #ifdef V_SCCS
- (void) strcpy(finalfile, final);
- #endif
- (void) addrcsext(final);
- if (!noexec && access(final, 0))
- {
- /*
- * if not, need to get a title message for it
- */
- if (!title[0]) /* no title file yet. */
- (void) getfinput(title, TYPE_TITLE); /* get one */
- if (title[0]) /* if we've one, build command */
- (void) sprintf(titlest, " -t%s ", title);
- #ifdef V_SCCS
- do_admin = TRUE; /* 1st check-in */
- #endif
- }
- #ifdef V_SCCS
- else
- do_admin = FALSE;
- #endif
- }
- else if (noexec)
- (void) strcpy(titlest, " -tfile_name ");
- }
- else /* check out mode. */
- { /*
- * find a comma to make the new name.
- * if found one, strip it to make a new name.
- */
- (void) rmrcsext(final);
- }
-
- /*
- * Build command string
- */
- if (do_copy) /* we want to just copy the file now. */
- {
- if (!interactive && !noexec && !access(final, 0))
- {
- (void) printf("%s already exists. Overwrite? (yes) ", final);
- (void) strrd(cmdbuf, 20, stdin);
- (void) strlwr(cmdbuf);
- if (strnicmp(cmdbuf, "yes", strlen(cmdbuf)))
- return(TRUE);
- }
- (void) sprintf(cmdbuf, "cp -p %s %s", filename, final); /* copy command */
- }
- else if (cii)
- {
- #ifdef V_RCS
- (void) sprintf(cmdbuf, "%s%s%s%s%s %s %s",
- ci_cmd, cioopt, titlest, logstr,
- do_unlink ? "" : " -l", filename, final);
- #else
- st = cmdbuf;
- (void) sprintf(st, "cp %s %s; ", filename, finalfile);
- st += strlen(st); /* skip to end of string. */
- if (cp = strrchr(final, '/'))
- {
- *cp = '\0';
- (void) sprintf(st, "cd %s; ", final);
- st += strlen(st); /* skip to end of string. */
- *cp = '/';
- }
- if (do_admin)
- {
- (void) sprintf(st, "%s -i%s%s%s%s %s",
- ici_cmd, justname(finalfile),
- cioopt, titlest, logstr, justname(final));
- st += strlen(st); /* skip to end of string. */
- }
- else
- {
- (void) sprintf(st, "%s%s%s %s",
- ci_cmd, cioopt, logstr, justname(final));
- st += strlen(st); /* skip to end of string. */
- }
- if (do_unlink)
- {
- (void) sprintf(st, "; rm %s", filename);
- st += strlen(st); /* skip to end of string. */
- }
- #endif
- }
- else /* coo */
- {
- #ifdef V_RCS
- (void) sprintf(cmdbuf, "%s%s %s %s",
- co_cmd, cioopt, filename, final);
- #else
- st = cmdbuf;
- (void) sprintf(st, "rm -f %s; ", final);
- st += strlen(st); /* skip to end of string. */
- if (cp = strrchr(filename, '/'))
- {
- *cp = '\0';
- (void) sprintf(st, "cd %s; ", filename);
- st += strlen(st); /* skip to end of string. */
- *cp = '/';
- }
- addrcsext(filename);
- (void) sprintf(st, "%s%s %s", co_cmd, cioopt,
- justname(filename));
- st += strlen(st); /* skip to end of string. */
- if (cp = strrchr(final, '/'))
- {
- cp++;
- (void) sprintf(st, "; mv %s %s", cp, final);
- st += strlen(st); /* skip to end of string. */
- }
- #endif
- }
-
- #ifdef INTERACTIVE
- if (interactive)
- {
- char ans[20];
- int done = FALSE;
-
- do
- {
- (void) printf("%s\nExecute? (yes) ", cmdbuf);
- (void) strrd(ans, 20, stdin);
- st = ans;
- while (isspace(*st))
- st++;
- if (!*st)
- (void) strcpy(st, "yes");
- (void) strlwr(st);
- if (!strnicmp(st, "yes", strlen(st))) {
- done = TRUE;
- (void) system(cmdbuf); /* do it. */
- }
- else if (*st == '?')
- {
- (void) printf("\n");
- (void) printf("yes Do it\n");
- (void) printf("no Don't do it\n");
- (void) printf("view View current file\n");
- (void) printf("? Print this message\n");
- (void) printf("\n");
- }
- else if (!strnicmp(st, "view", strlen(st)))
- {
- (void) printf("Not implemented yet!\n\n");
- }
- else /* take it as "no" */
- done = TRUE;
- } while (!done);
- }
- else
- {
- #endif /* INTERACTIVE */
- if (verbose)
- (void) printf("%s command: %s:\n", prognam, cmdbuf);
- if (!noexec)
- {
- if (do_copy && !verbose)
- (void) printf("%s\n", cmdbuf);
- (void) system(cmdbuf); /* do it. */
- }
- else if (!verbose) /* if don't want to exec, don't */
- (void) printf("%s\n", cmdbuf);
- #ifdef INTERACTIVE
- }
- #endif /* INTERACTIVE */
-
- if (updsrcdir) /* update source directory */
- {
- getsrcdir(final, filename);
-
- if (st = strrchr(final, '/')) /* if this has a sub dir. */
- {
- *st = '\0'; /* terminate it at the directoy level. */
- if (access(final, 0)) /* it's not here... */
- if (!makedir(final)) /* so try and make it. */
- {
- (void) printf("Could not create directory: %s:\n", final);
- return(FALSE);
- }
- *st = '/'; /* restore the rest of the file name. */
- }
-
- (void) sprintf(cmdbuf, "cp -p %s %s", filename, final);
- if (noexec) /* don't actual do it */
- (void) printf("%s\n", cmdbuf);
- else
- {
- if (verbose) /* speak, yo wise one! */
- (void) printf("%s command: %s:\n", prognam, cmdbuf);
- if (!stricmp(filename, final))
- (void) printf("Source and destination identical. Not updated.\n");
- else
- {
- (void) chmod(final, 0640);
- (void) system(cmdbuf); /* do it! */
- }
- }
- }
- return(TRUE);
- }
-
- /*--------------------------------------------------- addrcsext() -----------
- / add RCS file extension ",v" if there isn't one already
- /---------------------------------------------------------------------------*/
- int
- addrcsext(fname)
- char *fname;
- {
- register char *cp;
-
- #ifdef V_RCS
- for (cp = fname; *cp; cp++)
- ;
- if (*--cp == 'v' && *(cp - 1) == ',')
- return(0); /* already there */
-
- *++cp = ','; /* add ",v" */
- *++cp = 'v';
- *++cp = '\0';
- #else
- char t_name[20];
-
- cp = justname(fname);
- if (*cp == 's' && *(cp + 1) == '.')
- return(0);
- (void) strcpy(t_name, cp);
- *cp++ = 's'; /* add "s." in front of file name */
- *cp++ = '.';
- (void) strcpy(cp, t_name);
- #endif
- return(1);
- }
-
- /*--------------------------------------------------- rmrcsext() ------------
- / remove RCS extension if there is one; returns 1 if remove, else 0
- /---------------------------------------------------------------------------*/
- int
- rmrcsext(fname)
- char *fname;
- {
- register char *cp;
-
- #ifdef V_RCS
- for (cp = fname; *cp; cp++)
- ;
- if (*--cp == 'v' && *--cp == ',')
- {
- *cp = '\0';
- return(1);
- }
- #else
- cp = justname(fname);
- if (*cp == 's' && *(cp + 1) == '.')
- {
- (void) strcpy(cp, cp + 2);
- return(1);
- }
- #endif
- return(0);
- }
-
- /*--------------------------------------------------- inshdr() --------------
- / insert RCS header if none exists already
- /---------------------------------------------------------------------------*/
- void
- inshdr(t_name)
- char *t_name;
- {
- # define FTYPE_C 0 /* C program text */
- # define FTYPE_S 1 /* assembly program text */
- # define FTYPE_SH 2 /* shell script */
- # define FTYPE_ROFF 3 /* nroff, tbl, eqn, etc */
- # define FTYPE_F 4 /* Fortran program text */
- # define FTYPE_DEFAULT 5 /* don't know */
- # define FTYPE_MK 6 /* makefile script */
- # define FTYPE_H 7 /* C header file text */
-
- static struct _ftype {
- char *keyword; /* phrase may exist in file(1) output */
- char *header; /* header template file name. */
- } ftype[] = {
- #ifdef V_RCS
- { "c program", "rcshead.c" }, /* FTYPE_C */
- { "assembler", "rcshead.s" }, /* FTYPE_S */
- { "command", "rcshead.sh" }, /* FTYPE_SH */
- { "roff, tbl", "rcshead.rof" }, /* FTYPE_ROFF */
- { "fortran", "rcshead.f" }, /* FTYPE_F */
- { 0, "rcshead" }, /* FTYPE_DEFAULT */
- { 0, "rcshead.mk" }, /* FTYPE_MK */
- { 0, "rcshead.h" } }; /* FTYPE_H */
- #else
- { "c program", "sccshead.c" }, /* FTYPE_C */
- { "assembler", "sccshead.s" }, /* FTYPE_S */
- { "command", "sccshead.sh" }, /* FTYPE_SH */
- { "roff, tbl", "sccshead.rof"}, /* FTYPE_ROFF */
- { "fortran", "sccshead.f" }, /* FTYPE_F */
- { 0, "sccshead" }, /* FTYPE_DEFAULT */
- { 0, "sccshead.mk" }, /* FTYPE_MK */
- { 0, "sccshead.h" } }; /* FTYPE_H */
- #endif /* V_RCS */
- static struct _fext {
- char *name;
- int type;
- } fext[] = {
- { ".c", FTYPE_C },
- { ".h", FTYPE_H },
- { ".s", FTYPE_S },
- { ".f", FTYPE_F },
- { ".man", FTYPE_ROFF },
- { ".mk", FTYPE_MK },
- { ".1", FTYPE_ROFF },
- { ".2", FTYPE_ROFF },
- { ".3", FTYPE_ROFF },
- { ".4", FTYPE_ROFF },
- { ".5", FTYPE_ROFF },
- { ".6", FTYPE_ROFF },
- { ".7", FTYPE_ROFF },
- { ".8", FTYPE_ROFF },
- { ".9", FTYPE_ROFF },
- { 0, 0 } };
- FILE *ifp, *ofp;
- char buf[4096], headfile[128], tempfile[20], fname[40];
- register int i, c, ft = FTYPE_DEFAULT, err=0;
- register char *ext;
-
- strcpy(fname, justname(t_name)); /* copy over only name. */
-
- if (!(ifp = fopen(t_name, "r"))) /* quickly check for RCS header */
- return;
- /* we are looking for "$Header" */
- /* within first 50 lines of the file */
- for (i = 0; strrd(buf, 128, ifp) > 0 && i < 50; i++)
- #ifdef V_RCS
- if (strstr(buf, "$Header"))
- #else
- if (strstr(buf, "#ident"))
- #endif
- {
- (void) fclose(ifp);
- if (verbose)
- #ifdef V_RCS
- (void) printf("%s already has a RCS header.\n",
- #else
- (void) printf("%s already has a SCCS header.\n",
- #endif /* V_RCS */
- t_name);
- return;
- }
-
- (void) fclose(ifp);
- /* examine file(1) output */
- for (i = 0; ftype[i].keyword; i++)
- if (strstr(ftypestr, ftype[i].keyword))
- {
- ft = i;
- break; /* found one */
- }
-
- if (!ftype[i].keyword) /* file(1) didn't help */
- { /* examine file extension */
- if (ext = strrchr(fname, '.'))
- {
- for (i = 0; fext[i].name; i++)
- if (!stricmp(ext, fext[i].name))
- ft = fext[i].type;
- }
- else
- { /* check if makefile script */
- (void) strcpy(buf, fname);
- (void) strlwr(buf);
- if (!strcmp(buf, "makefile") || !strcmp(buf, "Makefile"))
- ft = FTYPE_MK; /* If either of two fixed names.. */
- }
- }
- else if (ft == FTYPE_C) /* see if source or header */
- {
- if ((ext = strrchr(fname, '.')) && !stricmp(ext, ".h"))
- ft = FTYPE_H;
- }
- if (verbose) /* is this necessary */
- (void) printf("%s is type [%d]\n", fname, ft);
- if (noexec) /* no execution mode */
- return;
-
- (void) sprintf(headfile, "%s%s", headdir, ftype[ft].header);
- if (!(ifp = fopen(headfile, "r")))
- {
- (void) printf("Unable to open header template file [%s]\n",
- headfile);
- return;
- }
- /* build a tmp file in the same directory as old file. */
- strcpy(tempfile, t_name);
- ext = justname(tempfile); /* find end of path. */
- *ext = '\0'; /* and terminate path there. */
- (void) strcat(tempfile, "ctXXXXXX"); /* add tmp name */
- (void) mktemp(tempfile); /* generate temp file name */
- if (!(ofp = fopen(tempfile, "w"))) /* open temp file */
- {
- (void) printf("Unable to open temporary file [%s]\n", tempfile);
- (void) fclose(ifp);
- return;
- }
- while ((c = fgetc(ifp)) != EOF) /* copy header first */
- (void) fputc(c, ofp);
- (void) fclose(ifp);
- if (!(ifp = fopen(t_name, "r"))) /* open check-in file */
- {
- (void) printf("Unable to open [%s] for read\n", t_name);
- (void) fclose(ofp);
- (void) unlink(tempfile);
- return;
- }
- while ((c = fgetc(ifp)) != EOF) /* append to temp file */
- if(fputc(c, ofp) == EOF)
- err=1; /* couldn't write error. */
- (void) fclose(ifp); /* done */
- (void) fclose(ofp);
-
- /* ok. It's hard to make sure that everthing has gone well; if we unlink
- the src file and can't link the temp file, we could lose everthing.
- So, if copy fails, leave temp file alone, as it may be the only copy
- we have left! If the unlinking the original fails, we can remove the
- copy, as we don't need it.
- */
- if(!err && !unlink(t_name)) /* 'mv tempfile fname' */
- {
- #ifndef OS2
- if(!link(tempfile, t_name)) /* 'cp tempfile t_name' */
- (void) unlink(tempfile); /* 'rm tempfile' */
- else
- (void) printf("Link of %s and %s failed after removing %s.\n%s not removed.\n",
- tempfile, t_name, t_name, tempfile);
- #else
- if(!rename(tempfile, t_name)) /* 'cp tempfile t_name' */
- (void) printf("Rename of %s to %s failed after removing %s.\n%s not removed.\n",
- tempfile, t_name, t_name, tempfile);
- #endif
- }
- else
- {
- (void) unlink(tempfile); /* 'rm tempfile' */
- (void) printf("Could not insert header into %s. Copy failed.\n", t_name);
- }
- }
-
- /*--------------------------------------------------- makedir() -------------
- / make a directory path, with recursion.
- / returns TRUE if successful, FALSE otherwise.
- /
- / This really needs to be re-written. It works, but that's all I can really
- / say for it... Hey, *I* don't have mkdir() calls!
- /---------------------------------------------------------------------------*/
- int
- makedir(newpath)
- char *newpath; /* path name to make. */
- {
- register char *st, *cp;
-
- if(!*newpath) return(FALSE); /* skip last directory attempt. */
- if (noexec)
- {
- (void) printf("mkdir: %s\n", newpath);
- return(TRUE);
- }
- else if(verbose)
- (void) printf("mkdir: %s\n", newpath);
-
- cp = memalloc(strlen(newpath) + 24);
-
- if (mkdir(newpath)) /* it failed.. */
- {
- (void) strcpy(cp, newpath); /* get current one. */
- st = strrchr(cp, '/'); /* remove one more layer.. */
- *st = '\0'; /* terminate here. */
- if (makedir(cp) == FALSE) /* try and build next level back. */
- {
- free(cp);
- return(FALSE);
- }
- /* ok, so.. it passed on back. Try this again. */
- if(mkdir(newpath))
- {
- free(cp);
- return(FALSE);
- }
- }
-
- free(cp);
- return(TRUE);
- }
-
- /*--------------------------------------------------- strstr() --------------
- / find a substring within a string
- /---------------------------------------------------------------------------*/
- #ifndef OS2
- char *
- strstr(s1, s2)
- register char *s1, *s2;
- {
- register int l;
-
- if (l = strlen(s2))
- for ( ; s1 = strchr(s1, s2[0]); s1++)
- if (memcmp(s1, s2, l) == 0)
- break;
- return(s1);
- }
-
- /*--------------------------------------------------- strlwr() ---------------
- / strlwr.c - convert passed string to its equivalent lowercases
- /----------------------------------------------------------------------------*/
- char *
- strlwr(s)
- register char *s;
- {
- char *op;
-
- for (op = s; *s; s++)
- if (isupper(*s))
- *s = _tolower(*s);
- return(op);
- }
- #endif
-
- /*--------------------------------------------------- asciifile() -----------
- / check if passed file is an ascii file using file(1) command
- /---------------------------------------------------------------------------*/
- int
- asciifile(fn)
- char *fn;
- {
- char cmdstr[256];
- register FILE *fp;
-
- #ifdef OS2
- int file, cnt, i;
-
- if ((file = open(fn, O_RDONLY|O_BINARY)) == -1)
- return(FALSE);
- cnt = read(file, cmdstr, sizeof(cmdstr)); /* get a block. */
- close(file); /* and done. */
-
- for ( i = 0; i < cnt; i++ )
- if ( cmdstr[i] == 0 || cmdstr[i] == 127 )
- return(FALSE);
-
- return(TRUE);
- #else /* OS2 */
- (void) sprintf(cmdstr, "file %s", fn);
- if (!(fp = popen(cmdstr, "r")))
- return(FALSE);
- (void) strrd(ftypestr, 80, fp); /* get a line. */
- (void) pclose(fp); /* and done. */
- #ifdef DEBUG
- (void) printf("%s\n", cmdstr);
- #endif
- if (strstr(ftypestr, "text"))
- return(TRUE);
- return(FALSE);
- #endif /* OS2 */
- }
-
- /*--------------------------------------------------- rcsfile() -------------
- / check if passed file is an RCS file using file(1) command
- /---------------------------------------------------------------------------*/
- int
- rcsfile(fn)
- char *fn;
- {
- char cmdstr[256];
- register FILE *fp;
-
- #ifdef OS2
- if (!(fp = fopen(fn, "r")))
- return(FALSE);
- (void) strrd(ftypestr, 80, fp); /* get a line. */
- (void) fclose(fp); /* and done. */
- #ifdef DEBUG
- (void) printf("%s\n", cmdstr);
- #endif
- if (strcmp(ftypestr, "head "))
- return(TRUE);
- #else /* OS2 */
- (void) sprintf(cmdstr, "file %s", fn);
- if (!(fp = popen(cmdstr, "r")))
- return(FALSE);
- (void) strrd(ftypestr, 80, fp); /* get a line. */
- (void) pclose(fp); /* and done. */
- #ifdef DEBUG
- (void) printf("%s\n", cmdstr);
- #endif
- #ifdef V_RCS
- if (strstr(ftypestr, "text"))
- #else
- if (strstr(ftypestr, "sccs"))
- #endif
- return(TRUE);
- #endif /* OS2 */
- return(FALSE);
- }
-
- /*--------------------------------------------------- strrd() ----------------
- / read from given file pointer until a line separator or end-of-file or
- / (len) characters excluding the terminator.
- /---------------------------------------------------------------------------*/
- int
- strrd(buf, len, fle)
- char *buf;
- int len;
- FILE *fle;
- {
- int c0, i0 = 0;
-
- while (((c0 = getc(fle)) != EOF) && c0 && c0 != '\n')
- if(i0 < len) /* if room in buffer..*/
- buf[i0++] = (char) c0; /* save it. */
- buf[i0] = 0;
- if (i0 == 0 && c0 == EOF)
- return(-1);
- return(i0);
- }
-
- /*--------------------------------------------------- getdir() --------------
- / get and readin variables for later.
- /---------------------------------------------------------------------------*/
- void
- getdir()
- {
- register char *cp;
-
- if(cp = getenv("HOME")) /* get user's home dir. */
- {
- (void) strcpy(homedir = memalloc(strlen(cp) + 2), cp);
- if (!(s_homedir = fix_envstr(homedir)))
- {
- free(homedir);
- homedir = (char *) 0;
- }
- }
- else /* this should NEVER happen */
- {
- (void) fprintf(stderr, "No home directory???\n");
- exit(-1);
- }
-
- #ifdef V_RCS
- if(cp = getenv("RCSDIR")) /* RCS directory */
- #else
- if(cp = getenv("SCCSDIR")) /* SCCS directory */
- #endif
- (void) strcpy(rcsdir = memalloc(strlen(cp) + 2), cp);
- else /* RCS is $HOME/RCS */
- (void) sprintf(rcsdir = memalloc(s_homedir + 6),
- #ifdef V_RCS
- "%s/RCS", homedir);
- #else
- "%s/SCCS", homedir);
- #endif
- if (!(s_rcsdir = fix_envstr(rcsdir)))
- {
- free(rcsdir);
- rcsdir = (char *) 0;
- }
-
- #ifdef V_RCS
- if(cp = getenv("RCSWORK")) /* user's working directory */
- #else
- if(cp = getenv("SCCSWORK")) /* user's working directory */
- #endif
- {
- (void) strcpy(rcswrk = memalloc(strlen(cp) + 2), cp);
- if (!(s_rcswrk = fix_envstr(rcswrk)))
- {
- free(rcswrk);
- rcswrk = (char *) 0;
- }
- }
-
- #ifdef V_RCS
- if (cp = getenv("RCSSRC")) /* master source directory */
- #else
- if (cp = getenv("SCCSSRC")) /* master source directory */
- #endif
- {
- (void) strcpy(srcdir = memalloc(strlen(cp) + 2), cp);
- if (!(s_srcdir = fix_envstr(srcdir)))
- {
- free(srcdir);
- srcdir = (char *) 0;
- }
- }
-
- #ifdef V_RCS
- if (cp = getenv("RCSHEAD")) /* RCS header file directory */
- #else
- if (cp = getenv("SCCSHEAD")) /* SCCS header file directory */
- #endif
- {
- (void) strcpy(headdir = memalloc(strlen(cp) + 2), cp);
- if (!(s_headdir = fix_envstr(headdir)))
- {
- free(headdir);
- headdir = homedir;
- }
- }
- else
- headdir = homedir;
-
- #ifdef V_RCS
- if (cp = getenv("RCSOWN")) /* the owner of RCS files */
- #else
- if (cp = getenv("SCCSOWN")) /* the owner of SCCS files */
- #endif
- {
- s_rcsown = strlen(cp);
- (void) strcpy(rcsown = memalloc(s_rcsown + 1), cp);
- }
-
- if(cp = getenv("PATH")) /* current path, ie. $PATH */
- {
- s_path = strlen(cp);
- (void) strcpy(path = memalloc(s_path + 1), cp);
- }
-
- if((currentdir = getcwd((char *)NULL, 200)) == NULL)
- {
- (void) fprintf(stderr, "Cannot get working dir.\n");
- exit(-1);
- }
- #ifdef OS2
- /* strcpy(currentdir, currentdir + 2); */
- UnixFileName(currentdir);
- #endif
- strcat(currentdir, "/");
- s_currentdir = strlen(currentdir);
- }
-
- /*--------------------------------------------------- fix_envstr() ----------
- / fix environment variable to avoid problems later.
- / 1. strip leading/trailing white spaces
- / 2. strip duplicate slashes
- / 3. add trailing slash
- / 4. return string length
- /---------------------------------------------------------------------------*/
- int
- fix_envstr(cs)
- char *cs;
- {
- register char *cp, *dp;
- register int was_slash = FALSE;
-
- #ifdef OS2
- UnixFileName(cs);
- #endif
-
- cp = dp = cs;
- while (isspace(*cp)) /* remove leading white spaces */
- cp++;
-
- if (!*cp) /* string was a full of blanks */
- return(0);
-
- while (*cp)
- {
- if (*cp == '/')
- {
- if (was_slash)
- {
- cp++; /* strip duplicate slashes */
- continue;
- }
- else
- was_slash = TRUE;
- }
- else
- was_slash = FALSE;
- *dp++ = *cp++;
- }
-
- do /* remove trailing while spaces */
- {
- dp--;
- } while (isspace(*dp));
-
- if (*dp != '/') /* add trailing slash */
- *++dp = '/';
- *++dp = '\0'; /* null terminate */
- return(strlen(cs));
- }
-
- /*--------------------------------------------------- getrcsdir() -----------
- / get $RCSDIR + tail directory
- /---------------------------------------------------------------------------*/
- void
- getrcsdir(tdir, sdir)
- char *tdir, *sdir;
- {
- register char *cp = sdir;
-
- if(rcswrk && !strnicmp(rcswrk, cp, s_rcswrk))
- cp += s_rcswrk;
- if(homedir && !strnicmp(homedir, cp, s_homedir))
- cp += s_homedir;
- #ifdef OS2
- if(isalpha(cp[0]) && cp[1] == ':')
- cp += 2;
- #endif
- if(cp[0] == '/')
- cp++;
- /*
- * build the final directory name
- */
- (void) sprintf(tdir, "%s%s", rcsdir, cp);
- }
-
- /*--------------------------------------------------- getworkdir() ----------
- / get $RCSWORK or $HOME + tail
- /---------------------------------------------------------------------------*/
- void
- getworkdir(tdir, sdir)
- char *tdir, *sdir;
- {
- register char *cp = sdir;
-
- if (rcsdir && !strnicmp(rcsdir, cp, s_rcsdir))
- cp += s_rcsdir;
- #ifdef OS2
- if(isalpha(cp[0]) && cp[1] == ':')
- cp += 2;
- #endif
- if(cp[0] == '/')
- cp++;
- (void) sprintf(tdir, "%s%s", rcswrk ? rcswrk : homedir, cp);
- }
-
- /*--------------------------------------------------- getsrcdir() -----------
- / get $RCSSRC + tail
- /---------------------------------------------------------------------------*/
- void
- getsrcdir(tdir, sdir)
- char *tdir, *sdir;
- {
- register char *cp = sdir;
-
- if (rcswrk && !strnicmp(rcswrk, cp, s_rcswrk))
- cp += s_rcswrk;
- if(homedir && !strnicmp(homedir, cp, s_homedir))
- cp += s_homedir;
- #ifdef OS2
- if(isalpha(cp[0]) && cp[1] == ':')
- cp += 2;
- #endif
- if(cp[0] == '/')
- cp++;
- (void) sprintf(tdir, "%s%s", srcdir ? srcdir : homedir, cp);
- }
-
- /*--------------------------------------------------- getfinput() ------------
- / get a title file.
- /---------------------------------------------------------------------------*/
- int
- getfinput(name, type)
- char *name; /* buffer to put file name into. */
- int type; /* what data we want. */
- {
- int stat_loc;
-
- (void) strcpy(name, tmpnam(editfile));
- #ifndef OS2
- if (fork())
- { /* parent just waits for the child to finish */
- (void) wait(&stat_loc);
- }
- else
- { /* child does his/her stuff */
- (void) signal(SIGINT, SIG_DFL);
- (void) signal(SIGQUIT, SIG_DFL);
- (void) signal(SIGBREAK, SIG_DFL);
- (void) signal(SIGTERM, SIG_DFL);
- exit(child_getfinput(name, type) == TRUE ? 0 : -1);
- }
- return((stat_loc >> 8) & 0xff);
- #else
- return child_getfinput(name, type) == TRUE ? 0 : -1;
- #endif
- }
-
- /*--------------------------------------------------- child_getfinput() -----
- / actual get title file.
- /---------------------------------------------------------------------------*/
- int
- child_getfinput(name, type)
- char *name; /* buffer to put file name into. */
- int type; /* what data we want. */
- {
- static char *input_type[2] = { "log", "title" };
- FILE *fp, *xfp;
- register char *st;
- int c, done = FALSE;
- char buf[82]; /* just larger than input buffer. */
-
- #ifndef OS2
- (void) setuid(real_user_id); /* user's real user id */
- #endif
- if((fp = fopen(name, "w")) == NULL) /* failed open. */
- {
- (void) unlink(name); /* remove it. */
- name[0] = '\0';
- (void) printf("Unable to create tmp file.\n");
- return(FALSE);
- }
- (void) printf("Enter %s message, <ret>.<ret> or Control-Z to end:\n",
- input_type[type]);
- while (!done)
- {
- (void) printf(">>");
- if(strrd(buf, 80, stdin) == -1) /* read in one line. */
- {
- /* ok, read somewhere that this is possible. By doing this,
- we should be able to continue after a control-D.
- */
- clearerr(stdin);
- break;
- }
- if(!strcmp(".", buf)) /* end of message */
- break;
- if (buf[0] == '~') /* special command */
- {
- switch (buf[1]) /* command character */
- {
- case '?': /* print usage, help message */
- (void) printf("\n");
- (void) printf("~. End of input\n");
- (void) printf("~! Invoke shell\n");
- (void) printf("~e Edit message using an editor\n");
- (void) printf("~p Print message buffer\n");
- (void) printf("~r Read in a file\n");
- (void) printf("~w Write message to a file\n");
- (void) printf("~? Print this message\n");
- (void) printf("\n");
- break;
- case '!': /* shell */
- st = getenv("SHELL");
- (void) system(st ? st : "/bin/sh");
- (void) printf("[Press RETURN to continue]");
- (void) strrd(buf, 20, stdin);
- break;
- case 'p': /* print message buffer content */
- (void) fclose(fp);
- fp = fopen(name, "r");
- while ((c = fgetc(fp)) != EOF)
- (void) fputc(c, stdout);
- (void) fclose(fp);
- fp = fopen(name, "a");
- (void) printf("Continue entering %s message.\n",
- input_type[type]);
- break;
- case 'e': /* editor */
- case 'v': /* visual */
- (void) fclose(fp);
- st = getenv(buf[1] == 'e' ?"EDITOR":"VISUAL");
- (void) sprintf(buf, "%s %s",
- st ? st : "/usr/bin/vi", name);
- (void) system(buf);
- fp = fopen(name, "a");
- (void) printf("Continue entering %s message.\n",
- input_type[type]);
- break;
- case 'r': /* read in a file */
- st = &buf[2];
- while (isspace(*st))
- st++;
- if (!*st)
- {
- (void) printf("File name missing!\n");
- break;
- }
- if (xfp = fopen(st, "r"))
- {
- while ((c = fgetc(xfp)) != EOF)
- (void) fputc(c, fp);
- (void) fclose(xfp);
- }
- else
- (void) printf("Unable to open %s.\n",
- st);
- break;
- case 'w': /* write message to a file */
- st = &buf[2];
- while (isspace(*st))
- st++;
- if (!*st)
- (void) printf("File name missing!\n");
- else
- {
- if (xfp = fopen(st, "a"))
- {
- (void) fclose(fp);
- fp = fopen(name, "r");
- while ((c = fgetc(fp)) != EOF)
- (void) fputc(c, xfp);
- (void) fclose(xfp);
- (void) fclose(fp);
- fp = fopen(name, "a");
- }
- else
- (void) printf("Unable to open %s.\n",
- st);
- }
- break;
- case '.': /* end of message */
- done = TRUE;
- break;
- default: /* user doesn't know */
- (void) printf("Unrecognized command %c -- ignored\n",
- buf[1] & 0x7f);
- break;
- }
- continue;
- }
- (void) fprintf(fp, "%s\n", buf);
- }
- (void) fclose(fp);
- (void) printf("\n");
- return(TRUE);
- }
-
- /*--------------------------------------------------- justname() ------------
- / extract just filename from a full path
- /---------------------------------------------------------------------------*/
- char *
- justname(fpath)
- char *fpath;
- {
- register char *cp;
-
- #ifdef OS2
- UnixFileName(fpath);
- #endif
- if (cp = strrchr(fpath, '/'))
- return(++cp);
-
- return(fpath);
- }
-
- /*--------------------------------------------------- memalloc() ------------
- / allocate specified amount of memory. If not successful, exit.
- /---------------------------------------------------------------------------*/
- char *
- memalloc(size)
- register int size;
- {
- register char *cp;
-
- if (!(cp = malloc((unsigned)size)))
- {
- perror(prognam);
- exit(99);
- }
- return(cp);
- }
-
- /*--------------------------------------------------- get_final_id() --------
- / Get the RCSOWN user id to create files with. If none found, use user id.
- /---------------------------------------------------------------------------*/
- void
- get_final_id()
- {
- FILE *fp;
-
- if(!rcsown) /* if there isn't one of these. */
- #ifdef V_RCS
- rcsown = "rcsfiles"; /* default name. */
- #else
- rcsown = "sccsfiles"; /* default name. */
- #endif
-
- if ((fp = fopen (pwdfile, "r")) == NULL)
- {
- #ifdef DEBUG
- (void) fprintf(stderr, "setpwent: %s non-existant or unreadable.\n",
- pwdfile);
- #endif
- user_id = real_user_id; /* make sure it's owners id now. */
- return; /* couldn't do it. */
- }
- while (nextent(fp)) /* while entries in file.. */
- if (!strcmp(pwdname, rcsown)) /* If name matches. */
- break;
- (void) fclose(fp); /* close the file. */
- return; /* found it or not, return. */
- }
-
- /*--------------------------------------------------- nextent() -------------
- / get one entry from a password file. Return TRUE if there is one found,
- / FALSE otherwise.
- /---------------------------------------------------------------------------*/
- int
- nextent(fle)
- FILE *fle; /* file pointer. */
- {
- register char *cp, *pwp;
- char savbuf[200]; /* usually large enough for a password entry. */
-
- while (strrd(savbuf, (int) (sizeof (savbuf)), fle) != -1)
- {
- pwp = pwdname;
- cp = savbuf; /* get user name */
- while (*cp && *cp != ':')
- *pwp++ = *cp++;
- *pwp = '\0'; /* terminate name. */
- for (cp++; *cp && *cp != ':'; cp++)
- ; /* skip over password. */
- user_id = atoi(++cp); /* ok, save this users id number. */
- return (TRUE);
- }
- user_id = real_user_id; /* make sure it's owners id now. */
- return (FALSE);
- }
-
- /*----------------------------- End of cio.c -------------------------------*/
-
- #ifdef OS2
- UnixFileName(char *name)
- {
- /* strlwr(name); */
- for ( ; *name; name++ )
- if ( *name == '\\' )
- *name = '/';
- }
- #endif
-
-