📄 rcsfnms.c
字号:
do { if ((xl = suffixlen(x))) { if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) return p; } else { dl = dirlen(name); if ( rcsdirlen < dl && !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) && (!dl || isSLASH(*--p)) ) return nz; } x += xl; } while (*x++); return 0;} /*ARGSUSED*/ RILE *rcsreadopen(RCSname, status, mustread) struct buf *RCSname; struct stat *status; int mustread;/* Open RCSNAME for reading and yield its FILE* descriptor. * If successful, set *STATUS to its status. * Pass this routine to pairfilenames() for read-only access to the file. */{ return Iopen(RCSname->string, FOPEN_R, status);} static intfinopen(rcsopen, mustread) /* jlf RILE *(*rcsopen)P((struct buf*,struct stat*,int)); */ RILE *(*rcsopen)(); int mustread;/* * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. * Set finptr to the result and yield true if successful. * RCSb holds the file's name. * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. * Yield true if successful or if an unusual failure. */{ int interesting, preferold; /* * We prefer an old name to that of a nonexisting new RCS file, * unless we tried locking the old name and failed. */ preferold = RCSbuf.string[0] && (mustread||frewrite); finptr = (*rcsopen)(&RCSb, &RCSstat, mustread); interesting = finptr || errno!=ENOENT; if (interesting || !preferold) { /* Use the new name. */ RCSerrno = errno; bufscpy(&RCSbuf, RCSb.string); } return interesting;} static intfin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread) char const *d, *base, *x; size_t dlen, baselen, xlen; /* jlf RILE *(*rcsopen)P((struct buf*,struct stat*,int)); */ RILE *(*rcsopen)(); int mustread;/* * D is a directory name with length DLEN (including trailing slash). * BASE is a filename with length BASELEN. * X is an RCS filename suffix with length XLEN. * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. * Yield true if successful. * Try dRCS/basex first; if that fails and x is nonempty, try dbasex. * Put these potential names in RCSb. * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. * Yield true if successful or if an unusual failure. */{ register char *p; bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1); /* Try dRCS/basex. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, rcsdir, rcsdirlen); p += rcsdirlen; *p++ = SLASH; VOID memcpy(p, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; if (xlen) { if (finopen(rcsopen, mustread)) return true; /* Try dbasex. */ /* Start from scratch, because finopen() may have changed RCSb. */ VOID memcpy(p = RCSb.string, d, dlen); VOID memcpy(p += dlen, base, baselen); VOID memcpy(p += baselen, x, xlen); p[xlen] = 0; } return finopen(rcsopen, mustread);} intpairfilenames(argc, argv, rcsopen, mustread, quiet) int argc; char **argv; /* jlf RILE *(*rcsopen)P((struct buf*,struct stat*,int)); */ RILE *(*rcsopen)(); int mustread, quiet;/* Function: Pairs the filenames pointed to by argv; argc indicates * how many there are. * Places a pointer to the RCS filename into RCSfilename, * and a pointer to the name of the working file into workfilename. * If both the workfilename and the RCS filename are given, and workstdout * is set, a warning is printed. * * If the RCS file exists, places its status into RCSstat. * * If the RCS file exists, it is RCSOPENed for reading, the file pointer * is placed into finptr, and the admin-node is read in; returns 1. * If the RCS file does not exist and MUSTREAD, * print an error unless QUIET and return 0. * Otherwise, initialize the admin node and return -1. * * 0 is returned on all errors, e.g. files that are not regular files. */{ static struct buf tempbuf; register char *p, *arg, *RCS1; char const *purefname, *pureRCSname, *x; int paired; size_t arglen, dlen, baselen, xlen; if (!(arg = *argv)) return 0; /* already paired filename */ if (*arg == '-') { error("%s option is ignored after file names", arg); return 0; } purefname = basename(arg); /* Allocate buffer temporary to hold the default paired file name. */ p = arg; for (;;) { switch (*p++) { /* Beware characters that cause havoc with ci -k. */ case KDELIM: error("RCS file name `%s' contains %c", arg, KDELIM); return 0; case ' ': case '\n': case '\t': error("RCS file name `%s' contains white space", arg); return 0; default: continue; case 0: break; } break; } paired = false; /* first check suffix to see whether it is an RCS file or not */ if ((x = rcssuffix(arg))) { /* RCS file name given*/ RCS1 = arg; pureRCSname = purefname; baselen = x - purefname; if ( 1 < argc && !rcssuffix(workfilename = p = argv[1]) && baselen <= (arglen = strlen(p)) && ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) && memcmp(purefname, p, baselen) == 0 ) { argv[1] = 0; paired = true; } else { bufscpy(&tempbuf, purefname); workfilename = p = tempbuf.string; p[baselen] = 0; } } else { /* working file given; now try to find RCS file */ workfilename = arg; baselen = p - purefname - 1; /* derive RCS file name*/ if ( 1 < argc && (x = rcssuffix(RCS1 = argv[1])) && baselen <= x - RCS1 && ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) && memcmp(purefname, pureRCSname, baselen) == 0 ) { argv[1] = 0; paired = true; } else pureRCSname = RCS1 = 0; } /* now we have a (tentative) RCS filename in RCS1 and workfilename */ /* Second, try to find the right RCS file */ if (pureRCSname!=RCS1) { /* a path for RCSfile is given; single RCS file to look for */ bufscpy(&RCSbuf, RCS1); finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread); RCSerrno = errno; } else { bufscpy(&RCSbuf, ""); if (RCS1) /* RCS file name was given without path. */ VOID fin2open(arg, (size_t)0, pureRCSname, baselen, x, strlen(x), rcsopen, mustread ); else { /* No RCS file name was given. */ /* Try each suffix in turn. */ dlen = purefname-arg; x = suffixes; while (! fin2open(arg, dlen, purefname, baselen, x, xlen=suffixlen(x), rcsopen, mustread )) { x += xlen; if (!*x++) break; } } } RCSfilename = p = RCSbuf.string; if (finptr) { if (!S_ISREG(RCSstat.st_mode)) { error("%s isn't a regular file -- ignored", p); return 0; } Lexinit(); getadmin(); } else { if (RCSerrno!=ENOENT || mustread || !frewrite) { if (RCSerrno == EEXIST) error("RCS file %s is in use", p); else if (!quiet || RCSerrno!=ENOENT) enerror(RCSerrno, p); return 0; } InitAdmin(); };# if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED if (filenametoolong(p)) { error("RCS file name %s is too long", p); return 0; }# ifndef NAME_MAX /* * Check workfilename too, even though it cannot be longer, * because it may reside on a different filesystem. */ if (filenametoolong(workfilename)) { error("working file name %s is too long", workfilename); return 0; }# endif# endif if (paired && workstdout) warn("Option -p is set; ignoring output file %s",workfilename); prevkeys = false; return finptr ? 1 : -1;} char const *getfullRCSname()/* Function: returns a pointer to the full path name of the RCS file. * Gets the working directory's name at most once. * Removes leading "../" and "./". */{ static char const *wdptr; static struct buf rcsbuf, wdbuf; static size_t pathlength; register char const *realname; register size_t parentdirlength; register unsigned dotdotcounter; register char *d; register char const *wd; if (ROOTPATH(RCSfilename)) { return(RCSfilename); } else { if (!(wd = wdptr)) { /* Get working directory for the first time. */ if (!(d = cgetenv("PWD"))) { bufalloc(&wdbuf, SIZEABLE_PATH + 1);# if !has_getcwd && has_getwd d = getwd(wdbuf.string);# else while ( !(d = getcwd(wdbuf.string, wdbuf.size)) && errno==ERANGE ) bufalloc(&wdbuf, wdbuf.size<<1);# endif if (!d) efaterror("working directory"); } parentdirlength = strlen(d); while (parentdirlength && isSLASH(d[parentdirlength-1])) { d[--parentdirlength] = 0; /* Check needed because some getwd implementations */ /* generate "/" for the root. */ } wdptr = wd = d; pathlength = parentdirlength; } /*the following must be redone since RCSfilename may change*/ /* Find how many `../'s to remove from RCSfilename. */ dotdotcounter =0; realname = RCSfilename; while (realname[0]=='.') { if (isSLASH(realname[1])) { /* drop leading ./ */ realname += 2; } else if (realname[1]=='.' && isSLASH(realname[2])) { /* drop leading ../ and remember */ dotdotcounter++; realname += 3; } else break; } /* Now remove dotdotcounter trailing directories from wd. */ parentdirlength = pathlength; while (dotdotcounter && parentdirlength) { /* move pointer backwards over trailing directory */ if (isSLASH(wd[--parentdirlength])) { dotdotcounter--; } } /* build full path name */ bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2); d = rcsbuf.string; VOID memcpy(d, wd, parentdirlength); d += parentdirlength; *d++ = SLASH; VOID strcpy(d, realname); return rcsbuf.string; }}#ifndef isSLASH intisSLASH(c) int c;{ switch (c) { case SLASHes: return true; default: return false; }}#endif#if !has_getcwd && !has_getwd char *getcwd(path, size) char *path; size_t size;{ static char const usrbinpwd[] = "/usr/bin/pwd";# define binpwd (usrbinpwd+4) register FILE *fp; register int c; register char *p, *lim; int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus; pid_t child;# if !has_waitpid pid_t w;# endif if (!size) { errno = EINVAL; return 0; } if (pipe(fd) != 0) return 0; if (!(child = vfork())) { if ( close(fd[0]) == 0 && (fd[1] == STDOUT_FILENO ||# ifdef F_DUPFD (VOID close(STDOUT_FILENO), fcntl(fd[1], F_DUPFD, STDOUT_FILENO))# else dup2(fd[1], STDOUT_FILENO)# endif == STDOUT_FILENO && close(fd[1]) == 0 ) ) { VOID close(STDERR_FILENO); VOID execl(binpwd, binpwd, (char *)0); VOID execl(usrbinpwd, usrbinpwd, (char *)0); } _exit(EXIT_FAILURE); } e = errno; closeerror = close(fd[1]); closeerrno = errno; fp = 0; readerror = toolong = wstatus = 0; p = path; if (0 <= child) { fp = fdopen(fd[0], "r"); e = errno; if (fp) { lim = p + size; for (p = path; ; *p++ = c) { if ((c=getc(fp)) < 0) { if (feof(fp)) break; if (ferror(fp)) { readerror = 1; e = errno; break; } } if (p == lim) { toolong = 1; break; } } }# if has_waitpid if (waitpid(child, &wstatus, 0) < 0) wstatus = 1;# else do { if ((w = wait(&wstatus)) < 0) { wstatus = 1; break; } } while (w != child);# endif } if (!fp) { VOID close(fd[0]); errno = e; return 0; } if (fclose(fp) != 0) return 0; if (readerror) { errno = e; return 0; } if (closeerror) { errno = closeerrno; return 0; } if (toolong) { errno = ERANGE; return 0; } if (wstatus || p == path || *--p != '\n') { errno = EACCES; return 0; } *p = '\0'; return path;}#endif#ifdef PAIRTEST/* test program for pairfilenames() and getfullRCSname() */char const cmdid[] = "pair";main(argc, argv)int argc; char *argv[];{ int result; int initflag; quietflag = initflag = false; while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { switch ((*argv)[1]) { case 'p': workstdout = stdout; break; case 'i': initflag=true; break; case 'q': quietflag=true; break; default: error("unknown option: %s", *argv); break; } } do { RCSfilename=workfilename=nil; result = pairfilenames(argc,argv,rcsreadopen,!initflag,quietflag); if (result!=0) { diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n", RCSfilename,workfilename,getfullRCSname() ); } switch (result) { case 0: continue; /* already paired file */ case 1: if (initflag) { error("RCS file %s exists already",RCSfilename); } else { diagnose("RCS file %s exists\n",RCSfilename); } Ifclose(finptr); break; case -1:diagnose("RCS file doesn't exist\n"); break; } } while (++argv, --argc>=1);} exiting voidexiterr(){ dirtempunlink(); tempunlink(); _exit(EXIT_FAILURE);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -