home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs567s.zip / rcsfront / cio.c < prev    next >
C/C++ Source or Header  |  1994-12-29  |  52KB  |  1,774 lines

  1. /*----------------------------------------------------------------------------
  2. / cio.c - This is a C program to replace the over-grown shell script
  3. / that started as something small...
  4. /
  5. / Authors:    Jason P. Winters and Craig J. Kim
  6. /
  7. /  We hereby declare this software to be Public Domain.  That means we don't
  8. /  care what you do with it.  We _would_ prefer that you at least leave our
  9. /  names in it, as befits Authors, but we can't force you.  Of course, since
  10. /  it's public domain, all risks/gains using it are your problems.  You don't
  11. /  have any reason to call us up and complain about it deleting 30megs of
  12. /  your source code without telling you. ( Software should at least *tell* you
  13. /  when it does something like that, right? )  :)
  14. /
  15. / Start Date:    November 23, 1988
  16. / Revisions:    29-Nov-88 jpw - initial coding completed.
  17. /        29-Nov-88 cjk - rewrite of front-end logic
  18. /        30-Nov-88 jpw - Added signals, cleanup of temp files.
  19. /        30-Nov-88 cjk - added -N option
  20. /        01-Dec-88 cjk - added usage
  21. /        01-Dec-88 jpw - added SUID controls for secure files.
  22. /        02-Dec-88 jpw - added -A option
  23. /        05-Dec-88 cjk - added '~' commands for message entering
  24. /        05-Dec-88 cjk - fixed cp to check file status before copying
  25. /        06-Dec-88 cjk - use separate process for user file input
  26. /        06-Dec-88 jpw - source now passes System V.2 lint
  27. /        07-Dec-88 cjk - added environment variable check routine
  28. /        20-Dec-88 cjk - chmod files in source dir to 0640
  29. /        21-Dec-88 cjk - put RCS header if not exists
  30. /        08-Mar-89 cjk - SCCS version
  31. /        02-Oct-89 jpw - Fixed parsing for header type to insert
  32. /                        Fixed small bug in directory creation routine
  33. /        10-May-90 jpw - Changed st += sprintf() code to allow for
  34. /                        broken sprint() calls.  Failed on Sun
  35. /                        machines.
  36. /
  37. / Known bugs:
  38. /       On some systems, the Control-D as end of input in the log entry
  39. /       routines will cause stdin to be closed, which means the next call
  40. /       to get an entry (such as a Title file) will fail.  A call to clearerr()
  41. /       has been added to fix this, but it has not been tested.
  42. /
  43. / To be done:
  44. /    1. When -U is used, the destination directory should be created if
  45. /       it does not exist already.  Also, the file mode should be changed to
  46. /       0640 so that overwriting is not possible by anyone other than
  47. /       $RCSOWN for security.
  48. /    2. Full "interactive" mode support
  49. /   3. Actually use the SCCS version. (Ugh!)
  50. /---------------------------------------------------------------------------*/
  51.  
  52. /*#define DEBUG        /* wanna know what's goin' on? */
  53. /*#define INTERACTIVE    /* enable -I option (incomplete) */
  54. /*#define void    int    /* if system can't handle void types. */
  55. #define V_RCS        /* RCS version */
  56. /*#define V_SCCS        /* SCCS version */
  57.  
  58. /*--------------------------------------------------- includes -------------*/
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62. #include <sys/types.h>
  63. #include <sys/stat.h>
  64. #include <errno.h>
  65. #include <signal.h>
  66. #include <fcntl.h>
  67.  
  68. #ifdef __EMX__
  69. #define getcwd _getcwd2
  70. #define mkdir(d) mkdir (d, 0755)
  71. #endif
  72.  
  73. #ifndef OS2
  74. #define stricmp   strcmp
  75. #define strnicmp  strncmp
  76. #endif
  77.  
  78. /*--------------------------------------------------- externals ------------*/
  79. extern FILE *fopen();               /* open a stream (should be in stdio.h) */
  80. extern FILE *popen();                 /* open a pipe (should be in stdio.h) */
  81. extern char *getenv();                      /* read an environment variable */
  82. extern char *tmpnam();                      /* create a temporary file name */
  83. extern char *mktemp();                  /* create temp file with a template */
  84. extern char *malloc();                        /* allocate a chunk of memory */
  85. extern char *getcwd();                             /* get current directory */
  86. extern int  unlink();                             /* unlink (delete) a file */
  87. extern void exit();                            /* define these for LINT!!!! */
  88. extern void perror();                          /* define these for LINT!!!! */
  89. extern void free();                            /* define these for LINT!!!! */
  90.  
  91. /*--------------------------------------------------- defines --------------*/
  92. #ifndef TRUE
  93. # define TRUE    1
  94. # define FALSE    0
  95. #endif
  96.  
  97. #define TYPE_LOG    0        /* log message */
  98. #define TYPE_TITLE    1        /* title message */
  99. #define MAX_LOG        1020        /* max # of characters for a log */
  100.  
  101. /*--------------------------------------------------- forwards -------------*/
  102. void usage(/*_ void _*/);                    /* print program usage message */
  103. int  getfinput(/*_ char *name, int type _*/);             /* get title file */
  104. int  child_getfinput(/*_ char *name, int type _*/);      /* actual get file */
  105. void doincmds(/*_ char *argv[], int argc, int in _*/); /* perform user wish */
  106. void do_ciodir(/*_ char *filenm _*/);    /* do user wish in recursive if -R */
  107. int  cio(/*_ char *filenme _*/);                          /* the work horse */
  108. int  addrcsext(/*_ char *fname _*/);         /* add RCS file name extension */
  109. int  rmrcsext(/*_ char *fname _*/);       /* remove RCS file name extension */
  110. void inshdr(/*_ char *fname _*/);                      /* insert RCS header */
  111. int  makedir(/*_ char *path _*/);    /* make a directory and all its parent */
  112. char *strstr(/*_ char *s1, char *s2 _*/);  /* find a string within a string */
  113. char *strlwr(/*_ char *s _*/);               /* convert upper case to lower */
  114. int  asciifile(/*_ char *filename _*/);                  /* check file type */
  115. int  rcsfile(/*_ char *filename _*/);             /* check file is RCS file */
  116. int  strrd(/*_ char *buf, int max_size,  FILE *fle _*/);/* read from a file */
  117. void getdir(/*_ void _*/);        /* obtain necessary directory information */
  118. int  fix_envstr(/*_ char *cs _*/);  /* remove leading/trailing blanks, etc. */
  119. void getrcsdir(/*_ char *dir _*/);          /* build rcs dir out of working */
  120. void getworkdir(/*_ char *dir _*/);         /* build working dir out of rcs */
  121. void getsrcdir(/*_ char *dir _*/);       /* build source dir out of working */
  122. char *justname(/*_ char *fpath _*/);        /* return just filename portion */
  123. char *memalloc(/*_ int size _*/);  /* allocate memory and check for success */
  124. void sigcleanup(/*_ void _*/);                 /* cleanup in case interrupt */
  125. void get_final_id(/*_ void _*/);           /* get user id of RCS file owner */
  126. int  nextent(/*_ FILE *fp _*/);    /* read next entry from /etc/passwd file */
  127.  
  128. /*--------------------------------------------------- globals --------------*/
  129. #ifdef V_RCS
  130. char *ci_cmd = "ci";                /* command to use to check in a module. */
  131. char *co_cmd = "co";               /* command to use to check out a module. */
  132. #else
  133. char *ici_cmd = "admin";      /* command to check in a module for 1st time. */
  134. char *ci_cmd = "delta";                    /* command to check in a module. */
  135. char *co_cmd = "get";                     /* command to check out a module. */
  136. #endif
  137. char *currentdir;                                     /* current directory. */
  138. char *homedir;                                    /* user's home directory. */
  139. char *rcswrk;                                                  /* $RCSWORK. */
  140. char *rcsown;                                                   /* $RCSOWN. */
  141. char *rcsdir;                                                   /* $RCSDIR. */
  142. char *srcdir;                                                   /* $RCSSRC. */
  143. char *headdir;                                                 /* $RCSHEAD. */
  144. char *path;                                                       /* $PATH. */
  145. char *pwdfile = "/etc/passwd";                      /* default passwd file. */
  146. char cioopt[100];                      /* large buffer for command options. */
  147. char d_ent[90];                             /* small buffer for file reads. */
  148. char final[400];                    /* final dir to pass on as destination. */
  149. #ifdef V_SCCS
  150. char finalfile[400];                  /* final file without SCCS extension. */
  151. #endif
  152. char logstr[MAX_LOG + 4];                            /* log string to pass. */
  153. char title[100];                                     /* log string to pass. */
  154. char cmdbuf[2400];                                     /* do a single file. */
  155. char editfile[400];                  /* temp edit file, makes cleanup easy. */
  156. char pwdname[20];                                    /* Name found in file. */
  157. char ftypestr[82];                               /* command file(1) output. */
  158. char cii = FALSE;                       /* if set, we are in check in mode. */
  159. char recurse = FALSE;               /* if set, do recursive check in/out's. */
  160. char usertitle = FALSE;                       /* user specified title file. */
  161. char interactive = FALSE;                /* user friendly interactive mode. */
  162. char allfiles = FALSE;                    /* set it TRUE to copy all files. */
  163. char insertheader = FALSE;     /* insert RCS header at the top of the file. */
  164. #ifdef DEBUG
  165. char noexec = TRUE;                     /* set it FALSE for execution mode. */
  166. char verbose = TRUE;                                    /* be a chatterbox. */
  167. #else
  168. char noexec = FALSE;                  /* set it TRUE for no execution mode. */
  169. char verbose = FALSE;                                  /* not a chatterbox. */
  170. #endif
  171. char updsrcdir = FALSE;           /* update master source directory on cii. */
  172. #ifdef V_SCCS
  173. char do_admin = FALSE;                    /* set it TRUE if first check in. */
  174. #endif
  175. char *prognam;                                     /* name of this program. */
  176. struct stat filestat;                                  /* file status info. */
  177. int s_currentdir;                           /* length of current directory. */
  178. int s_homedir;                          /* length of user's home directory. */
  179. int s_rcswrk;                                        /* length of $RCSWORK. */
  180. int s_rcsdir;                                         /* length of $RCSDIR. */
  181. int s_srcdir;                                         /* length of $RCSSRC. */
  182. int s_path;                                             /* length of $PATH. */
  183. int s_rcsown;                                         /* length of $RCSOWN. */
  184. int s_headdir;                                       /* length of $RCSHEAD. */
  185. int user_id;                   /* Effective user id to use if ROOT process. */
  186. int real_user_id;                      /* Save buffer for original user_id. */
  187. int do_unlink;  /* add -l option if not set to avoid unlink of source file. */
  188.  
  189. /*--------------------------------------------------- main() ----------------
  190. / where we begin!
  191. /---------------------------------------------------------------------------*/
  192. main(argc, argv)
  193. int argc;
  194. char *argv[];
  195. {
  196.     register int in;
  197.     register char *cp;        /* used in string updates. */
  198.  
  199. #ifdef __EMX__
  200.     _response(&argc, &argv);
  201.     _wildcard(&argc, &argv);
  202.     _emxload_env("RCSLOAD");
  203. #endif
  204.  
  205.     prognam = justname(argv[0]);    /* program name */
  206. #ifdef OS2
  207.         if ( stricmp(prognam + 3, ".exe") == 0 )
  208.           prognam[3] = 0;
  209. #endif
  210.     getdir();            /* go get the enviroment pointers. */
  211.  
  212.     /*
  213.      * figure what the user wants us to be by reading program name
  214.      */
  215.     if (!stricmp("ciitest", prognam) || !stricmp("cootest", prognam))
  216.     {
  217.         getrcsdir(final, currentdir);    /* setup variables. */
  218.         /*
  219.          * print out our variables here.
  220.         */
  221. #ifdef V_RCS
  222.         (void) printf("Homedir:%s:  rcsdir:%s:  rcswrk:%s:  rcssrc:%s:\n",
  223. #else
  224.         (void) printf("HOME:%s:  SCCSDIR:%s:  SCCSWRK:%s:  SCCSSRC:%s:\n",
  225. #endif
  226.                 homedir ? homedir : "",
  227.                 rcsdir ? rcsdir : "",
  228.                 rcswrk ? rcswrk : "",
  229.                 srcdir ? srcdir : "");
  230.         (void) printf("Final dir:%s:\n", final);
  231.         return(0);
  232.     }
  233.     if (!stricmp("cii", prognam))    /* this is input.. */
  234.         cii = TRUE;        /* show we are inputs. */
  235.     else if (stricmp("coo", prognam))/* it's not this either.. */
  236.     {
  237.         (void) printf("Just what did you think this program was, anyway??\n");
  238.         return(-1);
  239.     }
  240.  
  241. #ifndef OS2        
  242.     if (!(user_id = geteuid())) /* we are a root process.. */
  243.     {
  244.         (void) umask(027); /* set general mask to private modes. */
  245.         real_user_id = getuid();
  246.         if (cii)    /* only set this if we are in checkin mode. */
  247.             get_final_id(); /* go get the final user ID for file creation. */
  248.         else
  249.             user_id = real_user_id;    /* otherwise, use owners real one. */
  250.         (void) setuid(user_id); /* and, fix up the user id now. */
  251. #ifdef DEBUG
  252.         (void) printf("Using Uid:%d:\n", user_id);
  253. #endif
  254.     }
  255.     else
  256.         real_user_id = user_id;    /* else they should match. */
  257. #else 
  258.     real_user_id = 1;    /* else they should match. */
  259. #endif
  260.  
  261.     /* prepare for disasters */
  262.     (void) signal(SIGINT, sigcleanup);
  263. #ifndef OS2
  264.     (void) signal(SIGQUIT, sigcleanup);
  265. #else
  266.     (void) signal(SIGBREAK, sigcleanup); /* OS/2 */
  267.     (void) signal(SIGTERM, sigcleanup);  /* signals */
  268. #endif
  269.  
  270.         if ( argc <= 1 )
  271.         {
  272.             usage();
  273.             return(0);
  274.         }
  275.  
  276.     cp = cioopt;
  277.     title[0] = '\0';  /* make sure no titles are required. */
  278.     for (in = 1; argv[in][0] == '-'; in++) /* while chars here.. */
  279.     {
  280.         switch ((int) argv[in][1])    /* what option? */
  281.         {
  282.         case '?':        /* print program usage */
  283.         case '-':
  284.             usage();
  285.             return(0);
  286.         case 'A':        /* copy all files */
  287.             allfiles = !allfiles;
  288.             break;
  289. #ifdef INTERACTIVE
  290.         case 'I':        /* interactive mode */
  291.             interactive = !interactive;
  292.             break;
  293. #endif
  294.         case 'H':        /* RCS/SCCS header */
  295.             insertheader = !insertheader;
  296.             break;
  297.         case 'N':        /* do not execute */
  298.             noexec = !noexec;
  299.             break;
  300.         case 'R':        /* Recursion flag. */
  301.             recurse = !recurse;
  302.             break;
  303.         case 'T':        /* get Title flag. */
  304.             if(cii)    /* get a title file and name. */
  305.                 (void) getfinput(title, TYPE_TITLE);
  306.             break;
  307.         case 'U':        /* update working directory */
  308.             updsrcdir = !updsrcdir;
  309.             break;
  310.         case 'V':        /* verbose */
  311.             verbose = !verbose;
  312.             break;
  313. #ifdef V_RCS
  314.         case 'm':        /* they gave us one */
  315. #else
  316.         case 'y':        /* they gave us one */
  317. #endif
  318.             (void) strcpy(logstr, " -");
  319.             (void) strcat(logstr, &argv[in][1]); /* copy across. */
  320.             break;
  321.         case 't':        /* user gave us one */
  322.             (void) strcpy(title, &argv[in][1]);
  323.             usertitle = TRUE;
  324.             break;
  325.         default:        /* must be a ci or co command */
  326.             (void) sprintf(cp, " %s", argv[in]); /* append */
  327.             cp += strlen(cp); /* skip to end of string. */
  328.             break;
  329.         }
  330.     }
  331. #ifdef INTERACTIVE
  332.     if (noexec && interactive)    /* resolve conflict of interest */
  333.         interactive = FALSE;
  334. #endif
  335.     doincmds(argv, argc, in);    /* do the check in command. */
  336.     if (title[0] && !usertitle)    /* if file is here. */
  337.         (void) unlink(title);    /* zap it! */
  338.     return(0);            /* we did it good! */
  339. }
  340.  
  341. /*--------------------------------------------------- usage() ---------------
  342. / print program usage information
  343. /---------------------------------------------------------------------------*/
  344. void
  345. usage()
  346. {
  347.     char *inout = cii ? "in" : "out";
  348.  
  349. #ifdef INTERACTIVE
  350.     (void) fprintf(stderr, "Usage: %s [-A] %s[-I] [-N] [-R] %s",
  351. #else
  352.     (void) fprintf(stderr, "Usage: %s [-A] %s[-N] [-R] %s",
  353. #endif
  354.             prognam, cii ? "[-H] " : "",
  355.                  cii ? "[-T] [-U] " : "");
  356.     (void) fprintf(stderr, "[-V] [%s options] [[filename]...]\n",
  357.             cii ? ci_cmd : co_cmd);
  358.     (void) fprintf(stderr, "     -A : check %s all files\n", inout);
  359. #ifdef INTERACTIVE
  360.     (void) fprintf(stderr, "     -I : interactive mode\n");
  361. #endif
  362.     if (cii)
  363. #ifdef V_RCS
  364.         (void) fprintf(stderr, "     -H : attach RCS header\n");
  365. #else
  366.         (void) fprintf(stderr, "     -H : attach SCCS header\n");
  367. #endif
  368.     (void) fprintf(stderr, "     -N : no execute mode\n");
  369.     (void) fprintf(stderr, "     -R : recursive check %s\n", inout);
  370.     if (cii)
  371.     {
  372.         (void) fprintf(stderr, "     -T : create title file\n");
  373.         (void) fprintf(stderr, "     -U : update source directory\n");
  374.     }
  375.     (void) fprintf(stderr, "     -V : verbose mode\n");
  376. }
  377.  
  378. /*--------------------------------------------------- sigcleanup() ----------
  379. / cleanup before exiting.
  380. /---------------------------------------------------------------------------*/
  381. void
  382. sigcleanup()
  383. {
  384.     (void) printf("\n[%s: Interrupted]\n", prognam);
  385.     if (title[0] && !usertitle)    /* remove title file, if here. */
  386.         (void) unlink(title);
  387.     if (editfile[0])        /* if a temp file might be here. */
  388.         (void) unlink(editfile);    /* attempt to remove it.*/
  389.     exit(0);
  390. }
  391.  
  392. /*--------------------------------------------------- doincmds() ------------
  393. / actual do routine
  394. /---------------------------------------------------------------------------*/
  395. void
  396. doincmds(argv, argc, in)
  397. char *argv[];
  398. int argc, in;
  399. {
  400.     register char *cp;
  401.     char entry[400];
  402.  
  403.     if (cii)
  404.     {
  405.         if (argc == in)        /* no arguments given */
  406.         {
  407.             do_ciodir(currentdir);
  408.             return /* void */;
  409.         }
  410.         for ( ; in < argc; in++)
  411.         {
  412. #ifdef OS2
  413.                         UnixFileName(argv[in]);
  414. #endif
  415.             (void) sprintf(entry, "%s%s", currentdir, argv[in]);
  416. #ifdef DEBUG
  417.             (void) printf("Processing %s\n", entry);
  418. #endif
  419.             if (stat(entry, &filestat))
  420.             {
  421. #ifdef DEBUG
  422.                 (void) printf("Unable to stat(2) %s\n", entry);
  423. #endif
  424.                 continue;
  425.             }
  426.             do_unlink = (filestat.st_uid == real_user_id);
  427.             if ((filestat.st_mode & S_IFMT) == S_IFDIR)
  428.                 do_ciodir(entry);
  429.             else
  430.                 (void) cio(entry);
  431.         }
  432.     }
  433.     else /* coo */
  434.     {
  435.         char *ep;
  436.  
  437.         getrcsdir(entry, currentdir);
  438.         if (argc == in)
  439.         {
  440.             do_ciodir(entry);
  441.             return /* void */;
  442.         }
  443.         for (ep = entry; *ep; ep++)
  444.             ;
  445.         for ( ; in < argc; in++)
  446.         {
  447. #ifdef OS2
  448.                         UnixFileName(argv[in]);
  449. #endif
  450.             (void) sprintf(ep, "%s", argv[in]);
  451. #ifdef DEBUG
  452.             (void) printf("Processing %s\n", entry);
  453. #endif
  454.             if (stat(entry, &filestat))
  455.             {
  456.                 if (!addrcsext(entry))
  457.                     continue;
  458.                 if (stat(entry, &filestat))
  459.                     continue;
  460.             }
  461.             do_unlink = (filestat.st_uid == real_user_id);
  462.             if ((filestat.st_mode & S_IFMT) == S_IFDIR)
  463.                 do_ciodir(entry);
  464.             else
  465.                 (void) cio(entry);
  466.         }
  467.  
  468.     }
  469.     return /* void */;
  470. }
  471.  
  472. /*--------------------------------------------------- do_ciodir() -----------
  473. / actual do routine - Warning: RECURSIVE
  474. /---------------------------------------------------------------------------*/
  475. void
  476. do_ciodir(dir)
  477. char *dir;
  478. {
  479.     FILE *pp;
  480.     char *cmd, *entry;
  481.  
  482.         if ( dir[strlen(dir) - 1] == '/' )
  483.           dir[strlen(dir) - 1] = 0;
  484. #ifdef OS2
  485.     (void) sprintf(cmd = memalloc(strlen(dir) + 10), "dir /b \"%s\"", dir);
  486. #else
  487.     (void) sprintf(cmd = memalloc(strlen(dir) + 4), "ls %s", dir);
  488. #endif
  489.     pp = popen(cmd, "r");
  490.     free(cmd);
  491.     if (!pp)
  492.         return /* void */;
  493.     entry = memalloc(strlen(dir) + 30);
  494.     while (strrd(d_ent, 80, pp) != -1)
  495.     {
  496.         (void) sprintf(entry, "%s/%s", dir, d_ent);
  497.         if (stat(entry, &filestat))
  498.         {
  499. #ifdef DEBUG
  500.             (void) printf("Unable to stat(2) %s\n", entry);
  501. #endif
  502.             continue;
  503.         }
  504.         do_unlink = (filestat.st_uid == real_user_id);
  505.         if ((filestat.st_mode & S_IFMT) == S_IFDIR)
  506.         {
  507.             if (recurse)
  508.                 do_ciodir(entry);
  509.             else
  510.                 continue;
  511.         }
  512.         else
  513.             (void) cio(entry);
  514.     }
  515.     free(entry);
  516.     (void) pclose(pp);
  517.     return /* void */;
  518. }
  519.  
  520. /*--------------------------------------------------- cio() -----------------
  521. / do this to file, if we can.
  522. /---------------------------------------------------------------------------*/
  523. int
  524. cio(filename)
  525. char *filename;
  526. {
  527.     register char *cp, *st;        /* some char pointers */
  528.     int do_copy = FALSE;        /* do cp(1) */
  529.     char titlest[100];        /* for file names. */
  530.  
  531.     if (cii)
  532.     {
  533.         if (!asciifile(filename))    /* if not ascii file */
  534.         {
  535.             if (!allfiles)
  536.                 return(FALSE);    /* don't if not forced copy */
  537.             do_copy = TRUE;
  538.         }
  539.         else if (insertheader)        /* inserting default header */
  540.         {
  541.             inshdr(filename);
  542.         }
  543.     }
  544.     else if (!rcsfile(filename))        /* not an RCS file */
  545.     {
  546.         if (!allfiles)
  547.             return(FALSE);
  548.         do_copy = TRUE;            /* simply cp(1) it */
  549.     }
  550.  
  551.     if (cii && !do_copy && !logstr[0]) /* we don't have a log entry yet. */
  552.     {
  553.         if (noexec)
  554.         {
  555.             (void) printf("Logfile entry bypassed.\n");
  556.             (void) strcpy(logstr, "");    /* fake it */
  557.         }
  558.         else if (!getfinput(titlest, TYPE_LOG)) /* if we entered anything */
  559.         {
  560.             FILE *fp;
  561.             char buf[100];
  562.             register char *bp;
  563.             register int numchars = 0;
  564.  
  565.             if (fp = fopen(titlest, "r"))
  566.             {
  567.                 st = logstr;
  568. #ifdef V_RCS
  569.                 (void) sprintf(st, " -m\"");
  570. #else
  571.                 (void) sprintf(st, " -y\"");
  572. #endif
  573.                 st += strlen(st); /* skip to end of string. */
  574.                 while (strrd(buf, 80, fp) != -1)
  575.                 {    /*
  576.                      * escape quotes (") characters
  577.                      */
  578.                     bp = buf;
  579.                     while (*bp)
  580.                     {
  581.                         if (*bp == '"')
  582.                             if (numchars < MAX_LOG)
  583.                             {
  584.                                 numchars++;
  585.                                 *st++ = '\\'; /*escape*/
  586.                             }
  587.                         if (numchars < MAX_LOG)
  588.                         {
  589.                             numchars++;
  590.                             *st++ = *bp++; /* append */
  591.                         }
  592.                     }
  593.                     *st++ = '\n'; /* add end of line now. */
  594.                 }
  595.                 if (*(st - 1) == '\n')
  596.                     *(st - 1) = '"';
  597.                 else
  598.                     *st++ = '"';
  599.                 *st = '\0';
  600.                 (void) fclose(fp);
  601.                 if (numchars >= MAX_LOG)
  602.                     (void) printf("Log entry truncated.\n");
  603.             }
  604.             (void) unlink(titlest); /* cleanup. */
  605.         }
  606.     }
  607.  
  608.     titlest[0] = '\0'; /* cleanup string reference. */
  609.     if (cii)
  610.         getrcsdir(final, filename);
  611.     else
  612.         getworkdir(final, filename);
  613.  
  614.     if (st = strrchr(final, '/'))    /* if this has a sub dir. */
  615.     {
  616.         *st = '\0';    /* terminate it at the directoy level. */
  617.         if (access(final, 0))    /* it's not here... */
  618.             if (!makedir(final))    /* so try and make it. */
  619.             {
  620.                 (void) printf("Could not create directory: %s:\n", final);
  621.                 return(FALSE);
  622.             }
  623.         *st = '/';    /* restore the rest of the file name. */
  624.     }
  625.  
  626.     if (cii)
  627.     {
  628.         if (!do_copy)    /* not in binary mode. */
  629.         {    /*
  630.              * make the new file name and check if it's here
  631.              */
  632. #ifdef V_SCCS
  633.             (void) strcpy(finalfile, final);
  634. #endif
  635. #ifdef OS2
  636.             char *rcsinit = getenv("RCSINIT");
  637.             /* only add ,v if RCS itself is configured to use ,v */
  638.             if (rcsinit && strstr(rcsinit, "-x,v/") != 0)
  639.               (void) addrcsext(final);
  640. #else
  641.             (void) addrcsext(final);
  642. #endif
  643.             if (!noexec && access(final, 0))
  644.             {
  645.                 /*
  646.                  * if not, need to get a title message for it
  647.                  */
  648.                 if (!title[0]) /* no title file yet. */
  649.                     (void) getfinput(title, TYPE_TITLE); /* get one */
  650.                 if (title[0])  /* if we've one, build command */
  651.                     (void) sprintf(titlest, " -t%s ", title);
  652. #ifdef V_SCCS
  653.                 do_admin = TRUE;    /* 1st check-in */
  654. #endif
  655.             }
  656. #ifdef V_SCCS
  657.             else
  658.                 do_admin = FALSE;
  659. #endif
  660.         }
  661.         else if (noexec)
  662.             (void) strcpy(titlest, " -tfile_name ");
  663.     }
  664.     else    /* check out mode. */
  665.     {    /*
  666.          * find a comma to make the new name.
  667.          * if found one, strip it to make a new name.
  668.          */
  669.         (void) rmrcsext(final);
  670.     }
  671.  
  672.     /*
  673.      * Build command string
  674.      */
  675.     if (do_copy)    /* we want to just copy the file now. */
  676.     {
  677.         if (!interactive && !noexec && !access(final, 0))
  678.         {
  679.             (void) printf("%s already exists.  Overwrite? (yes) ", final);
  680.             (void) strrd(cmdbuf, 20, stdin);
  681.             (void) strlwr(cmdbuf);
  682.             if (strnicmp(cmdbuf, "yes", strlen(cmdbuf)))
  683.                 return(TRUE);
  684.         }
  685.         (void) sprintf(cmdbuf, "cp -p %s %s", filename, final); /* copy command */
  686.     }
  687.     else if (cii)
  688.     {
  689. #ifdef V_RCS
  690.         (void) sprintf(cmdbuf, "%s%s%s%s%s %s %s",
  691.             ci_cmd, cioopt, titlest, logstr,
  692.             do_unlink ? "" : " -l", filename, final);
  693. #else
  694.         st = cmdbuf;
  695.         (void) sprintf(st, "cp %s %s; ", filename, finalfile);
  696.         st += strlen(st); /* skip to end of string. */
  697.         if (cp = strrchr(final, '/'))
  698.         {
  699.             *cp = '\0';
  700.             (void) sprintf(st, "cd %s; ", final);
  701.             st += strlen(st); /* skip to end of string. */
  702.             *cp = '/';
  703.         }
  704.         if (do_admin)
  705.         {
  706.             (void) sprintf(st, "%s -i%s%s%s%s %s",
  707.                 ici_cmd, justname(finalfile),
  708.                 cioopt, titlest, logstr, justname(final));
  709.             st += strlen(st); /* skip to end of string. */
  710.         }
  711.         else
  712.         {
  713.             (void) sprintf(st, "%s%s%s %s",
  714.                 ci_cmd, cioopt, logstr, justname(final));
  715.             st += strlen(st); /* skip to end of string. */
  716.         }
  717.         if (do_unlink)
  718.         {
  719.             (void) sprintf(st, "; rm %s", filename);
  720.             st += strlen(st); /* skip to end of string. */
  721.         }
  722. #endif
  723.     }
  724.     else    /* coo */
  725.     {
  726. #ifdef V_RCS
  727.         (void) sprintf(cmdbuf, "%s%s %s %s",
  728.                 co_cmd, cioopt, filename, final);
  729. #else
  730.         st = cmdbuf;
  731.         (void) sprintf(st, "rm -f %s; ", final);
  732.         st += strlen(st); /* skip to end of string. */
  733.         if (cp = strrchr(filename, '/'))
  734.         {
  735.             *cp = '\0';
  736.             (void) sprintf(st, "cd %s; ", filename);
  737.             st += strlen(st); /* skip to end of string. */
  738.             *cp = '/';
  739.         }
  740.         addrcsext(filename);
  741.         (void) sprintf(st, "%s%s %s", co_cmd, cioopt,
  742.             justname(filename));
  743.         st += strlen(st); /* skip to end of string. */
  744.         if (cp = strrchr(final, '/'))
  745.         {
  746.             cp++;
  747.             (void) sprintf(st, "; mv %s %s", cp, final);
  748.             st += strlen(st); /* skip to end of string. */
  749.         }
  750. #endif
  751.     }
  752.  
  753. #ifdef INTERACTIVE
  754.     if (interactive)
  755.     {
  756.         char ans[20];
  757.         int done = FALSE;
  758.  
  759.         do
  760.         {
  761.             (void) printf("%s\nExecute? (yes) ", cmdbuf);
  762.             (void) strrd(ans, 20, stdin);
  763.             st = ans;
  764.             while (isspace(*st))
  765.                 st++;
  766.             if (!*st)
  767.                 (void) strcpy(st, "yes");
  768.             (void) strlwr(st);
  769.             if (!strnicmp(st, "yes", strlen(st))) {
  770.                 done = TRUE;
  771.                 (void) system(cmdbuf);    /* do it. */
  772.             }
  773.             else if (*st == '?')
  774.             {
  775.                 (void) printf("\n");
  776.                 (void) printf("yes     Do it\n");
  777.                 (void) printf("no      Don't do it\n");
  778.                 (void) printf("view    View current file\n");
  779.                 (void) printf("?       Print this message\n");
  780.                 (void) printf("\n");
  781.             }
  782.             else if (!strnicmp(st, "view", strlen(st)))
  783.             {
  784.                 (void) printf("Not implemented yet!\n\n");
  785.             }
  786.             else /* take it as "no" */
  787.                 done = TRUE;
  788.         } while (!done);
  789.     }
  790.     else
  791.     {
  792. #endif /* INTERACTIVE */
  793.         if (verbose)
  794.             (void) printf("%s command: %s:\n", prognam, cmdbuf);
  795.         if (!noexec)
  796.         {
  797.             if (do_copy && !verbose)
  798.                 (void) printf("%s\n", cmdbuf);
  799.             (void) system(cmdbuf);    /* do it. */
  800.         }
  801.         else if (!verbose)    /* if don't want to exec, don't */
  802.             (void) printf("%s\n", cmdbuf);
  803. #ifdef INTERACTIVE
  804.     }
  805. #endif /* INTERACTIVE */
  806.  
  807.     if (updsrcdir)            /* update source directory */
  808.     {
  809.         getsrcdir(final, filename);
  810.  
  811.             if (st = strrchr(final, '/'))    /* if this has a sub dir. */
  812.             {
  813.                 *st = '\0';    /* terminate it at the directoy level. */
  814.                 if (access(final, 0))    /* it's not here... */
  815.                     if (!makedir(final))    /* so try and make it. */
  816.                     {
  817.                         (void) printf("Could not create directory: %s:\n", final);
  818.                         return(FALSE);
  819.                     }
  820.                 *st = '/';    /* restore the rest of the file name. */
  821.             }
  822.  
  823.         (void) sprintf(cmdbuf, "cp -p %s %s", filename, final);
  824.         if (noexec)        /* don't actual do it */
  825.             (void) printf("%s\n", cmdbuf);
  826.         else
  827.         {
  828.             if (verbose)    /* speak, yo wise one! */
  829.                 (void) printf("%s command: %s:\n", prognam, cmdbuf);
  830.             if (!stricmp(filename, final))
  831.                 (void) printf("Source and destination identical.  Not updated.\n");
  832.             else
  833.             {
  834.                 (void) chmod(final, 0640);
  835.                 (void) system(cmdbuf);    /* do it! */
  836.             }
  837.         }
  838.     }
  839.     return(TRUE);
  840. }
  841.  
  842. /*--------------------------------------------------- addrcsext() -----------
  843. / add RCS file extension ",v" if there isn't one already
  844. /---------------------------------------------------------------------------*/
  845. int
  846. addrcsext(fname)
  847. char *fname;
  848. {
  849.     register char *cp;
  850.  
  851. #ifdef V_RCS
  852.     for (cp = fname; *cp; cp++)
  853.         ;
  854.     if (*--cp == 'v' && *(cp - 1) == ',')
  855.         return(0);        /* already there */
  856.  
  857.     *++cp = ',';            /* add ",v" */
  858.     *++cp = 'v';
  859.     *++cp = '\0';
  860. #else
  861.     char t_name[20];
  862.  
  863.     cp = justname(fname);
  864.     if (*cp == 's' && *(cp + 1) == '.')
  865.         return(0);
  866.     (void) strcpy(t_name, cp);
  867.     *cp++ = 's';            /* add "s." in front of file name */
  868.     *cp++ = '.';
  869.     (void) strcpy(cp, t_name);
  870. #endif
  871.     return(1);
  872. }
  873.  
  874. /*--------------------------------------------------- rmrcsext() ------------
  875. / remove RCS extension if there is one; returns 1 if remove, else 0
  876. /---------------------------------------------------------------------------*/
  877. int
  878. rmrcsext(fname)
  879. char *fname;
  880. {
  881.     register char *cp;
  882.  
  883. #ifdef V_RCS
  884.     for (cp = fname; *cp; cp++)
  885.         ;
  886.     if (*--cp == 'v' && *--cp == ',')
  887.     {
  888.         *cp = '\0';
  889.         return(1);
  890.     }
  891. #else
  892.     cp = justname(fname);
  893.     if (*cp == 's' && *(cp + 1) == '.')
  894.     {
  895.         (void) strcpy(cp, cp + 2);
  896.         return(1);
  897.     }
  898. #endif
  899.     return(0);
  900. }
  901.  
  902. /*--------------------------------------------------- inshdr() --------------
  903. / insert RCS header if none exists already
  904. /---------------------------------------------------------------------------*/
  905. void
  906. inshdr(t_name)
  907. char *t_name;
  908. {
  909. #    define FTYPE_C        0    /* C program text */
  910. #    define FTYPE_S        1    /* assembly program text */
  911. #    define FTYPE_SH        2    /* shell script */
  912. #    define FTYPE_ROFF    3    /* nroff, tbl, eqn, etc */
  913. #    define FTYPE_F        4    /* Fortran program text */
  914. #    define FTYPE_DEFAULT    5    /* don't know */
  915. #    define FTYPE_MK        6    /* makefile script */
  916. #    define FTYPE_H        7    /* C header file text */
  917.  
  918.     static struct _ftype {
  919.         char *keyword;        /* phrase may exist in file(1) output */
  920.         char *header;        /* header template file name. */
  921.     } ftype[] = {
  922. #ifdef V_RCS
  923.         { "c program",    "rcshead.c"    },    /* FTYPE_C */
  924.         { "assembler",    "rcshead.s"    },    /* FTYPE_S */
  925.         { "command",    "rcshead.sh"    },    /* FTYPE_SH */
  926.         { "roff, tbl",    "rcshead.rof"    },    /* FTYPE_ROFF */
  927.         { "fortran",    "rcshead.f"    },    /* FTYPE_F */
  928.         { 0,        "rcshead"    },    /* FTYPE_DEFAULT */
  929.         { 0,        "rcshead.mk"    },    /* FTYPE_MK */
  930.         { 0,        "rcshead.h"    } };    /* FTYPE_H */
  931. #else
  932.         { "c program",    "sccshead.c"    },    /* FTYPE_C */
  933.         { "assembler",    "sccshead.s"    },    /* FTYPE_S */
  934.         { "command",    "sccshead.sh"    },    /* FTYPE_SH */
  935.         { "roff, tbl",    "sccshead.rof"},    /* FTYPE_ROFF */
  936.         { "fortran",    "sccshead.f"    },    /* FTYPE_F */
  937.         { 0,        "sccshead"    },    /* FTYPE_DEFAULT */
  938.         { 0,        "sccshead.mk"    },    /* FTYPE_MK */
  939.         { 0,        "sccshead.h"    } };    /* FTYPE_H */
  940. #endif /* V_RCS */
  941.     static struct _fext {
  942.         char *name;
  943.         int type;
  944.     } fext[] = {
  945.         { ".c",        FTYPE_C        },
  946.         { ".h",        FTYPE_H        },
  947.         { ".s",        FTYPE_S        },
  948.         { ".f",        FTYPE_F        },
  949.         { ".man",    FTYPE_ROFF    },
  950.         { ".mk",    FTYPE_MK    },
  951.         { ".1",        FTYPE_ROFF    },
  952.         { ".2",        FTYPE_ROFF    },
  953.         { ".3",        FTYPE_ROFF    },
  954.         { ".4",        FTYPE_ROFF    },
  955.         { ".5",        FTYPE_ROFF    },
  956.         { ".6",        FTYPE_ROFF    },
  957.         { ".7",        FTYPE_ROFF    },
  958.         { ".8",        FTYPE_ROFF    },
  959.         { ".9",        FTYPE_ROFF    },
  960.         { 0,        0        } };
  961.     FILE *ifp, *ofp;
  962.     char buf[4096], headfile[128], tempfile[20], fname[40];
  963.     register int i, c, ft = FTYPE_DEFAULT, err=0;
  964.     register char *ext;
  965.  
  966.     strcpy(fname, justname(t_name)); /* copy over only name. */
  967.  
  968.     if (!(ifp = fopen(t_name, "r")))    /* quickly check for RCS header */
  969.         return;
  970.                     /* we are looking for "$Header" */
  971.                     /* within first 50 lines of the file */
  972.     for (i = 0; strrd(buf, 128, ifp) > 0 && i < 50; i++)
  973. #ifdef V_RCS
  974.         if (strstr(buf, "$Header"))
  975. #else
  976.         if (strstr(buf, "#ident"))
  977. #endif
  978.         {
  979.             (void) fclose(ifp);
  980.             if (verbose)
  981. #ifdef V_RCS
  982.                 (void) printf("%s already has a RCS header.\n",
  983. #else
  984.                 (void) printf("%s already has a SCCS header.\n",
  985. #endif /* V_RCS */
  986.                         t_name);
  987.             return;
  988.         }
  989.  
  990.     (void) fclose(ifp);
  991.                     /* examine file(1) output */
  992.     for (i = 0; ftype[i].keyword; i++)
  993.         if (strstr(ftypestr, ftype[i].keyword))
  994.         {
  995.             ft = i;
  996.             break;        /* found one */
  997.         }
  998.  
  999.     if (!ftype[i].keyword)        /* file(1) didn't help */
  1000.     {                /* examine file extension */
  1001.         if (ext = strrchr(fname, '.'))
  1002.         {
  1003.             for (i = 0; fext[i].name; i++)
  1004.                 if (!stricmp(ext, fext[i].name))
  1005.                     ft = fext[i].type;
  1006.         }
  1007.         else
  1008.         {            /* check if makefile script */
  1009.             (void) strcpy(buf, fname);
  1010.             (void) strlwr(buf);
  1011.             if (!strcmp(buf, "makefile") || !strcmp(buf, "Makefile"))
  1012.                 ft = FTYPE_MK; /* If either of two fixed names.. */
  1013.         }
  1014.     }
  1015.     else if (ft == FTYPE_C)        /* see if source or header */
  1016.     {
  1017.         if ((ext = strrchr(fname, '.')) && !stricmp(ext, ".h"))
  1018.             ft = FTYPE_H;
  1019.     }
  1020.     if (verbose)            /* is this necessary */
  1021.         (void) printf("%s is type [%d]\n", fname, ft);
  1022.     if (noexec)            /* no execution mode */
  1023.         return;
  1024.  
  1025.     (void) sprintf(headfile, "%s%s", headdir, ftype[ft].header);
  1026.     if (!(ifp = fopen(headfile, "r")))
  1027.     {
  1028.         (void) printf("Unable to open header template file [%s]\n",
  1029.                 headfile);
  1030.         return;
  1031.     }
  1032.     /* build a tmp file in the same directory as old file. */
  1033.     strcpy(tempfile, t_name);
  1034.     ext = justname(tempfile); /* find end of path. */
  1035.     *ext = '\0'; /* and terminate path there. */
  1036.     (void) strcat(tempfile, "ctXXXXXX"); /* add tmp name */
  1037.     (void) mktemp(tempfile);        /* generate temp file name */
  1038.     if (!(ofp = fopen(tempfile, "w")))    /* open temp file */
  1039.     {
  1040.         (void) printf("Unable to open temporary file [%s]\n", tempfile);
  1041.         (void) fclose(ifp);
  1042.         return;
  1043.     }
  1044.     while ((c = fgetc(ifp)) != EOF)        /* copy header first */
  1045.         (void) fputc(c, ofp);
  1046.     (void) fclose(ifp);
  1047.     if (!(ifp = fopen(t_name, "r")))        /* open check-in file */
  1048.     {
  1049.         (void) printf("Unable to open [%s] for read\n", t_name);
  1050.         (void) fclose(ofp);
  1051.         (void) unlink(tempfile);
  1052.         return;
  1053.     }
  1054.     while ((c = fgetc(ifp)) != EOF)        /* append to temp file */
  1055.         if(fputc(c, ofp) == EOF)
  1056.             err=1; /* couldn't write error. */
  1057.     (void) fclose(ifp);            /* done */
  1058.     (void) fclose(ofp);
  1059.  
  1060. /* ok.  It's hard to make sure that everthing has gone well; if we unlink
  1061.    the src file and can't link the temp file, we could lose everthing.
  1062.    So, if copy fails, leave temp file alone, as it may be the only copy
  1063.    we have left!  If the unlinking the original fails, we can remove the
  1064.    copy, as we don't need it.
  1065. */
  1066.     if(!err && !unlink(t_name))    /* 'mv tempfile fname' */
  1067.     {           
  1068. #ifndef OS2                
  1069.         if(!link(tempfile, t_name)) /* 'cp tempfile t_name' */
  1070.             (void) unlink(tempfile);        /* 'rm tempfile' */
  1071.         else
  1072.             (void) printf("Link of %s and %s failed after removing %s.\n%s not removed.\n",
  1073.                 tempfile, t_name, t_name, tempfile);
  1074. #else
  1075.         if(!rename(tempfile, t_name)) /* 'cp tempfile t_name' */
  1076.             (void) printf("Rename of %s to %s failed after removing %s.\n%s not removed.\n",
  1077.                 tempfile, t_name, t_name, tempfile);
  1078. #endif
  1079.     }
  1080.     else
  1081.     {
  1082.         (void) unlink(tempfile);        /* 'rm tempfile' */
  1083.         (void) printf("Could not insert header into %s.  Copy failed.\n", t_name);
  1084.     }
  1085. }
  1086.  
  1087. /*--------------------------------------------------- makedir() -------------
  1088. / make a directory path, with recursion.
  1089. / returns TRUE if successful, FALSE otherwise.
  1090. /
  1091. / This really needs to be re-written.  It works, but that's all I can really
  1092. / say for it...  Hey, *I* don't have mkdir() calls!
  1093. /---------------------------------------------------------------------------*/
  1094. int
  1095. makedir(newpath)
  1096. char *newpath;        /* path name to make. */
  1097. {
  1098.     register char *st, *cp;
  1099.  
  1100.     if(!*newpath) return(FALSE); /* skip last directory attempt. */
  1101.     if (noexec)
  1102.     {
  1103.         (void) printf("mkdir: %s\n", newpath);
  1104.         return(TRUE);
  1105.     }
  1106.     else if(verbose)
  1107.         (void) printf("mkdir: %s\n", newpath);
  1108.  
  1109.     cp = memalloc(strlen(newpath) + 24);
  1110.  
  1111.     if (mkdir(newpath))            /* it failed.. */
  1112.     {
  1113.         (void) strcpy(cp, newpath);    /* get current one. */
  1114.         st = strrchr(cp, '/'); /* remove one more layer.. */
  1115.         *st = '\0';        /* terminate here. */
  1116.         if (makedir(cp) == FALSE)    /* try and build next level back. */
  1117.         {
  1118.             free(cp);
  1119.             return(FALSE);
  1120.         }
  1121.                 /* ok, so.. it passed on back. Try this again. */
  1122.         if(mkdir(newpath))
  1123.         {
  1124.             free(cp);
  1125.             return(FALSE);
  1126.         }
  1127.     }
  1128.  
  1129.     free(cp);
  1130.     return(TRUE);
  1131. }
  1132.  
  1133. /*--------------------------------------------------- strstr() --------------
  1134. / find a substring within a string
  1135. /---------------------------------------------------------------------------*/
  1136. #ifndef OS2
  1137. char *
  1138. strstr(s1, s2)
  1139. register char *s1, *s2;
  1140. {
  1141.     register int l;
  1142.  
  1143.     if (l = strlen(s2))
  1144.         for ( ; s1 = strchr(s1, s2[0]); s1++)
  1145.             if (memcmp(s1, s2, l) == 0)
  1146.                 break;
  1147.     return(s1);
  1148. }
  1149.  
  1150. /*--------------------------------------------------- strlwr() ---------------
  1151. / strlwr.c - convert passed string to its equivalent lowercases
  1152. /----------------------------------------------------------------------------*/
  1153. char *
  1154. strlwr(s)
  1155. register char *s;
  1156. {
  1157.     char *op;
  1158.  
  1159.     for (op = s; *s; s++)
  1160.         if (isupper(*s))
  1161.             *s = _tolower(*s);
  1162.     return(op);
  1163. }
  1164. #endif
  1165.  
  1166. /*--------------------------------------------------- asciifile() -----------
  1167. / check if passed file is an ascii file using file(1) command
  1168. /---------------------------------------------------------------------------*/
  1169. int
  1170. asciifile(fn)
  1171. char *fn;
  1172. {
  1173.     char cmdstr[256];
  1174.     register FILE *fp;
  1175.  
  1176. #ifdef OS2
  1177.         int file, cnt, i;
  1178.  
  1179.     if ((file = open(fn, O_RDONLY|O_BINARY)) == -1)
  1180.         return(FALSE);
  1181.     cnt = read(file, cmdstr, sizeof(cmdstr)); /* get a block. */
  1182.     close(file);    /* and done. */
  1183.  
  1184.         for ( i = 0; i < cnt; i++ )
  1185.                 if ( cmdstr[i] == 0 || cmdstr[i] == 127 )
  1186.                     return(FALSE);
  1187.  
  1188.         return(TRUE);
  1189. #else /* OS2 */
  1190.     (void) sprintf(cmdstr, "file %s", fn);
  1191.     if (!(fp = popen(cmdstr, "r")))
  1192.         return(FALSE);
  1193.     (void) strrd(ftypestr, 80, fp); /* get a line. */
  1194.     (void) pclose(fp);    /* and done. */
  1195. #ifdef DEBUG
  1196.     (void) printf("%s\n", cmdstr);
  1197. #endif
  1198.     if (strstr(ftypestr, "text"))
  1199.         return(TRUE);
  1200.     return(FALSE);
  1201. #endif /* OS2 */
  1202. }
  1203.  
  1204. /*--------------------------------------------------- rcsfile() -------------
  1205. / check if passed file is an RCS file using file(1) command
  1206. /---------------------------------------------------------------------------*/
  1207. int
  1208. rcsfile(fn)
  1209. char *fn;
  1210. {
  1211.     char cmdstr[256];
  1212.     register FILE *fp;
  1213.  
  1214. #ifdef OS2
  1215.     if (!(fp = fopen(fn, "r")))
  1216.         return(FALSE);
  1217.     (void) strrd(ftypestr, 80, fp); /* get a line. */
  1218.     (void) fclose(fp);    /* and done. */
  1219. #ifdef DEBUG
  1220.     (void) printf("%s\n", cmdstr);
  1221. #endif
  1222.     if (strcmp(ftypestr, "head     "))
  1223.         return(TRUE);
  1224. #else /* OS2 */
  1225.     (void) sprintf(cmdstr, "file %s", fn);
  1226.     if (!(fp = popen(cmdstr, "r")))
  1227.         return(FALSE);
  1228.     (void) strrd(ftypestr, 80, fp); /* get a line. */
  1229.     (void) pclose(fp);    /* and done. */
  1230. #ifdef DEBUG
  1231.     (void) printf("%s\n", cmdstr);
  1232. #endif
  1233. #ifdef V_RCS
  1234.     if (strstr(ftypestr, "text"))
  1235. #else
  1236.     if (strstr(ftypestr, "sccs"))
  1237. #endif
  1238.         return(TRUE);
  1239. #endif /* OS2 */
  1240.     return(FALSE);
  1241. }
  1242.  
  1243. /*--------------------------------------------------- strrd() ----------------
  1244. / read from given file pointer until a line separator or end-of-file or
  1245. / (len) characters excluding the terminator.
  1246. /---------------------------------------------------------------------------*/
  1247. int
  1248. strrd(buf, len, fle)
  1249. char *buf;
  1250. int len;
  1251. FILE *fle;
  1252. {
  1253.     int c0, i0 = 0;
  1254.  
  1255.     while (((c0 = getc(fle)) != EOF) && c0 && c0 != '\n')
  1256.         if(i0 < len)  /* if room in buffer..*/
  1257.             buf[i0++] = (char) c0;  /* save it. */
  1258.     buf[i0] = 0;
  1259.     if (i0 == 0 && c0 == EOF)
  1260.         return(-1);
  1261.     return(i0);
  1262. }
  1263.  
  1264. /*--------------------------------------------------- getdir() --------------
  1265. / get and readin variables for later.
  1266. /---------------------------------------------------------------------------*/
  1267. void
  1268. getdir()
  1269. {
  1270.     register char *cp;
  1271.  
  1272.     if(cp = getenv("HOME"))        /* get user's home dir. */
  1273.     {
  1274.         (void) strcpy(homedir = memalloc(strlen(cp) + 2), cp);
  1275.         if (!(s_homedir = fix_envstr(homedir)))
  1276.         {
  1277.             free(homedir);
  1278.             homedir = (char *) 0;
  1279.         }
  1280.     }
  1281.     else                /* this should NEVER happen */
  1282.     {
  1283.         (void) fprintf(stderr, "No home directory???\n");
  1284.         exit(-1);
  1285.     }
  1286.  
  1287. #ifdef V_RCS
  1288.     if(cp = getenv("RCSDIR"))    /* RCS directory */
  1289. #else
  1290.     if(cp = getenv("SCCSDIR"))    /* SCCS directory */
  1291. #endif
  1292.         (void) strcpy(rcsdir = memalloc(strlen(cp) + 2), cp);
  1293.     else                /* RCS is $HOME/RCS */
  1294.         (void) sprintf(rcsdir = memalloc(s_homedir + 6),
  1295. #ifdef V_RCS
  1296.                 "%s/RCS", homedir);
  1297. #else
  1298.                 "%s/SCCS", homedir);
  1299. #endif
  1300.     if (!(s_rcsdir = fix_envstr(rcsdir)))
  1301.     {
  1302.         free(rcsdir);
  1303.         rcsdir = (char *) 0;
  1304.     }
  1305.  
  1306. #ifdef V_RCS
  1307.     if(cp = getenv("RCSWORK"))    /* user's working directory */
  1308. #else
  1309.     if(cp = getenv("SCCSWORK"))    /* user's working directory */
  1310. #endif
  1311.     {
  1312.         (void) strcpy(rcswrk = memalloc(strlen(cp) + 2), cp);
  1313.         if (!(s_rcswrk = fix_envstr(rcswrk)))
  1314.         {
  1315.             free(rcswrk);
  1316.             rcswrk = (char *) 0;
  1317.         }
  1318.     }
  1319.  
  1320. #ifdef V_RCS
  1321.     if (cp = getenv("RCSSRC"))    /* master source directory */
  1322. #else
  1323.     if (cp = getenv("SCCSSRC"))    /* master source directory */
  1324. #endif
  1325.     {
  1326.         (void) strcpy(srcdir = memalloc(strlen(cp) + 2), cp);
  1327.         if (!(s_srcdir = fix_envstr(srcdir)))
  1328.         {
  1329.             free(srcdir);
  1330.             srcdir = (char *) 0;
  1331.         }
  1332.     }
  1333.  
  1334. #ifdef V_RCS
  1335.     if (cp = getenv("RCSHEAD"))    /* RCS header file directory */
  1336. #else
  1337.     if (cp = getenv("SCCSHEAD"))    /* SCCS header file directory */
  1338. #endif
  1339.     {
  1340.         (void) strcpy(headdir = memalloc(strlen(cp) + 2), cp);
  1341.         if (!(s_headdir = fix_envstr(headdir)))
  1342.         {
  1343.             free(headdir);
  1344.             headdir = homedir;
  1345.         }
  1346.     }
  1347.     else
  1348.         headdir = homedir;
  1349.  
  1350. #ifdef V_RCS
  1351.     if (cp = getenv("RCSOWN"))    /* the owner of RCS files */
  1352. #else
  1353.     if (cp = getenv("SCCSOWN"))    /* the owner of SCCS files */
  1354. #endif
  1355.     {
  1356.         s_rcsown = strlen(cp);
  1357.         (void) strcpy(rcsown = memalloc(s_rcsown + 1), cp);
  1358.     }
  1359.  
  1360.     if(cp = getenv("PATH"))        /* current path, ie. $PATH */
  1361.     {
  1362.         s_path = strlen(cp);
  1363.         (void) strcpy(path = memalloc(s_path + 1), cp);
  1364.     }
  1365.  
  1366.     if((currentdir = getcwd((char *)NULL, 200)) == NULL)
  1367.     {
  1368.         (void) fprintf(stderr, "Cannot get working dir.\n");
  1369.         exit(-1);
  1370.     }
  1371. #ifdef OS2
  1372.         /* strcpy(currentdir, currentdir + 2); */
  1373.         UnixFileName(currentdir);
  1374. #endif
  1375.         strcat(currentdir, "/");
  1376.     s_currentdir = strlen(currentdir);
  1377. }
  1378.  
  1379. /*--------------------------------------------------- fix_envstr() ----------
  1380. / fix environment variable to avoid problems later.
  1381. / 1. strip leading/trailing white spaces
  1382. / 2. strip duplicate slashes
  1383. / 3. add trailing slash
  1384. / 4. return string length
  1385. /---------------------------------------------------------------------------*/
  1386. int
  1387. fix_envstr(cs)
  1388. char *cs;
  1389. {
  1390.     register char *cp, *dp;
  1391.     register int was_slash = FALSE;
  1392.  
  1393. #ifdef OS2
  1394.         UnixFileName(cs);
  1395. #endif
  1396.  
  1397.     cp = dp = cs;
  1398.     while (isspace(*cp))        /* remove leading white spaces */
  1399.         cp++;
  1400.  
  1401.     if (!*cp)            /* string was a full of blanks */
  1402.         return(0);
  1403.  
  1404.     while (*cp)
  1405.     {
  1406.         if (*cp == '/')
  1407.         {
  1408.             if (was_slash)
  1409.             {
  1410.                 cp++;    /* strip duplicate slashes */
  1411.                 continue;
  1412.             }
  1413.             else
  1414.                 was_slash = TRUE;
  1415.         }
  1416.         else
  1417.             was_slash = FALSE;
  1418.         *dp++ = *cp++;
  1419.     }
  1420.  
  1421.     do                /* remove trailing while spaces */
  1422.     {
  1423.         dp--;
  1424.     } while (isspace(*dp));
  1425.  
  1426.     if (*dp != '/')            /* add trailing slash */
  1427.         *++dp = '/';
  1428.     *++dp = '\0';            /* null terminate */
  1429.     return(strlen(cs));
  1430. }
  1431.  
  1432. /*--------------------------------------------------- getrcsdir() -----------
  1433. / get $RCSDIR + tail directory
  1434. /---------------------------------------------------------------------------*/
  1435. void
  1436. getrcsdir(tdir, sdir)
  1437. char *tdir, *sdir;
  1438. {
  1439.     register char *cp = sdir;
  1440.  
  1441.     if(rcswrk && !strnicmp(rcswrk, cp, s_rcswrk))
  1442.         cp += s_rcswrk;
  1443.     if(homedir && !strnicmp(homedir, cp, s_homedir))
  1444.         cp += s_homedir;
  1445. #ifdef OS2
  1446.         if(isalpha(cp[0]) && cp[1] == ':')
  1447.                 cp += 2;
  1448. #endif
  1449.         if(cp[0] == '/')
  1450.                 cp++;
  1451.     /*
  1452.      * build the final directory name
  1453.      */
  1454.     (void) sprintf(tdir, "%s%s", rcsdir, cp);
  1455. }
  1456.  
  1457. /*--------------------------------------------------- getworkdir() ----------
  1458. / get $RCSWORK or $HOME + tail
  1459. /---------------------------------------------------------------------------*/
  1460. void
  1461. getworkdir(tdir, sdir)
  1462. char *tdir, *sdir;
  1463. {
  1464.     register char *cp = sdir;
  1465.  
  1466.     if (rcsdir && !strnicmp(rcsdir, cp, s_rcsdir))
  1467.         cp += s_rcsdir;
  1468. #ifdef OS2
  1469.         if(isalpha(cp[0]) && cp[1] == ':')
  1470.                 cp += 2;
  1471. #endif
  1472.         if(cp[0] == '/')
  1473.                 cp++;
  1474.     (void) sprintf(tdir, "%s%s", rcswrk ? rcswrk : homedir, cp);
  1475. }
  1476.  
  1477. /*--------------------------------------------------- getsrcdir() -----------
  1478. / get $RCSSRC + tail
  1479. /---------------------------------------------------------------------------*/
  1480. void
  1481. getsrcdir(tdir, sdir)
  1482. char *tdir, *sdir;
  1483. {
  1484.     register char *cp = sdir;
  1485.  
  1486.     if (rcswrk && !strnicmp(rcswrk, cp, s_rcswrk))
  1487.         cp += s_rcswrk;
  1488.     if(homedir && !strnicmp(homedir, cp, s_homedir))
  1489.         cp += s_homedir;
  1490. #ifdef OS2
  1491.         if(isalpha(cp[0]) && cp[1] == ':')
  1492.                 cp += 2;
  1493. #endif
  1494.         if(cp[0] == '/')
  1495.                 cp++;
  1496.     (void) sprintf(tdir, "%s%s", srcdir ? srcdir : homedir, cp);
  1497. }
  1498.  
  1499. /*--------------------------------------------------- getfinput() ------------
  1500. / get a title file.
  1501. /---------------------------------------------------------------------------*/
  1502. int
  1503. getfinput(name, type)
  1504. char *name;        /* buffer to put file name into. */
  1505. int type;        /* what data we want. */
  1506. {
  1507.     int stat_loc;
  1508.  
  1509.     (void) strcpy(name, tmpnam(editfile));
  1510. #ifndef OS2
  1511.     if (fork())
  1512.     {    /* parent just waits for the child to finish */
  1513.         (void) wait(&stat_loc);
  1514.     }
  1515.     else
  1516.     {    /* child does his/her stuff */
  1517.         (void) signal(SIGINT, SIG_DFL);
  1518.         (void) signal(SIGQUIT, SIG_DFL);
  1519.         (void) signal(SIGBREAK, SIG_DFL);
  1520.         (void) signal(SIGTERM, SIG_DFL);
  1521.         exit(child_getfinput(name, type) == TRUE ? 0 : -1);
  1522.     }
  1523.     return((stat_loc >> 8) & 0xff);
  1524. #else
  1525.     return child_getfinput(name, type) == TRUE ? 0 : -1;
  1526. #endif
  1527. }
  1528.  
  1529. /*--------------------------------------------------- child_getfinput() -----
  1530. / actual get title file.
  1531. /---------------------------------------------------------------------------*/
  1532. int
  1533. child_getfinput(name, type)
  1534. char *name;        /* buffer to put file name into. */
  1535. int type;        /* what data we want. */
  1536. {
  1537.     static char *input_type[2] = { "log", "title" };
  1538.     FILE *fp, *xfp;
  1539.     register char *st;
  1540.     int c, done = FALSE;
  1541.     char buf[82];            /* just larger than input buffer. */
  1542.                   
  1543. #ifndef OS2
  1544.     (void) setuid(real_user_id);        /* user's real user id */
  1545. #endif        
  1546.     if((fp = fopen(name, "w")) == NULL) /* failed open. */
  1547.     {
  1548.         (void) unlink(name);        /* remove it. */
  1549.         name[0] = '\0';
  1550.         (void) printf("Unable to create tmp file.\n");
  1551.         return(FALSE);
  1552.     }
  1553.     (void) printf("Enter %s message, <ret>.<ret> or Control-Z to end:\n",
  1554.         input_type[type]);
  1555.     while (!done)
  1556.     {
  1557.         (void) printf(">>");
  1558.         if(strrd(buf, 80, stdin) == -1) /* read in one line. */
  1559.         {
  1560.             /* ok, read somewhere that this is possible.  By doing this,
  1561.                we should be able to continue after a control-D.
  1562.             */
  1563.             clearerr(stdin);
  1564.             break;
  1565.         }
  1566.         if(!strcmp(".", buf))    /* end of message */
  1567.             break;
  1568.         if (buf[0] == '~')    /* special command */
  1569.         {
  1570.             switch (buf[1])    /* command character */
  1571.             {
  1572.             case '?':    /* print usage, help message */
  1573.                 (void) printf("\n");
  1574.                 (void) printf("~.    End of input\n");
  1575.                 (void) printf("~!    Invoke shell\n");
  1576.                 (void) printf("~e    Edit message using an editor\n");
  1577.                 (void) printf("~p    Print message buffer\n");
  1578.                 (void) printf("~r    Read in a file\n");
  1579.                 (void) printf("~w    Write message to a file\n");
  1580.                 (void) printf("~?    Print this message\n");
  1581.                 (void) printf("\n");
  1582.                 break;
  1583.             case '!':    /* shell */
  1584.                 st = getenv("SHELL");
  1585.                 (void) system(st ? st : "/bin/sh");
  1586.                 (void) printf("[Press RETURN to continue]");
  1587.                 (void) strrd(buf, 20, stdin);
  1588.                 break;
  1589.             case 'p':    /* print message buffer content */
  1590.                 (void) fclose(fp);
  1591.                 fp = fopen(name, "r");
  1592.                 while ((c = fgetc(fp)) != EOF)
  1593.                     (void) fputc(c, stdout);
  1594.                 (void) fclose(fp);
  1595.                 fp = fopen(name, "a");
  1596.                 (void) printf("Continue entering %s message.\n",
  1597.                     input_type[type]);
  1598.                 break;
  1599.             case 'e':    /* editor */
  1600.             case 'v':    /* visual */
  1601.                 (void) fclose(fp);
  1602.                 st = getenv(buf[1] == 'e' ?"EDITOR":"VISUAL");
  1603.                 (void) sprintf(buf, "%s %s",
  1604.                     st ? st : "/usr/bin/vi", name);
  1605.                 (void) system(buf);
  1606.                 fp = fopen(name, "a");
  1607.                 (void) printf("Continue entering %s message.\n",
  1608.                     input_type[type]);
  1609.                 break;
  1610.             case 'r':    /* read in a file */
  1611.                 st = &buf[2];
  1612.                 while (isspace(*st))
  1613.                     st++;
  1614.                 if (!*st)
  1615.                 {
  1616.                     (void) printf("File name missing!\n");
  1617.                     break;
  1618.                 }
  1619.                 if (xfp = fopen(st, "r"))
  1620.                 {
  1621.                     while ((c = fgetc(xfp)) != EOF)
  1622.                         (void) fputc(c, fp);
  1623.                     (void) fclose(xfp);
  1624.                 }
  1625.                 else
  1626.                     (void) printf("Unable to open %s.\n",
  1627.                             st);
  1628.                 break;
  1629.             case 'w':    /* write message to a file */
  1630.                 st = &buf[2];
  1631.                 while (isspace(*st))
  1632.                     st++;
  1633.                 if (!*st)
  1634.                     (void) printf("File name missing!\n");
  1635.                 else
  1636.                 {
  1637.                     if (xfp = fopen(st, "a"))
  1638.                     {
  1639.                         (void) fclose(fp);
  1640.                         fp = fopen(name, "r");
  1641.                         while ((c = fgetc(fp)) != EOF)
  1642.                             (void) fputc(c, xfp);
  1643.                         (void) fclose(xfp);
  1644.                         (void) fclose(fp);
  1645.                         fp = fopen(name, "a");
  1646.                     }
  1647.                     else
  1648.                         (void) printf("Unable to open %s.\n",
  1649.                             st);
  1650.                 }
  1651.                 break;
  1652.             case '.':    /* end of message */
  1653.                 done = TRUE;
  1654.                 break;
  1655.             default:    /* user doesn't know */
  1656.                 (void) printf("Unrecognized command %c -- ignored\n",
  1657.                     buf[1] & 0x7f);
  1658.                 break;
  1659.             }
  1660.             continue;
  1661.         }
  1662.         (void) fprintf(fp, "%s\n", buf);
  1663.     }
  1664.     (void) fclose(fp);
  1665.     (void) printf("\n");
  1666.     return(TRUE);
  1667. }
  1668.  
  1669. /*--------------------------------------------------- justname() ------------
  1670. / extract just filename from a full path
  1671. /---------------------------------------------------------------------------*/
  1672. char *
  1673. justname(fpath)
  1674. char *fpath;
  1675. {
  1676.     register char *cp;
  1677.  
  1678. #ifdef OS2
  1679.         UnixFileName(fpath);
  1680. #endif
  1681.     if (cp = strrchr(fpath, '/'))
  1682.         return(++cp);
  1683.  
  1684.     return(fpath);
  1685. }
  1686.  
  1687. /*--------------------------------------------------- memalloc() ------------
  1688. / allocate specified amount of memory.  If not successful, exit.
  1689. /---------------------------------------------------------------------------*/
  1690. char *
  1691. memalloc(size)
  1692. register int size;
  1693. {
  1694.     register char *cp;
  1695.  
  1696.     if (!(cp = malloc((unsigned)size)))
  1697.     {
  1698.         perror(prognam);
  1699.         exit(99);
  1700.     }
  1701.     return(cp);
  1702. }
  1703.  
  1704. /*--------------------------------------------------- get_final_id() --------
  1705. / Get the RCSOWN user id to create files with.  If none found, use user id.
  1706. /---------------------------------------------------------------------------*/
  1707. void
  1708. get_final_id()
  1709. {
  1710.     FILE *fp;
  1711.  
  1712.     if(!rcsown)            /* if there isn't one of these. */
  1713. #ifdef V_RCS
  1714.         rcsown = "rcsfiles";    /* default name. */
  1715. #else
  1716.         rcsown = "sccsfiles";    /* default name. */
  1717. #endif
  1718.  
  1719.     if ((fp = fopen (pwdfile, "r")) == NULL)
  1720.     {
  1721. #ifdef DEBUG
  1722.         (void) fprintf(stderr, "setpwent: %s non-existant or unreadable.\n",
  1723.                 pwdfile);
  1724. #endif
  1725.         user_id = real_user_id;        /* make sure it's owners id now. */
  1726.         return;        /* couldn't do it. */
  1727.     }
  1728.     while (nextent(fp))        /* while entries in file.. */
  1729.         if (!strcmp(pwdname, rcsown))   /* If name matches. */
  1730.             break;
  1731.     (void) fclose(fp);    /* close the file. */
  1732.     return;            /* found it or not, return. */
  1733. }
  1734.  
  1735. /*--------------------------------------------------- nextent() -------------
  1736. / get one entry from a password file.  Return TRUE if there is one found,
  1737. / FALSE otherwise.
  1738. /---------------------------------------------------------------------------*/
  1739. int
  1740. nextent(fle)
  1741. FILE *fle;     /* file pointer. */
  1742. {
  1743.     register char *cp, *pwp;
  1744.     char savbuf[200];    /* usually large enough for a password entry. */
  1745.  
  1746.     while (strrd(savbuf, (int) (sizeof (savbuf)), fle) != -1)
  1747.     {
  1748.         pwp = pwdname;
  1749.         cp = savbuf;        /* get user name */
  1750.         while (*cp && *cp != ':')
  1751.             *pwp++ = *cp++;
  1752.         *pwp = '\0';        /* terminate name. */
  1753.         for (cp++; *cp && *cp != ':'; cp++)
  1754.             ;        /* skip over password. */
  1755.         user_id = atoi(++cp);    /* ok, save this users id number. */
  1756.         return (TRUE);
  1757.     }
  1758.     user_id = real_user_id;        /* make sure it's owners id now. */
  1759.     return (FALSE);
  1760. }
  1761.  
  1762. /*----------------------------- End of cio.c -------------------------------*/
  1763.  
  1764. #ifdef OS2
  1765. UnixFileName(char *name)
  1766. {
  1767.   /* strlwr(name); */
  1768.   for ( ; *name; name++ )
  1769.     if ( *name == '\\' )
  1770.       *name = '/';
  1771. }
  1772. #endif
  1773.  
  1774.