home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OS9000 / APPS / rcs.lzh / rcs1 / rcsfnms.c < prev    next >
Text File  |  1996-04-20  |  36KB  |  1,094 lines

  1. /*
  2.  *                     RCS file name handling
  3.  */
  4. #ifndef lint
  5.  static char
  6.  rcsid[]= "$Id: rcsfnms.c_v 1.2 96/04/07 00:19:49 hiro Exp $ Purdue CS";
  7. #endif
  8. /****************************************************************************
  9.  *                     creation and deletion of semaphorefile,
  10.  *                     creation of temporary filenames and cleanup()
  11.  *                     pairing of RCS file names and working file names.
  12.  *                     Testprogram: define PAIRTEST
  13.  ****************************************************************************
  14.  */
  15.  
  16. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  17.    Distributed under license by the Free Software Foundation, Inc.
  18.  
  19. This file is part of RCS.
  20.  
  21. RCS is free software; you can redistribute it and/or modify
  22. it under the terms of the GNU General Public License as published by
  23. the Free Software Foundation; either version 1, or (at your option)
  24. any later version.
  25.  
  26. RCS is distributed in the hope that it will be useful,
  27. but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  29. GNU General Public License for more details.
  30.  
  31. You should have received a copy of the GNU General Public License
  32. along with RCS; see the file COPYING.  If not, write to
  33. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  34.  
  35. Report problems and direct all questions to:
  36.  
  37.     rcs-bugs@cs.purdue.edu
  38.  
  39. */
  40.  
  41.  
  42.  
  43.  
  44. /* $Log:    rcsfnms.c_v $
  45.  * Revision 1.2  96/04/07  00:19:49  hiro
  46.  * Ported to OS-9000.
  47.  * 
  48.  * Revision 1.1  93/04/02  01:30:56  hiro
  49.  * Initial revision
  50.  * 
  51.  * Revision 1.2  90/07/23  10:24:37  momo
  52.  * Minor change
  53.  * 
  54.  * Revision 1.1  90/07/19  15:21:30  momo
  55.  * Initial revision
  56.  * 
  57.  * revision 5.2 koya 90/01/24 10:22:39
  58.  * Change path-name handlars.
  59.  * Especially, separator of path names.
  60.  * 
  61.  * revision 5.1 koya 90/01/24 07:05:43
  62.  * Initial revision
  63.  * 
  64.  * Revision 4.8  89/05/01  15:09:41  narten
  65.  * changed getwd to not stat empty directories.
  66.  * 
  67.  * Revision 4.7  88/11/08  12:01:22  narten
  68.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  69.  * 
  70.  * Revision 4.7  88/08/09  19:12:53  eggert
  71.  * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint.
  72.  * 
  73.  * Revision 4.6  87/12/18  11:40:23  narten
  74.  * additional file types added from 4.3 BSD version, and SPARC assembler
  75.  * comment character added. Also, more lint cleanups. (Guy Harris)
  76.  * 
  77.  * Revision 4.5  87/10/18  10:34:16  narten
  78.  * Updating version numbers. Changes relative to 1.1 actually relative
  79.  * to verion 4.3
  80.  * 
  81.  * Revision 1.3  87/03/27  14:22:21  jenkins
  82.  * Port to suns
  83.  * 
  84.  * Revision 1.2  85/06/26  07:34:28  svb
  85.  * Comment leader '% ' for '*.tex' files added.
  86.  * 
  87.  * Revision 1.1  84/01/23  14:50:24  kcs
  88.  * Initial revision
  89.  * 
  90.  * Revision 4.3  83/12/15  12:26:48  wft
  91.  * Added check for KDELIM in file names to pairfilenames().
  92.  * 
  93.  * Revision 4.2  83/12/02  22:47:45  wft
  94.  * Added csh, red, and sl file name suffixes.
  95.  * 
  96.  * Revision 4.1  83/05/11  16:23:39  wft
  97.  * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames():
  98.  * 1. added copying of path from workfile to RCS file, if RCS file is omitted;
  99.  * 2. added getting the file status of RCS and working files;
  100.  * 3. added ignoring of directories.
  101.  * 
  102.  * Revision 3.7  83/05/11  15:01:58  wft
  103.  * Added comtable[] which pairs file name suffixes with comment leaders;
  104.  * updated InitAdmin() accordingly.
  105.  * 
  106.  * Revision 3.6  83/04/05  14:47:36  wft
  107.  * fixed Suffix in InitAdmin().
  108.  * 
  109.  * Revision 3.5  83/01/17  18:01:04  wft
  110.  * Added getwd() and rename(); these can be removed by defining
  111.  * V4_2BSD, since they are not needed in 4.2 bsd.
  112.  * Changed sys/param.h to sys/types.h.
  113.  *
  114.  * Revision 3.4  82/12/08  21:55:20  wft
  115.  * removed unused variable.
  116.  *
  117.  * Revision 3.3  82/11/28  20:31:37  wft
  118.  * Changed mktempfile() to store the generated file names.
  119.  * Changed getfullRCSname() to store the file and pathname, and to
  120.  * delete leading "../" and "./".
  121.  *
  122.  * Revision 3.2  82/11/12  14:29:40  wft
  123.  * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(),
  124.  * checksuffix(), checkfullpath(). Semaphore name generation updated.
  125.  * mktempfile() now checks for nil path; freefilename initialized properly.
  126.  * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST.
  127.  * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here.
  128.  *
  129.  * Revision 3.1  82/10/18  14:51:28  wft
  130.  * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h).
  131.  * renamed checkpath() to checkfullpath().
  132.  */
  133.  
  134.  
  135. #include "rcsbase.h"
  136. #ifdef OSK
  137. #    include "time.h"
  138. #    include "stat.h"
  139. #else
  140. #    include <sys/types.h>
  141. #    include <sys/stat.h>
  142. #endif
  143. #ifdef MSDOS
  144. #    include <direct.h>
  145. #else
  146. #    ifdef OSK
  147. #        include <dir.h>
  148. #    else
  149. #        include <sys/dir.h>
  150. #    endif /* OSK */
  151. #endif /* MSDOS */
  152.  
  153. extern char * rindex();
  154. extern char * mktemp();
  155. extern FILE * fopen();
  156. extern char * getwd();         /* get working directory; forward decl       */
  157. extern int    stat(), fstat();
  158.  
  159. extern FILE * finptr;          /* RCS input file descriptor                 */
  160. extern FILE * frewrite;        /* New RCS file descriptor                   */
  161. extern char * RCSfilename, * workfilename; /* filenames                     */
  162. struct stat RCSstat, workstat; /* file status for RCS file and working file */
  163. int    haveRCSstat,  haveworkstat; /* indicators if status availalble       */
  164.  
  165.  
  166. char tempfilename [NCPFN+10];  /* used for derived file names               */
  167. char sub1filename [NCPPN];     /* used for files path/file.sfx,v            */
  168. char sub2filename [NCPPN];     /* used for files path/RCS/file.sfx,v        */
  169. char semafilename [NCPPN];     /* name of semaphore file                    */
  170. int  madesema;                 /* indicates whether a semaphore file has been set */
  171. char * tfnames[10];            /* temp. file names to be unlinked when finished   */
  172. int  freefilename;             /* index of next free file name in tfnames[]  */
  173.  
  174.  
  175. struct compair {
  176.         char * suffix, * comlead;
  177. };
  178.  
  179. struct compair comtable[] = {
  180. /* comtable pairs each filename suffix with a comment leader. The comment   */
  181. /* leader is placed before each line generated by the $Log keyword. This    */
  182. /* table is used to guess the proper comment leader from the working file's */
  183. /* suffix during initial ci (see InitAdmin()). Comment leaders are needed   */
  184. /* for languages without multiline comments; for others they are optional.  */
  185. /* According to your MSDOS-environment, you change these settlements. !!    */
  186. /* If you can work on UN*X, it is worthwile to keep these.            */
  187. /* It ,however, may casue lack of memory on MSDOS                */ 
  188. /* $Author: hiro $                                    */
  189.         "c",   " * ",   /* C           */
  190. #ifndef MSDOS
  191.         "csh", "# ",    /* shell       */
  192.         "e",   "# ",    /* efl         */
  193.         "f",   "c ",    /* fortran     */
  194. #endif /* NOT MSDOS */
  195.         "h",   " * ",   /* C-header    */
  196. #ifndef MSDOS
  197.         "l",   " * ",   /* lex         NOTE: conflict between lex and franzlisp*/
  198.         "mac", "; ",    /* macro       vms or dec-20 or pdp-11 macro */
  199.         "me",  ".\\\" ",/* me-macros   t/nroff*/
  200.         "mm",  ".\\\" ",/* mm-macros   t/nroff*/
  201. #endif /* NOT MSODS */
  202. #if defined(MSDOS) || defined(OSK)
  203.         "fin",  ".\\\" ",/* for *.fin files on MSDOS */
  204.         "fma",  ".\\\" ",/* for fma-macors fin on MSDOS */    
  205. #endif /* MSDOS || OSK */
  206. #ifndef MSDOS
  207.         "p",   " * ",   /* pascal      */
  208.         "pl",  "% ",    /* prolog      */
  209.         "r",   "# ",    /* ratfor      */
  210.         "red", "% ",    /* psl/rlisp   */
  211. #endif /* MSDOS */
  212. #ifdef sparc
  213.         "s",   "! ",    /* assembler   */
  214. #endif
  215. #ifdef mc68000
  216.         "s",   "| ",    /* assembler   */
  217. #endif
  218. #ifdef pdp11
  219.         "s",   "/ ",    /* assembler   */
  220. #endif
  221. #ifdef vax
  222.         "s",   "# ",    /* assembler   */
  223. #endif
  224. #ifdef MSDOS 
  225.         "asm",   "; ",  /* assembler    */
  226. #endif /* MSDOS */
  227. #ifdef OSK
  228.         "a",    "* ",    /* assembler    */
  229. #endif
  230. #ifdef MSDOS
  231.         "bat",  "REM ",    /* FOR COMMAND.COM  */
  232. #else
  233.         "sh",  "# ",    /* shell       */
  234. #endif /* MSDOS */
  235. #ifndef MSDOS
  236.         "sl",  "% ",    /* psl         */
  237.         "red", "% ",    /* psl/rlisp   */
  238.         "cl",  ";;; ",  /* common lisp   */
  239.         "ml",  "; ",    /* mocklisp    */
  240.         "el",  "; ",    /* gnulisp     */
  241. #endif /* NOT MSDOS */
  242.     "tex", "% ",    /* tex           */
  243.         "y",   " * ",   /* yacc        */
  244. #ifndef MSDOS
  245.         "ye",  " * ",   /* yacc-efl    */
  246.         "yr",  " * ",   /* yacc-ratfor */
  247. #endif /* NOT MSDOS */
  248.         "",    "# ",    /* default for empty suffix */
  249.         nil,   ""       /* default for unknown suffix; must always be last */
  250. };
  251.  
  252.  
  253. ffclose(fptr)
  254. FILE * fptr;
  255. /* Function: checks ferror(fptr) and aborts the program if there were
  256.  * errors; otherwise closes fptr.
  257.  */
  258. {       if (ferror(fptr) || fclose(fptr)==EOF)
  259.                 faterror("File read or write error; file system full?");
  260. }
  261.  
  262.  
  263. int trysema(RCSname,makesema)
  264. char * RCSname; int makesema;
  265. /* Function: Checks whether a semaphore file exists for RCSname. If yes,
  266.  * returns false. If not, creates one if makesema==true and returns true
  267.  * if successful. If a semaphore file was created, madesema is set to true.
  268.  * The name of the semaphore file is put into variable semafilename.
  269.  */
  270. {
  271. #ifndef MSDOS
  272.         register char * tp, *sp, *lp;
  273.         int fdesc;
  274.  
  275.         sp=RCSname;
  276.         lp = rindex(sp,'/');
  277.         if (lp==0) {
  278.                 semafilename[0]='.'; semafilename[1]='/';
  279.                 tp= &semafilename[2];
  280.         } else {
  281.                 /* copy path */
  282.                 tp=semafilename;
  283.                 do *tp++ = *sp++; while (sp<=lp);
  284.         }
  285.         /*now insert `,' and append file name */
  286. #ifdef OSK
  287.         *tp++ = '.';
  288. #else
  289.         *tp++ = ',';
  290. #endif
  291.         lp = rindex(sp, RCSSEP);
  292.         while (sp<lp) *tp++ = *sp++;
  293. #ifdef OSK
  294.         *tp++ = '.';
  295. #else
  296.         *tp++ = ',';
  297. #endif
  298.         *tp++ = '\0'; /* will be the same length as RCSname*/
  299.  
  300.         madesema = false;
  301.         if (access(semafilename, 0) == 0) {
  302.                 error("RCS file %s is in use",RCSname);
  303.                 return false;
  304.         }
  305.         if (makesema) {
  306.                 if ((fdesc=creat(semafilename, 000)) == -1) {
  307.                      error("Can't create semaphore file %s for RCS file %s",semafilename,RCSname);
  308.                      return false;
  309.                 } else
  310.                      VOID close(fdesc);
  311.                      madesema=true;
  312.         }
  313.         return true;
  314. #else /* NOT MSDOS */
  315.     makesema = true;
  316.     return true;
  317. #endif /* NOT MSDOS */
  318. }
  319.  
  320.  
  321. rmsema()
  322. /* Function: delete the semaphore file if madeseam==true;
  323.  * sets madesema to false.
  324.  */
  325. {
  326. #ifdef MSDOS
  327.     madesema = false ;
  328. #else
  329.         if (madesema) {
  330.                 madesema=false;
  331.                 if (unlink(semafilename) == -1) {
  332.                         error("Can't find semaphore file %s",semafilename);
  333.                 }
  334.         }
  335. #endif /* MSDOS */
  336. }
  337.  
  338. InitCleanup()
  339. {       freefilename =  0;  /* initialize pointer */
  340. }
  341.  
  342.  
  343. cleanup()
  344. /* Function: closes input file and rewrite file.
  345.  * Unlinks files in tfnames[], deletes semaphore file.
  346.  */
  347. {
  348.         register int i , t;
  349.  
  350.         if (finptr!=NULL)   VOID fclose(finptr);
  351.         if (frewrite!=NULL) VOID fclose(frewrite);
  352.         for (i=0; i<freefilename; i++)
  353.             if (tfnames[i][0]!='\0') VOID unlink(tfnames[i]);
  354.         InitCleanup();
  355.         rmsema();
  356. }
  357.  
  358.  
  359. char * mktempfile(fullpath,filename)
  360. register char * fullpath, * filename;
  361. /* Function: Creates a unique filename using the process id and stores it
  362.  * into a free slot in tfnames. The filename consists of the path contained
  363.  * in fullpath concatenated with filename. filename should end in "XXXXXX".
  364.  * Because of storage in tfnames, cleanup() can unlink the file later.
  365.  * freefilename indicates the lowest unoccupied slot in tfnames.
  366.  * Returns a pointer to the filename created.
  367.  * Example use: mktempfile("/tmp/", somefilename)
  368.  */
  369. {
  370.         register char * lastslash, *tp;
  371.  
  372.         if ((tp=tfnames[freefilename])==nil)
  373.             tp=tfnames[freefilename] = talloc(NCPPN);
  374.  
  375. #ifdef MSDOS
  376.         if (fullpath!=nil && (lastslash=rindex(fullpath,'\\'))!=0) {
  377. #else
  378.         if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) {
  379. #endif /* MSDOS */
  380.                 /* copy path */
  381.                 while (fullpath<=lastslash) *tp++ = *fullpath++;
  382.         }
  383.         while (*tp++ = *filename++);
  384.  
  385.         return (mktemp(tfnames[freefilename++]));
  386. }
  387.  
  388.  
  389.  
  390.  
  391. char * bindex(sp,c)
  392. register char * sp, c;
  393. /* Function: Finds the last occurrence of character c in string sp
  394.  * and returns a pointer to the character just beyond it. If the
  395.  * character doesn't occur in the string, sp is returned.
  396.  */
  397. {       register char * r;
  398.         r = sp;
  399.         while (*sp) {
  400.                 if (*sp++ == c) r=sp;
  401.         }
  402.         return r;
  403. }
  404.  
  405.  
  406.  
  407.  
  408.  
  409. InitAdmin()
  410. /* function: initializes an admin node */
  411. {       register char * Suffix;
  412.         register int i;
  413.  
  414.         Head=Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil;
  415.         StrictLocks=STRICT_LOCKING;
  416.  
  417.         /* guess the comment leader from the suffix*/
  418.         Suffix=bindex(workfilename, '.');
  419. #ifdef MSDOS
  420.     Suffix = strlwr( Suffix );
  421. #endif /* MSDOS */
  422.         if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/
  423.         for (i=0;;i++) {
  424.                 if (comtable[i].suffix==nil) {
  425.                         Comment=comtable[i].comlead; /*default*/
  426.                         break;
  427.                 } elsif (strcmp(Suffix,comtable[i].suffix)==0) {
  428.                         Comment=comtable[i].comlead; /*default*/
  429.                         break;
  430.                 }
  431.         }
  432.         Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/
  433. }
  434.  
  435.  
  436.  
  437. char * findpairfile(argc, argv, fname)
  438. int argc; char * argv[], *fname;
  439. /* Function: Given a filename fname, findpairfile scans argv for a pathname
  440.  * ending in fname. If found, returns a pointer to the pathname, and sets
  441.  * the corresponding pointer in argv to nil. Otherwise returns fname.
  442.  * argc indicates the number of entries in argv. Some of them may be nil.
  443.  */
  444. {
  445.         register char * * next, * match;
  446.         register int count;
  447.  
  448.         for (next = argv, count = argc; count>0; next++,count--) {
  449. #ifdef MSDOS
  450.                 if ((*next != nil) && strcmp(bindex(*next,'\\'),fname)==0) {
  451. #else
  452.                 if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) {
  453. #endif /* MSDOS */
  454.                         /* bindex finds the beginning of the file name stem */
  455.                         match= *next;
  456.                         *next=nil;
  457.                         return match;
  458.                 }
  459.         }
  460.         return fname;
  461. }
  462.  
  463.  
  464. int pairfilenames(argc, argv, mustread, tostdout)
  465. int argc; char ** argv; int mustread, tostdout;
  466. /* Function: Pairs the filenames pointed to by argv; argc indicates
  467.  * how many there are.
  468.  * Places a pointer to the RCS filename into RCSfilename,
  469.  * and a pointer to the name of the working file into workfilename.
  470.  * If both the workfilename and the RCS filename are given, and tostdout
  471.  * is true, a warning is printed.
  472.  *
  473.  * If the working file exists, places its status into workstat and
  474.  * sets haveworkstat to 0; otherwise, haveworkstat is set to -1;
  475.  * Similarly for the RCS file and the variables RCSstat and haveRCSstat.
  476.  *
  477.  * If the RCS file exists, it is opened for reading, the file pointer
  478.  * is placed into finptr, and the admin-node is read in; returns 1.
  479.  * If the RCS file does not exist and mustread==true, an error is printed
  480.  * and 0 returned.
  481.  * If the RCS file does not exist and mustread==false, the admin node
  482.  * is initialized to empty (Head, AccessList, Locks, Symbols, StrictLocks, Dbranch)
  483.  * and -1 returned.
  484.  *
  485.  * 0 is returned on all errors. Files that are directories are errors.
  486.  * Also calls InitCleanup();
  487.  */
  488. {
  489.         register char * sp, * tp;
  490.         char * lastsep, * purefname, * pureRCSname;
  491.         int opened, returncode;
  492. #ifdef MSDOS
  493.     struct stat dirstat;
  494. #endif /* MSDOS */
  495.         char * RCS1;
  496.     char prefdir[NCPPN];
  497.  
  498.  
  499.         if (*argv == nil) return 0; /* already paired filename */
  500.     if (rindex(*argv,KDELIM)!=0) {
  501.         /* KDELIM causes havoc in keyword expansion    */
  502.         error("RCS file name may not contain %c",KDELIM);
  503.         return 0;
  504.     }
  505.         InitCleanup();
  506.  
  507.         /* first check suffix to see whether it is an RCS file or not */
  508. #ifdef MSDOS
  509.         purefname=bindex(*argv, '\\'); /* skip path */
  510. #else
  511.         purefname=bindex(*argv, '/'); /* skip path */
  512. #endif /* MSDOS */
  513. #ifdef MSDOS
  514.     if( ( pureRCSname = strstr( *argv, "RCS\\" ) ) != NULL){
  515.                 /* RCS file name given*/
  516.         RCS1 = (*argv);
  517.                 /* derive workfilename*/
  518.         sp = purefname; tp=tempfilename;
  519.         while( *sp != '\0' ) *tp++=*sp++; *tp= '\0';
  520.                 workfilename=findpairfile(argc-1,argv+1,tempfilename);
  521.         if( strlen(pureRCSname) > NCPFN + 4 ) {
  522.             /* To avoid, ambiguous file name. eg."RCS\RCS\foo.c" */
  523.             if( strlen(pureRCSname + 4) != NULL ){
  524.                 error("file name %s is ambiguous", RCS1);
  525.                 return 0;
  526.             }
  527.             error("RCS file name %s too long",RCS1);
  528.             return 0;
  529.         }
  530.     } else {
  531.                 /* working file given; now try to find RCS file */
  532.         workfilename=*argv;
  533.         /* derive RCS file name*/
  534.         strcpy( tempfilename, "RCS\\" );
  535.         strcat( tempfilename, purefname );
  536.                 RCS1=findpairfile(argc-1,argv+1,tempfilename);
  537.         pureRCSname = strstr( RCS1, "RCS\\" );
  538.                 if (strlen(pureRCSname)>NCPFN+4) {
  539.                         error("working file name %s too long",workfilename);
  540.                         return 0;
  541.                 }
  542.         }
  543.     if( strchr( workfilename, '\\' ) != NULL ){
  544.         error("Sorry, file name %s confuse RCS", workfilename );
  545.         return 0;
  546.     }
  547. #else /* MSDOS */
  548.         lastsep=rindex(purefname, RCSSEP);
  549.         if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') {
  550.                 /* RCS file name given*/
  551.                 RCS1=(*argv); pureRCSname=purefname;
  552.                 /* derive workfilename*/
  553.                 sp = purefname; tp=tempfilename;
  554.                 while (sp<lastsep) *tp++ = *sp++; *tp='\0';
  555.                 /* try to find workfile name among arguments */
  556.                 workfilename=findpairfile(argc-1,argv+1,tempfilename);
  557.                 if (strlen(pureRCSname)>NCPFN) {
  558.                         error("RCS file name %s too long",RCS1);
  559.                         return 0;
  560.                 }
  561.         } else {
  562.                 /* working file given; now try to find RCS file */
  563.                 workfilename= *argv;
  564.                 /* derive RCS file name*/
  565.                 sp=purefname; tp=tempfilename;
  566.                 while (*tp++ = *sp++);
  567.                 *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp++='\0';
  568.                 /* Try to find RCS file name among arguments*/
  569.                 RCS1=findpairfile(argc-1,argv+1,tempfilename);
  570.                 pureRCSname=bindex(RCS1, '/');
  571.                 if (strlen(pureRCSname)>NCPFN) {
  572.                         error("working file name %s too long",workfilename);
  573.                         return 0;
  574.                 }
  575.         }
  576. #endif /* MSDOS */
  577.         /* now we have a (tentative) RCS filename in RCS1 and workfilename  */
  578. #if 1
  579.         /* First, get status of workfilename */
  580.         haveworkstat=stat(workfilename, &workstat);
  581. #ifdef OSK
  582. #ifdef _OS9000
  583.         if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR ) == S_IFDIR)) {
  584. #else
  585.         if ((haveworkstat==0) && ((workstat.st_mode & 0x80 ) == 0x80)) {
  586. #endif
  587. #else
  588.         if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR ) == S_IFDIR)) {
  589. #endif
  590.                 diagnose("Directory %s ignored",workfilename);
  591.                 return 0;
  592.         }
  593.         /* Second, try to find the right RCS file */
  594. #endif
  595. #ifdef MSDOS
  596.     RCSfilename=pureRCSname;
  597.     if (pureRCSname != RCS1){
  598.         error("Sorry, file name %s confuse RCS", RCS1);
  599.         return 0;
  600.     }else{
  601.         opened = ( ( finptr=fopen(pureRCSname, "r" ) ) != NULL );
  602.         if(opened){
  603.             returncode = 1;
  604.         }else{
  605.                         if (mustread) {
  606.                 error("Can't find %s",RCSfilename);
  607.                                 return 0;
  608.             }else{
  609.                 if( stat("RCS", &dirstat) == -1 ){
  610.                     error("Can't find RCS subdirectory");
  611.                     return 0;
  612.                 }else{
  613. #ifdef OSK
  614. #ifdef _OS9000
  615.                     if( !( dirstat.st_mode & S_IFDIR ) ){
  616. #else
  617.                     if( !( dirstat.st_mode & 0x80 ) ){
  618. #endif
  619. #else
  620.                     if( !( dirstat.st_mode & S_IFDIR ) ){
  621. #endif
  622.                         error("RCS is really directory?");
  623.                         return 0;
  624.                     }else returncode = -1;
  625.                 }
  626.             }
  627.         }
  628.     }
  629. #else /* MSDOS */    
  630.         if (pureRCSname!=RCS1) {
  631.                 /* a path for RCSfile is given; single RCS file to look for */
  632.                 finptr=fopen(RCSfilename=RCS1, "r");
  633.                 if (finptr!=NULL) {
  634. #    if 0
  635.                     Lexinit(); getadmin();
  636. #    endif
  637.                     returncode=1;
  638.                 } else { /* could not open */
  639.                     if (access(RCSfilename,0)==0) {
  640.                         error("Can't open existing %s", RCSfilename);
  641.                         return 0;
  642.                     }
  643.                     if (mustread) {
  644.                         error("Can't find %s", RCSfilename);
  645.                         return 0;
  646.                     } else {
  647.                         /* initialize if not mustread */
  648.                         InitAdmin();
  649.                         returncode = -1;
  650.                     }
  651.                 }
  652.         } else {
  653. #if 1 /* addred "RCSDIR" file access */
  654.             /* build second RCS file name by prefixing it with RCSDIR*/
  655.             /* then try to open one of them */
  656.  
  657.             opened = locateRCSfile(RCS1);
  658.  
  659.             if (opened == 1) {
  660.                 /* open succeeded */
  661. #    if 0
  662.                 Lexinit(); getadmin();
  663. #    endif
  664.                 returncode=1;
  665.             } else {
  666.                 /* open failed; may be read protected */
  667.                 if (opened == -1) {
  668.                      error("Can't open existing %s",RCSfilename);
  669.                      return 0;
  670.                 }
  671.                 if (mustread) {
  672.                      error("Can't find an RCS file for %s anywhere!", RCS1);
  673.                      return 0;
  674.                 } else {
  675.                      /* initialize new file. Put into ./RCS if possible, strip off suffix*/
  676.                     makeRCSfilename(RCS1);
  677.                     InitAdmin();
  678.                     returncode= -1;
  679.                 }
  680.             }
  681.        }
  682. #else
  683.         /* no path for RCS file name. Prefix it with path of work */
  684.         /* file if RCS file omitted. Make a second name including */
  685.         /* RCSDIR and try to open that one first.                 */
  686.         sub1filename[0]=sub2filename[0]= '\0';
  687.         if (RCS1==tempfilename) {
  688.             /* RCS file name not given; prepend work path */
  689.             sp= *argv; tp= sub1filename;
  690.             while (sp<purefname) *tp++ = *sp ++;
  691.             *tp='\0';
  692.             VOID strcpy(sub2filename,sub1filename); /* second one */
  693.         }
  694.         VOID strcat(sub1filename,RCSDIR);
  695.         VOID strcpy(prefdir,sub1filename); /* preferred directory for RCS file*/
  696.         VOID strcat(sub1filename,RCS1); VOID strcat(sub2filename,RCS1);
  697.  
  698.                 opened=(
  699.         ((finptr=fopen(RCSfilename=sub1filename, "r"))!=NULL) ||
  700.         ((finptr=fopen(RCSfilename=sub2filename,"r"))!=NULL) );
  701.  
  702.                 if (opened) {
  703.                         /* open succeeded */
  704.                         returncode=1;
  705.                 } else {
  706.                         /* open failed; may be read protected */
  707.             if ((access(RCSfilename=sub1filename,0)==0) ||
  708.                 (access(RCSfilename=sub2filename,0)==0)) {
  709.                                 error("Can't open existing %s",RCSfilename);
  710.                                 return 0;
  711.                         }
  712.                         if (mustread) {
  713.                 error("Can't find %s nor %s",sub1filename,sub2filename);
  714.                                 return 0;
  715.                         } else {
  716.                                 /* initialize new file. Put into ./RCS if possible, strip off suffix*/
  717.                 RCSfilename= (access(prefdir,0)==0)?sub1filename:sub2filename;
  718.                                 returncode= -1;
  719.                         }
  720.                 }
  721.         }
  722. #endif /* MSDOS */
  723.         if (returncode == 1) { /* RCS file open */
  724.                 haveRCSstat=fstat(fileno(finptr),&RCSstat);
  725. #ifdef OSK
  726. #ifdef _OS9000
  727.                 if ((haveRCSstat==0) && ((RCSstat.st_mode & S_IFDIR ) == S_IFDIR)) {
  728. #else
  729.                 if ((haveRCSstat== 0) && ((RCSstat.st_mode & 0x80) == 0x80)) {
  730. #endif
  731. #else
  732.                 if ((haveRCSstat== 0) && ((RCSstat.st_mode & S_IFDIR) == S_IFDIR)) {
  733. #endif
  734.                         diagnose("Directory %s ignored",RCSfilename);
  735.                         return 0;
  736.                 }
  737.                 Lexinit(); getadmin();
  738.         } else {  /* returncode == -1; RCS file nonexisting */
  739.                 haveRCSstat = -1;
  740.                 InitAdmin();
  741.         }
  742. #endif
  743.  
  744.         if (tostdout&&
  745.             !(RCS1==tempfilename||workfilename==tempfilename))
  746.                 /*The last term determines whether a pair of        */
  747.                 /* file names was given in the argument list        */
  748.                 warn("Option -p is set; ignoring output file %s",workfilename);
  749.  
  750.         return returncode;
  751. }
  752.  
  753.  
  754. char * getfullRCSname()
  755. /* Function: returns a pointer to the full path name of the RCS file.
  756.  * Calls getwd(), but only once.
  757.  * removes leading "../" and "./".
  758.  */
  759. {       static char pathbuf[NCPPN];
  760.         static char namebuf[NCPPN];
  761.         static int  pathlength;
  762.  
  763.         register char * realname, * lastpathchar;
  764.         register int  dotdotcounter, realpathlength;
  765.  
  766. #ifdef MSDOS    
  767.     /* Treat a full path name containing the drive name */
  768.     /* Added by $Author: hiro $ */
  769.         if (RCSfilename[1] == ':' && RCSfilename[2] == '\\') {
  770. #else
  771.         if (*RCSfilename=='/') {
  772. #endif /* MSDOS */
  773.                 return(RCSfilename);
  774.         } else {
  775.                 if (pathlength==0) { /*call curdir for the first time*/
  776.                     if (getwd(pathbuf)==NULL)
  777.                         faterror("Can't build current directory path");
  778.                     pathlength=strlen(pathbuf);
  779. #ifdef MSDOS    
  780.         /* Generally, a MSDOS path name seems to be like "A:\" */
  781.         /* Added by $Author: hiro $ */
  782.                     if (!((pathlength==3) && (pathbuf[2]=='\\'))) {
  783.                         pathbuf[pathlength++]='\\';
  784.                         /* Check needed because some getwd implementations */
  785.                         /* generate "/" for the root.                      */
  786.                     }
  787. #else
  788.                     if (!((pathlength==1) && (pathbuf[0]=='/'))) {
  789.                         pathbuf[pathlength++]='/';
  790.                         /* Check needed because some getwd implementations */
  791.                         /* generate "/" for the root.                      */
  792.                     }
  793. #endif /* MSDOS */
  794.                 }
  795.                 /*the following must be redone since RCSfilename may change*/
  796.                 /* find how many ../ to remvove from RCSfilename */
  797.                 dotdotcounter =0;
  798.                 realname = RCSfilename;
  799. #ifdef MSDOS    /* Chaged '/' to '\\' : By $Author: hiro $ */
  800.                 while( realname[0]=='.' &&
  801.                       (realname[1]=='\\'||(realname[1]=='.'&&realname[2]=='\\'))){
  802.                         if (realname[1]=='\\') {
  803.                             /* drop leading ./ */
  804.                             realname += 2;
  805.                         } else {
  806.                             /* drop leading ../ and remember */
  807.                             dotdotcounter++;
  808.                             realname += 3;
  809.                         }
  810.                 }
  811. #else
  812.                 while( realname[0]=='.' &&
  813.                       (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){
  814.                         if (realname[1]=='/') {
  815.                             /* drop leading ./ */
  816.                             realname += 2;
  817.                         } else {
  818.                             /* drop leading ../ and remember */
  819.                             dotdotcounter++;
  820.                             realname += 3;
  821.                         }
  822.                 }
  823. #endif /* MSDOS */
  824.                 /* now remove dotdotcounter trailing directories from pathbuf*/
  825.                 lastpathchar=pathbuf + pathlength-1;
  826.                 while (dotdotcounter>0 && lastpathchar>pathbuf) {
  827.                     /* move pointer backwards over trailing directory */
  828.                     lastpathchar--;
  829. #ifdef MSDOS
  830.                     if (*lastpathchar=='\\') {
  831. #else
  832.                     if (*lastpathchar=='/') {
  833. #endif /* MSDOS */
  834.                         dotdotcounter--;
  835.                     }
  836.                 }
  837.                 if (dotdotcounter>0) {
  838.                     error("Can't generate full path name for RCS file");
  839.                     return RCSfilename;
  840.                 } else {
  841.                     /* build full path name */
  842.                     realpathlength=lastpathchar-pathbuf+1;
  843.                     VOID strncpy(namebuf,pathbuf,realpathlength);
  844.                     VOID strcpy(&namebuf[realpathlength],realname);
  845.                     return(namebuf);
  846.                 }
  847.         }
  848. }
  849.  
  850. /* In MSDOS and (perhaps) OS/2, any directries are writable.     */
  851. /* So, the below check is NON-SENSE !! : $Author: hiro $         */
  852. int trydiraccess(filename)
  853. char * filename;
  854. /* checks write permission in directory of filename and returns
  855.  * true if writable, false otherwise
  856.  */
  857. {
  858.         char pathname[NCPPN];
  859.         register char * tp, *sp, *lp;
  860.  
  861. #ifdef MSDOS
  862.     return true;
  863. #else
  864.         lp = rindex(filename,'/');
  865.         if (lp==0) {
  866.                 /* check current directory */
  867. #ifdef OSK
  868.                 if (access(".",S_IFDIR|S_IWRITE)==0)
  869. #else
  870.                 if (access(".",2)==0)
  871. #endif
  872.                         return true;
  873.                 else {
  874.                         error("Current directory not writable");
  875.                         return false;
  876.                 }
  877.         }
  878.         /* copy path */
  879.         sp=filename;
  880.         tp=pathname;
  881. #ifdef OSK
  882.         do *tp++ = *sp++; while (sp<lp);
  883. #else
  884.         do *tp++ = *sp++; while (sp<=lp);
  885. #endif
  886.         *tp='\0';
  887. #ifdef OSK
  888.         if (access(pathname,S_IFDIR|S_IWRITE)==0)
  889. #else
  890.         if (access(pathname,2)==0)
  891. #endif
  892.                 return true;
  893.         else {
  894.                 error("Directory %s not writable", pathname);
  895.                 return false;
  896.         }
  897. #endif /* MSDOS */
  898. }
  899.  
  900.  
  901.  
  902. #ifndef V4_2BSD
  903. /* rename() and getwd() will be provided in bsd 4.2 */
  904.  
  905. #ifndef MSDOS
  906. #    ifdef OSK
  907. extern char *pwd();
  908. char *getwd( name )
  909. char *name;
  910. {
  911.     return ( pwd( name ) );
  912. }
  913.  
  914. #    else
  915. int rename(from, to)
  916. char * from, *to;
  917. /* Function: renames a file with the name given by from to the name given by to.
  918.  * unlinks the to-file if it already exists. returns -1 on error, 0 otherwise.
  919.  */
  920. {       VOID unlink(to);      /* no need to check return code; will be caught by link*/
  921.                          /* no harm done if file "to" does not exist            */
  922.         if (link(from,to)<0) return -1;
  923.         return(unlink(from));
  924. }
  925.  
  926. #define dot     "."
  927. #define dotdot  ".."
  928.  
  929.  
  930. char * getwd(name)
  931. char * name;
  932. /* Function: places full pathname of current working directory into name and
  933.  * returns name on success, NULL on failure.
  934.  * getwd is an adaptation of pwd. May not return to the current directory on
  935.  * failure.
  936.  */
  937. {
  938.         FILE    *file;
  939.         struct  stat    d, dd;
  940.         char buf[2];    /* to NUL-terminate dir.d_name */
  941.         struct  direct  dir;
  942.  
  943.         int rdev, rino;
  944.         int off;
  945.         register i,j;
  946.  
  947.         name[off= 0] = '/';
  948.         name[1] = '\0';
  949.         buf[0] = '\0';
  950.         if (stat("/", &d)<0) return NULL;
  951.         rdev = d.st_dev;
  952.         rino = d.st_ino;
  953.         for (;;) {
  954.                 if (stat(dot, &d)<0) return NULL;
  955.                 if (d.st_ino==rino && d.st_dev==rdev) {
  956.                         if (name[off] == '/') name[off] = '\0';
  957.                         chdir(name); /*change back to current directory*/
  958.                         return name;
  959.                 }
  960.                 if ((file = fopen(dotdot,"r")) == NULL) return NULL;
  961.                 if (fstat(fileno(file), &dd)<0) goto fail;
  962.                 chdir(dotdot);
  963.                 if(d.st_dev == dd.st_dev) {
  964.                         if(d.st_ino == dd.st_ino) {
  965.                             if (name[off] == '/') name[off] = '\0';
  966.                             chdir(name); /*change back to current directory*/
  967.                             VOID fclose(file);
  968.                             return name;
  969.                         }
  970.                         do {
  971.                             if (fread((char *)&dir, sizeof(dir), 1, file) !=1)
  972.                                 goto fail;
  973.                         } while (dir.d_ino != d.st_ino);
  974.                 }
  975.                 else do {
  976.                         if(fread((char *)&dir, sizeof(dir), 1, file) != 1) {
  977.                             goto fail;
  978.                         }
  979.                         if (dir.d_ino == 0)
  980.                 dd.st_ino = d.st_ino + 1;
  981.                         else if (stat(dir.d_name, &dd) < 0)
  982.                 goto fail;
  983.                 } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
  984.                 VOID fclose(file);
  985.  
  986.                 /* concatenate file name */
  987.                 i = -1;
  988.                 while (dir.d_name[++i] != 0);
  989.                 for(j=off+1; j>0; --j)
  990.                         name[j+i+1] = name[j];
  991.                 off=i+off+1;
  992.                 name[i+1] = '/';
  993.                 for(--i; i>=0; --i)
  994.                         name[i+1] = dir.d_name[i];
  995.         } /* end for */
  996.  
  997. fail:   VOID fclose(file);
  998.         return NULL;
  999. }
  1000. #endif    /* OSK */
  1001. #else /* MSDOS */
  1002.  
  1003. char *getwd(name)
  1004. char    *name;
  1005. {
  1006.     (void)getcwd(name, NCPPN);
  1007.     return name;
  1008. }
  1009. #endif /* MSODS */
  1010. #endif
  1011.  
  1012. #ifdef MSDOS
  1013. char *gettmpdir()
  1014. {
  1015.     char tp[NCPPN];
  1016.     
  1017.     strcpy( tp, getenv("TMP") );
  1018.     if( *tp == NULL ) strcpy( tp, "." );
  1019.     if( tp[strlen(tp) - 1] != '\\' )
  1020.         strcat( tp, "\\" );
  1021.     return tp;
  1022. }
  1023. #endif /* MSDOS */
  1024.  
  1025. #ifdef OSK
  1026. char *gettmpdir()
  1027. {
  1028.     static char tp[NCPPN];
  1029.     char *p , *getenv();
  1030.  
  1031.     p=getenv("TMP");
  1032.     if ( p == NULL )
  1033.              strcpy( tp , "." );
  1034.         else strcpy(tp,p);
  1035.     strcat( tp , "/" );
  1036.     return tp;
  1037. }
  1038. #endif
  1039.  
  1040. #ifdef PAIRTEST
  1041. /* test program for pairfilenames() and getfullRCSname() */
  1042. char * workfilename, *RCSfilename;
  1043. extern int quietflag;
  1044.  
  1045. main(argc, argv)
  1046. int argc; char *argv[];
  1047. {
  1048.         int result;
  1049.         int initflag,tostdout;
  1050.         quietflag=tostdout=initflag=false;
  1051.         cmdid="pair";
  1052.  
  1053.         while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) {
  1054.                 switch ((*argv)[1]) {
  1055.  
  1056.                 case 'p':       tostdout=true;
  1057.                                 break;
  1058.                 case 'i':       initflag=true;
  1059.                                 break;
  1060.                 case 'q':       quietflag=true;
  1061.                                 break;
  1062.                 default:        error("unknown option: %s", *argv);
  1063.                                 break;
  1064.                 }
  1065.         }
  1066.  
  1067.         do {
  1068.                 RCSfilename=workfilename=nil;
  1069.                 result=pairfilenames(argc,argv,!initflag,tostdout);
  1070.                 if (result!=0) {
  1071.                      diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename);
  1072.                      diagnose("Full RCS file name: %s", getfullRCSname());
  1073.                 }
  1074.                 switch (result) {
  1075.                         case 0: continue; /* already paired file */
  1076.  
  1077.                         case 1: if (initflag) {
  1078.                                     error("RCS file %s exists already",RCSfilename);
  1079.                                 } else {
  1080.                                     diagnose("RCS file %s exists",RCSfilename);
  1081.                                 }
  1082.                                 VOID fclose(finptr);
  1083.                                 break;
  1084.  
  1085.                         case -1:diagnose("RCS file does not exist");
  1086.                                 break;
  1087.                 }
  1088.  
  1089.         } while (++argv, --argc>=1);
  1090.  
  1091. }
  1092. #endif
  1093.  
  1094.