page%swap@Sun.COM (Bob Page) (11/19/89)
Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand) Posting-number: Volume 89, Issue 222 Archive-name: unix/rcs.07 # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # rcs/rcs.rcsfiles/partime.c,v # rcs/rcs.rcsfiles/rcs.c,v # This is archive 7 of a 14-part kit. # This archive created: Sun Nov 19 01:12:08 1989 if `test ! -d rcs` then mkdir rcs echo "mkdir rcs" fi if `test ! -d rcs/rcs.rcsfiles` then mkdir rcs/rcs.rcsfiles echo "mkdir rcs/rcs.rcsfiles" fi echo "extracting rcs/rcs.rcsfiles/partime.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/partime.c,v Xhead 1.4; Xbranch 1.4.2; Xaccess ; Xsymbols amiga_rcs:1.4.2 cbmvax_source:1.4.1 uunet_june89_dist:1.4; Xlocks ; strict; Xcomment @ * @; X X X1.4 Xdate 89.05.01.14.48.46; author narten; state Exp; Xbranches 1.4.1.1 1.4.2.1; Xnext ; X X1.4.1.1 Xdate 89.08.11.01.41.57; author rsbx; state Exp; Xbranches ; Xnext ; X X1.4.2.1 Xdate 89.10.13.19.17.41; author rsbx; state Exp; Xbranches ; Xnext 1.4.2.2; X X1.4.2.2 Xdate 89.10.15.15.43.31; author rsbx; state Exp; Xbranches ; Xnext 1.4.2.3; X X1.4.2.3 Xdate 89.10.29.14.47.46; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@Parse date/time string into a TM structure. X@ X X X X1.4 Xlog X@checked in with -k by rsbx at 89.08.10.16.06.05. X@ Xtext X@/* X * PARTIME parse date/time string into a TM structure X * X * Usage: X * #include "time.h" -- expanded tm structure X * char *str; struct tm *tp; X * partime(str,tp); X * Returns: X * 0 if parsing failed X * else time values in specified TM structure (unspecified values X * set to TMNULL) X * Notes: X * This code is quasi-public; it may be used freely in like software. X * It is not to be sold, nor used in licensed software without X * permission of the author. X * For everyone's benefit, please report bugs and improvements! X * Copyright 1980 by Ken Harrenstien, SRI International. X * (ARPANET: KLH @@ SRI) X */ X X/* Hacknotes: X * If parsing changed so that no backup needed, could perhaps modify X * to use a FILE input stream. Need terminator, though. X * Perhaps should return 0 on success, else a non-zero error val? X * Flush AMPM from TM structure and handle locally within PARTIME, X * like midnight/noon? X */ X X#ifndef lint Xstatic char rcsid[]= X"$Header: /usr/src/local/bin/rcs/src/RCS/partime.c,v 1.4 89/05/01 14:48:46 narten Exp $"; X#endif X X/* $Log: partime.c,v $ X * Revision 1.4 89/05/01 14:48:46 narten X * fixed #ifdef DEBUG construct X * X * Revision 1.3 88/11/08 12:02:15 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 1.3 88/08/28 14:53:40 eggert X * Remove unportable "#endif XXX"s. X * X * Revision 1.2 87/03/27 14:21:53 jenkins X * Port to suns X * X * Revision 1.1 84/01/23 14:50:07 kcs X * Initial revision X * X * Revision 1.1 82/05/06 11:38:26 wft X * Initial revision X * X */ X X#include <stdio.h> X#include <ctype.h> X#include "time.h" X X#ifndef lint Xstatic char timeid[] = TIMEID; X#endif X Xstruct tmwent { X char *went; X long wval; /* must be big enough to hold pointer or integer */ X char wflgs; X char wtype; X}; X /* wflgs */ X#define TWSPEC 01 /* Word wants special processing */ X#define TWTIME 02 /* Word is a time value (absence implies date) */ X#define TWDST 04 /* Word is a DST-type timezone */ X#define TW1200 010 /* Word is NOON or MIDNIGHT (sigh) */ X Xint pt12hack(); Xint ptnoise(); Xstruct tmwent tmwords [] = { X {"january", 0, 0, TM_MON}, X {"february", 1, 0, TM_MON}, X {"march", 2, 0, TM_MON}, X {"april", 3, 0, TM_MON}, X {"may", 4, 0, TM_MON}, X {"june", 5, 0, TM_MON}, X {"july", 6, 0, TM_MON}, X {"august", 7, 0, TM_MON}, X {"september", 8, 0, TM_MON}, X {"october", 9, 0, TM_MON}, X {"november", 10, 0, TM_MON}, X {"december", 11, 0, TM_MON}, X X {"sunday", 0, 0, TM_WDAY}, X {"monday", 1, 0, TM_WDAY}, X {"tuesday", 2, 0, TM_WDAY}, X {"wednesday", 3, 0, TM_WDAY}, X {"thursday", 4, 0, TM_WDAY}, X {"friday", 5, 0, TM_WDAY}, X {"saturday", 6, 0, TM_WDAY}, X X {"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */ X {"gst", 0*60, TWTIME, TM_ZON}, X {"gdt", 0*60, TWTIME+TWDST, TM_ZON}, /* ?? */ X X {"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */ X {"est", 5*60, TWTIME, TM_ZON}, /* Eastern */ X {"cst", 6*60, TWTIME, TM_ZON}, /* Central */ X {"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */ X {"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */ X {"yst", 9*60, TWTIME, TM_ZON}, /* Yukon */ X {"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */ X {"bst", 11*60, TWTIME, TM_ZON}, /* Bering */ X X {"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */ X {"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */ X {"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */ X {"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */ X {"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */ X {"ydt", 9*60, TWTIME+TWDST, TM_ZON}, /* Yukon */ X {"hdt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii */ X {"bdt", 11*60, TWTIME+TWDST, TM_ZON}, /* Bering */ X X {"daylight", 1, TWTIME+TWDST, TM_ZON}, /* Local Daylight */ X {"standard", 1, TWTIME, TM_ZON}, /* Local Standard */ X {"std", 1, TWTIME, TM_ZON}, /* " " */ X X {"am", 1, TWTIME, TM_AMPM}, X {"pm", 2, TWTIME, TM_AMPM}, X {"noon", 12,TWTIME+TW1200, 0}, /* Special frobs */ X {"midnight", 0, TWTIME+TW1200, 0}, X {"at", (long)ptnoise, TWSPEC, 0}, /* Noise word */ X X {0, 0, 0, 0}, /* Zero entry to terminate searches */ X}; X X#define TMWILD (-2) /* Value meaning item specified as wild-card */ X /* (May use someday...) */ X Xstruct token { X char *tcp; /* pointer to string */ X int tcnt; /* # chars */ X char tbrk; /* "break" char */ X char tbrkl; /* last break char */ X char tflg; /* 0 = alpha, 1 = numeric */ X union { /* Resulting value; */ X int tnum;/* either a #, or */ X struct tmwent *ttmw;/* ptr to a tmwent. */ X } tval; X}; X Xpartime(astr, atm) Xchar *astr; Xstruct tm *atm; X{ register int *tp; X register struct tmwent *twp; X register int i; X struct token btoken, atoken; X char *cp, ch; X int ord, midnoon; X int (*aproc)(); X X tp = (int *)atm; X zaptime(tp); /* Initialize the TM structure */ X midnoon = TMNULL; /* and our own temp stuff */ X btoken.tcnt = btoken.tbrkl = 0; X btoken.tcp = astr; X Xdomore: X if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken)) /* Get a token */ X { if(btoken.tval.tnum) return(0); /* Read error? */ X if(midnoon != TMNULL) /* EOF, wrap up */ X return(pt12hack(tp, midnoon)); X return(1); /* Win return! */ X } X if(btoken.tflg == 0) /* Alpha? */ X { twp = btoken.tval.ttmw; /* Yes, get ptr to entry */ X if(twp->wflgs&TWSPEC) /* Special alpha crock */ X { aproc = (int (*) ()) (twp->wval); X if(!(*aproc)(tp, twp, &btoken)) X return(0); /* ERR: special word err */ X goto domore; X } X if(twp->wflgs&TW1200) X if(ptstash(&midnoon,(int)twp->wval)) X return(0); /* ERR: noon/midnite clash */ X else goto domore; X if(ptstash(&tp[twp->wtype],(int)twp->wval)) X return(0); /* ERR: val already set */ X if(twp->wtype == TM_ZON) /* If was zone, hack DST */ X if(ptstash(&tp[TM_ISDST],(twp->wflgs&TWDST))) X return(0); /* ERR: DST conflict */ X goto domore; X } X X /* Token is number. Lots of hairy heuristics. */ X if(btoken.tcnt >= 7) /* More than 6 digits in string? */ X return(0); /* ERR: number too big */ X if(btoken.tcnt == 6) /* 6 digits = HHMMSS. Needs special crock */ X { /* since 6 digits are too big for integer! */ X i = (btoken.tcp[0]-'0')*10 /* Gobble 1st 2 digits */ X + btoken.tcp[1]-'0'; X btoken.tcnt = 2; /* re-read last 4 chars */ X goto coltime; X } X X i = btoken.tval.tnum; /* Value now known to be valid; get it. */ X if( btoken.tcnt == 5 /* 5 digits = HMMSS */ X || btoken.tcnt == 3) /* 3 digits = HMM */ X { if(btoken.tcnt != 3) X if(ptstash(&tp[TM_SEC], i%100)) X return(0); /* ERR: sec conflict */ X else i /= 100; Xhhmm4: if(ptstash(&tp[TM_MIN], i%100)) X return(0); /* ERR: min conflict */ X i /= 100; Xhh2: if(ptstash(&tp[TM_HOUR], i)) X return(0); /* ERR: hour conflict */ X goto domore; X } X X if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */ X { if(tp[TM_YEAR] != TMNULL) goto hhmm4; /* Already got yr? */ X if(tp[TM_HOUR] != TMNULL) goto year4; /* Already got hr? */ X if((i%100) > 59) goto year4; /* MM >= 60? */ X if(btoken.tbrk == ':') /* HHMM:SS ? */ X if( ptstash(&tp[TM_HOUR],i/100) X || ptstash(&tp[TM_MIN], i%100)) X return(0); /* ERR: hr/min clash */ X else goto coltm2; /* Go handle SS */ X if(btoken.tbrk != ',' && btoken.tbrk != '/' X && ptitoken(btoken.tcp+btoken.tcnt,&atoken) /* Peek */ X && atoken.tflg == 0 /* alpha */ X && (atoken.tval.ttmw->wflgs&TWTIME)) /* HHMM-ZON */ X goto hhmm4; X if(btoken.tbrkl == '-' /* DD-Mon-YYYY */ X || btoken.tbrkl == ',' /* Mon DD, YYYY */ X || btoken.tbrkl == '/' /* MM/DD/YYYY */ X || btoken.tbrkl == '.' /* DD.MM.YYYY */ X || btoken.tbrk == '-' /* YYYY-MM-DD */ X ) goto year4; X goto hhmm4; /* Give up, assume HHMM. */ X } X X /* From this point on, assume tcnt == 1 or 2 */ X /* 2 digits = YY, MM, DD, or HH (MM and SS caught at coltime) */ X if(btoken.tbrk == ':') /* HH:MM[:SS] */ X goto coltime; /* must be part of time. */ X if(i > 31) goto yy2; /* If >= 32, only YY poss. */ X X /* Check for numerical-format date */ X for (cp = "/-."; ch = *cp++;) X { ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */ X if(btoken.tbrk == ch) /* "NN-" */ X { if(btoken.tbrkl != ch) X { if(ptitoken(btoken.tcp+btoken.tcnt,&atoken) X && atoken.tflg == 0 X && atoken.tval.ttmw->wtype == TM_MON) X goto dd2; X if(ord)goto mm2; else goto dd2; /* "NN-" */ X } /* "-NN-" */ X if(tp[TM_DAY] == TMNULL X && tp[TM_YEAR] != TMNULL) /* If "YY-NN-" */ X goto mm2; /* then always MM */ X if(ord)goto dd2; else goto mm2; X } X if(btoken.tbrkl == ch /* "-NN" */ X && tp[ord ? TM_MON : TM_DAY] != TMNULL) X if(tp[ord ? TM_DAY : TM_MON] == TMNULL) /* MM/DD */ X if(ord)goto dd2; else goto mm2; X else goto yy2; /* "-YY" */ X } X X /* At this point only YY, DD, and HH are left. X * YY is very unlikely since value is <= 32 and there was X * no numerical format date. Make one last try at YY X * before dropping through to DD vs HH code. X */ X if(btoken.tcnt == 2 /* If 2 digits */ X && tp[TM_HOUR] != TMNULL /* and already have hour */ X && tp[TM_DAY] != TMNULL /* and day, but */ X && tp[TM_YEAR] == TMNULL) /* no year, then assume */ X goto yy2; /* that's what we have. */ X X /* Now reduced to choice between HH and DD */ X if(tp[TM_HOUR] != TMNULL) goto dd2; /* Have hour? Assume day. */ X if(tp[TM_DAY] != TMNULL) goto hh2; /* Have day? Assume hour. */ X if(i > 24) goto dd2; /* Impossible HH means DD */ X if(!ptitoken(btoken.tcp+btoken.tcnt, &atoken)) /* Read ahead! */ X if(atoken.tval.tnum) return(0); /* ERR: bad token */ X else goto dd2; /* EOF, assume day. */ X if( atoken.tflg == 0 /* If next token is an alpha */ X && atoken.tval.ttmw->wflgs&TWTIME) /* time-spec, assume hour */ X goto hh2; /* e.g. "3 PM", "11-EDT" */ X Xdd2: if(ptstash(&tp[TM_DAY],i)) /* Store day (1 based) */ X return(0); X goto domore; X Xmm2: if(ptstash(&tp[TM_MON], i-1)) /* Store month (make zero based) */ X return(0); X goto domore; X Xyy2: i += 1900; Xyear4: if(ptstash(&tp[TM_YEAR],i)) /* Store year (full number) */ X return(0); /* ERR: year conflict */ X goto domore; X X /* Hack HH:MM[[:]SS] */ Xcoltime: X if(ptstash(&tp[TM_HOUR],i)) return(0); X if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken)) X return(!btoken.tval.tnum); X if(!btoken.tflg) return(0); /* ERR: HH:<alpha> */ X if(btoken.tcnt == 4) /* MMSS */ X if(ptstash(&tp[TM_MIN],btoken.tval.tnum/100) X || ptstash(&tp[TM_SEC],btoken.tval.tnum%100)) X return(0); X else goto domore; X if(btoken.tcnt != 2 X || ptstash(&tp[TM_MIN],btoken.tval.tnum)) X return(0); /* ERR: MM bad */ X if(btoken.tbrk != ':') goto domore; /* Seconds follow? */ Xcoltm2: if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken)) X return(!btoken.tval.tnum); X if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */ X || ptstash(&tp[TM_SEC], btoken.tval.tnum)) X return(0); /* ERR: SS bad */ X goto domore; X} X X/* Store date/time value, return 0 if successful. X * Fails if entry already set to a different value. X */ Xptstash(adr,val) Xint *adr; X{ register int *a; X if( *(a=adr) != TMNULL) X return(*a != val); X *a = val; X return(0); X} X X/* This subroutine is invoked for NOON or MIDNIGHT when wrapping up X * just prior to returning from partime. X */ Xpt12hack(atp, aval) Xint *atp, aval; X{ register int *tp, i, h; X tp = atp; X if (((i=tp[TM_MIN]) && i != TMNULL) /* Ensure mins, secs */ X || ((i=tp[TM_SEC]) && i != TMNULL)) /* are 0 or unspec'd */ X return(0); /* ERR: MM:SS not 00:00 */ X i = aval; /* Get 0 or 12 (midnite or noon) */ X if ((h = tp[TM_HOUR]) == TMNULL /* If hour unspec'd, win */ X || h == 12) /* or if 12:00 (matches either) */ X tp[TM_HOUR] = i; /* Then set time */ X else if(!(i == 0 /* Nope, but if midnight and */ X &&(h == 0 || h == 24))) /* time matches, can pass. */ X return(0); /* ERR: HH conflicts */ X tp[TM_AMPM] = TMNULL; /* Always reset this value if won */ X return(1); X} X X/* Null routine for no-op tokens */ X Xptnoise() { return(1); } X X/* Get a token and identify it to some degree. X * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise X * hit error of some sort X */ X Xptitoken(astr, tkp) Xregister struct token *tkp; Xchar *astr; X{ X register char *cp; X register int i; X X tkp->tval.tnum = 0; X if(pttoken(astr,tkp) == 0) X#ifdef DEBUG X { X VOID printf("EOF\n"); X return(0); X } X#else X return(0); X#endif X cp = tkp->tcp; X X#ifdef DEBUG X i = cp[tkp->tcnt]; X cp[tkp->tcnt] = 0; X VOID printf("Token: \"%s\" ",cp); X cp[tkp->tcnt] = i; X#endif X X if(tkp->tflg) X for(i = tkp->tcnt; i > 0; i--) X tkp->tval.tnum = (int)tkp->tval.tnum*10 + ((*cp++)-'0'); X else X { i = ptmatchstr(cp, tkp->tcnt, tmwords); X tkp->tval.tnum = i ? i : -1; /* Set -1 for error */ X X#ifdef DEBUG X if(!i) VOID printf("Not found!\n"); X#endif X X if(!i) return(0); X } X X#ifdef DEBUG X if(tkp->tflg) X VOID printf("Val: %d.\n",tkp->tval.tnum); X else VOID printf("Found: \"%s\", val: %d., type %d\n", X tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype); X#endif X X return(1); X} X X/* Read token from input string into token structure */ Xpttoken(astr,tkp) Xregister struct token *tkp; Xchar *astr; X{ X register char *cp; X register int c; X X tkp->tcp = cp = astr; X tkp->tbrkl = tkp->tbrk; /* Set "last break" */ X tkp->tcnt = tkp->tbrk = tkp->tflg = 0; X X while(c = *cp++) X { switch(c) X { case ' ': case '\t': /* Flush all whitespace */ X while((c = *cp++) && isspace(c)); X cp--; /* Drop thru to handle brk */ X case '(': case ')': /* Perhaps any non-alphanum */ X case '-': case ',': /* shd qualify as break? */ X case '/': case ':': case '.': /* Break chars */ X if(tkp->tcnt == 0) /* If no token yet */ X { tkp->tcp = cp; /* ignore the brk */ X tkp->tbrkl = c; X continue; /* and go on. */ X } X tkp->tbrk = c; X return(tkp->tcnt); X } X if(tkp->tcnt == 0) /* If first char of token, */ X tkp->tflg = isdigit(c); /* determine type */ X if(( isdigit(c) && tkp->tflg) /* If not first, make sure */ X ||(!isdigit(c) && !tkp->tflg)) /* char matches type */ X tkp->tcnt++; /* Win, add to token. */ X else { X cp--; /* Wrong type, back up */ X tkp->tbrk = c; X return(tkp->tcnt); X } X } X return(tkp->tcnt); /* When hit EOF */ X} X X Xptmatchstr(astr,cnt,astruc) Xchar *astr; Xint cnt; Xstruct tmwent *astruc; X{ register char *cp, *mp; X register int c; X struct tmwent *lastptr; X struct integ { int word; }; /* For getting at array ptr */ X int i; X X lastptr = 0; X for(;mp = (char *)((struct integ *)astruc)->word; astruc += 1) X { cp = astr; X for(i = cnt; i > 0; i--) X { switch((c = *cp++) ^ *mp++) /* XOR the chars */ X { case 0: continue; /* Exact match */ X case 040: if(isalpha(c)) X continue; X } X break; X } X if(i==0) X if(*mp == 0) return((unsigned int)astruc); /* Exact match */ X else if(lastptr) return(0); /* Ambiguous */ X else lastptr = astruc; /* 1st ambig */ X } X return((unsigned int)lastptr); X} X X X Xzaptime(tp) Xregister int *tp; X/* clears tm structure pointed to by tp */ X{ register int i; X i = (sizeof (struct tm))/(sizeof (int)); X do *tp++ = TMNULL; /* Set entry to "unspecified" */ X while(--i); /* Faster than FOR */ X} X@ X X X1.4.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d31 1 Xa31 5 X<<<<<<< partime.c X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/partime.c,v 1.4.1.1 89/08/11 01:41:57 rsbx Exp Locker: rsbx $"; X======= X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/partime.c,v 1.2 89/09/17 13:34:54 rick Exp $"; X>>>>>>> 1.2 Xa34 11 X<<<<<<< partime.c X * Revision 1.4.1.1 89/08/11 01:41:57 rsbx X * Start of cbmvax RCS source branch. X======= X * Revision 1.2 89/09/17 13:34:54 rick X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com) X * All changes done with conditional compile (#ifdef AMIGA). This version X * compiles correctly with Lattice C version 5.02 or later. X>>>>>>> 1.2 X * X<<<<<<< partime.c Xa35 3 X * checked in with -k by rsbx at 89.08.10.16.06.05. X * X * Revision 1.4 89/05/01 14:48:46 narten Xa43 8 X======= X * Revision 1.3 89/09/16 09:42:36 rick X * Modified AMIGA changes to work with Lattice C X * X * Revision 1.2 88/09/03 15:08:16 rick X * Port to AmigaDos. All done with conditional compiles X * X>>>>>>> 1.2 Xa58 1 X#ifndef AMIGA Xa61 1 X#endif Xd76 1 Xa76 1 Xlong ptnoise(); Xd129 1 Xa129 1 X {"at", 1, 0, 0}, /* Noise word */ Xd152 1 Xa152 2 X{ X register int *tp; Xa332 3 X#ifdef AMIGA Xshort *adr; X#else Xd334 1 Xa334 7 X#endif X{ X#ifdef AMIGA X register short *a; X#else X register int *a; X#endif Xa344 3 X#ifdef AMIGA Xshort *atp, aval; X#else Xd346 1 Xa346 7 X#endif X{ X#ifdef AMIGA X register short *tp, i, h; X#else X register int *tp, i, h; X#endif Xd364 1 Xa364 1 Xlong ptnoise() { return(1); } Xa379 1 X<<<<<<< partime.c Xa382 5 X======= X#ifdef MYDEBUG X VOID printf("EOF\n"); X#endif MYDEBUG X>>>>>>> 1.2 Xd390 1 Xa390 1 X#ifdef MYDEBUG Xa394 1 X<<<<<<< partime.c Xa395 3 X======= X#endif MYDEBUG X>>>>>>> 1.2 Xd404 1 Xa404 1 X#ifdef MYDEBUG Xa405 1 X<<<<<<< partime.c Xa406 3 X======= X#endif MYDEBUG X>>>>>>> 1.2 Xd411 1 Xa411 1 X#ifdef MYDEBUG Xa415 1 X<<<<<<< partime.c Xa416 3 X======= X#endif MYDEBUG X>>>>>>> 1.2 Xa495 3 X#ifdef AMIGA Xregister short *tp; X#else Xa496 1 X#endif Xa498 3 X#ifdef AMIGA X i = (sizeof (struct tm))/(sizeof (short)); X#else Xa499 1 X#endif X@ X X X1.4.2.2 Xlog X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS Xsources I have here (and are later than the ones Rick used). X@ Xtext X@d31 5 Xa35 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/partime.c,v 1.4.2.1 89/10/13 19:17:41 rsbx Exp Locker: rsbx $"; Xd39 1 Xa39 3 X * Revision 1.4.2.1 89/10/13 19:17:41 rsbx X * Start of Amiga RCS port branch. X * Xd42 6 Xd49 1 Xd62 8 Xd427 2 Xa428 1 X#ifdef MYDEBUG Xd431 5 Xd448 1 Xd450 3 Xd463 1 Xd465 3 Xd477 1 Xd479 3 Xd520 1 X@ X X X1.4.2.3 Xlog X@Changed $Header$ to $Id$. X@ Xtext X@d31 1 Xa31 1 X"$Id$"; Xa34 4 X * Revision 1.4.2.2 89/10/15 15:43:31 rsbx X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS X * sources I have here (and are later than the ones Rick used). X * X@ X X X1.4.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@d31 1 Xa31 1 X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/partime.c,v 1.4 89/05/01 14:48:46 narten Exp $"; Xa34 3 X * Revision 1.4 89/05/01 14:48:46 narten X * checked in with -k by rsbx at 89.08.10.16.06.05. X * X@ SHAR_EOF echo "extracting rcs/rcs.rcsfiles/rcs.c,v" sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcs.c,v Xhead 4.11; Xbranch 4.11.2; Xaccess ; Xsymbols amiga_rcs:4.11.2 cbmvax_source:4.11.1 uunet_june89_dist:4.11; Xlocks ; strict; Xcomment @ * @; X X X4.11 Xdate 89.05.01.15.12.06; author narten; state Exp; Xbranches 4.11.1.1 4.11.2.1; Xnext ; X X4.11.1.1 Xdate 89.08.11.01.42.01; author rsbx; state Exp; Xbranches ; Xnext ; X X4.11.2.1 Xdate 89.10.13.19.17.47; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.2; X X4.11.2.2 Xdate 89.10.15.15.43.36; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.3; X X4.11.2.3 Xdate 89.10.16.19.06.13; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.4; X X4.11.2.4 Xdate 89.10.17.13.17.35; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.5; X X4.11.2.5 Xdate 89.10.30.13.38.35; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.6; X X4.11.2.6 Xdate 89.11.01.14.42.32; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.7; X X4.11.2.7 Xdate 89.11.05.23.14.17; author rsbx; state Exp; Xbranches ; Xnext 4.11.2.8; X X4.11.2.8 Xdate 89.11.12.15.07.03; author rsbx; state Exp; Xbranches ; Xnext ; X X Xdesc X@RCS create/change operation. X@ X X X X4.11 Xlog X@checked in with -k by rsbx at 89.08.10.16.06.26. X@ Xtext X@/* X * RCS create/change operation X */ X#ifndef lint Xstatic char rcsid[]= X"$Header: /usr/src/local/bin/rcs/src/RCS/rcs.c,v 4.11 89/05/01 15:12:06 narten Exp $ Purdue CS"; X#endif X/* Copyright (C) 1982, 1988, 1989 Walter Tichy X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by Walter Tichy. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. X * X * Report all problems and direct all questions to: X * rcs-bugs@@cs.purdue.edu X * X X X X X X X X*/ X X X X X/* $Log: rcs.c,v $ X * Revision 4.11 89/05/01 15:12:06 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.10 88/11/08 16:01:54 narten X * didn't install previous patch correctly X * X * Revision 4.9 88/11/08 13:56:01 narten X * removed include <sysexits.h> (not needed) X * minor fix for -A option X * X * Revision 4.8 88/11/08 12:01:58 narten X * changes from eggert@@sm.unisys.com (Paul Eggert) X * X * Revision 4.8 88/08/09 19:12:27 eggert X * Don't access freed storage. X * Use execv(), not system(); yield proper exit status; remove lint. X * X * Revision 4.7 87/12/18 11:37:17 narten X * lint cleanups (Guy Harris) X * X * Revision 4.6 87/10/18 10:28:48 narten X * Updating verison numbers. Changes relative to 1.1 are actually X * relative to 4.3 X * X * Revision 1.4 87/09/24 13:58:52 narten X * Sources now pass through lint (if you ignore printf/sprintf/fprintf X * warnings) X * X * Revision 1.3 87/03/27 14:21:55 jenkins X * Port to suns X * X * Revision 1.2 85/12/17 13:59:09 albitz X * Changed setstate to rcs_setstate because of conflict with random.o. X * X * Revision 1.1 84/01/23 14:50:09 kcs X * Initial revision X * X * Revision 4.3 83/12/15 12:27:33 wft X * rcs -u now breaks most recent lock if it can't find a lock by the caller. X * X * Revision 4.2 83/12/05 10:18:20 wft X * Added conditional compilation for sending mail. X * Alternatives: V4_2BSD, V6, USG, and other. X * X * Revision 4.1 83/05/10 16:43:02 wft X * Simplified breaklock(); added calls to findlock() and getcaller(). X * Added option -b (default branch). Updated -s and -w for -b. X * Removed calls to stat(); now done by pairfilenames(). X * Replaced most catchints() calls with restoreints(). X * Removed check for exit status of delivermail(). X * Directed all interactive output to stderr. X * X * Revision 3.9.1.1 83/12/02 22:08:51 wft X * Added conditional compilation for 4.2 sendmail and 4.1 delivermail. X * X * Revision 3.9 83/02/15 15:38:39 wft X * Added call to fastcopy() to copy remainder of RCS file. X * X * Revision 3.8 83/01/18 17:37:51 wft X * Changed sendmail(): now uses delivermail, and asks whether to break the lock. X * X * Revision 3.7 83/01/15 18:04:25 wft X * Removed putree(); replaced with puttree() in rcssyn.c. X * Combined putdellog() and scanlogtext(); deleted putdellog(). X * Cleaned up diagnostics and error messages. Fixed problem with X * mutilated files in case of deletions in 2 files in a single command. X * Changed marking of selector from 'D' to DELETE. X * X * Revision 3.6 83/01/14 15:37:31 wft X * Added ignoring of interrupts while new RCS file is renamed; X * Avoids deletion of RCS files by interrupts. X * X * Revision 3.5 82/12/10 21:11:39 wft X * Removed unused variables, fixed checking of return code from diff, X * introduced variant COMPAT2 for skipping Suffix on -A files. X * X * Revision 3.4 82/12/04 13:18:20 wft X * Replaced getdelta() with gettree(), changed breaklock to update X * field lockedby, added some diagnostics. X * X * Revision 3.3 82/12/03 17:08:04 wft X * Replaced getlogin() with getpwuid(), flcose() with ffclose(), X * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x). X * fixed -u for missing revno. Disambiguated structure members. X * X * Revision 3.2 82/10/18 21:05:07 wft X * rcs -i now generates a file mode given by the umask minus write permission; X * otherwise, rcs keeps the mode, but removes write permission. X * I added a check for write error, fixed call to getlogin(), replaced X * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed X * conflicting, long identifiers. X * X * Revision 3.1 82/10/13 16:11:07 wft X * fixed type of variables receiving from getc() (char -> int). X */ X X X#include <sys/types.h> X#include <sys/stat.h> X#include "rcsbase.h" X#ifndef lint Xstatic char rcsbaseid[] = RCSBASE; X#endif X Xextern FILE * fopen(); Xextern char * bindex(); Xextern int expandsym(); /* get numeric revision name */ Xextern struct hshentry * getnum(); Xextern struct lock * addlock(); /* add a lock */ Xextern char * getid(); Xextern char Klog[], Khead[], Kaccess[], Kbranch[], Ktext[]; X#ifdef COMPAT2 Xextern char Ksuffix[]; X#endif Xextern char * getcaller(); /* get login of caller */ Xextern struct hshentry * findlock(); /* find and remove lock */ Xextern struct hshentry * genrevs(); Xextern char * checkid(); /* check an identifier */ Xextern char * getfullRCSname(); /* get full path name of RCS file */ Xextern char * mktempfile(); /* temporary file name generator */ Xextern free(); Xextern void catchints(); Xextern void ignoreints(); Xextern int nerror; /* counter for errors */ Xextern int quietflag; /* diagnoses suppressed if true */ Xextern char curlogmsg[]; /* current log message */ Xextern char * resultfile; /* filename for fcopy */ Xextern FILE *fcopy; /* result file during editing */ Xextern FILE * finptr; /* RCS input file */ Xextern FILE * frewrite; /* new RCS file */ Xextern int rewriteflag; /* indicates whether input should be*/ X /* echoed to frewrite */ X Xchar * newRCSfilename, * diffilename, * cutfilename; Xchar * RCSfilename, * workfilename; Xextern struct stat RCSstat, workstat; /* file status of RCS and work file */ Xextern int haveRCSstat, haveworkstat;/* status indicators */ X Xchar accessorlst[strtsize]; XFILE * fcut; /* temporary file to rebuild delta tree */ Xint oldumask; /* save umask */ X Xint initflag, strictlock, strict_selected, textflag; Xchar * textfile, * accessfile; Xchar * caller, numrev[30]; /* caller's login; */ Xstruct access * newaccessor, * rmvaccessor, * rplaccessor; Xstruct access *curaccess, *rmaccess; Xstruct hshentry * gendeltas[hshsize]; X Xstruct Lockrev { X char * revno; X struct Lockrev * nextrev; X}; X Xstruct Symrev { X char * revno; X char * ssymbol; X int override; X struct Symrev * nextsym; X}; X Xstruct Status { X char * revno; X char * status; X struct Status * nextstatus; X}; X Xstruct delrevpair { X char * strt; X char * end; X int code; X}; X Xstruct Lockrev * newlocklst, * rmvlocklst; Xstruct Symrev * assoclst, * lastassoc; Xstruct Status * statelst, * laststate; Xstruct delrevpair * delrev; Xstruct hshentry * cuthead, *cuttail, * delstrt; Xchar branchnum[revlength], * branchsym; Xstruct hshentry branchdummy; Xchar * commsyml; Xchar * headstate; Xint lockhead,unlockcaller,chgheadstate,branchflag,commentflag; Xint delaccessflag; Xenum stringwork {copy, edit, empty}; /* expand and edit_expand not needed */ X X Xmain (argc, argv) Xint argc; Xchar * argv[]; X{ X char *comdusge; X int result; X struct access *removeaccess(), * getaccessor(); X struct Lockrev *rmnewlocklst(); X struct Lockrev *curlock, * rmvlock, *lockpt; X struct Status * curstate; X struct access *temp, *temptr; X int status; X X status = 0; X nerror = 0; X catchints(); X cmdid = "rcs"; X quietflag = false; X comdusge ="command format:\nrcs -i -alogins -Alogins -e[logins] -b[rev] -c[commentleader] -l[rev] -u[rev] -L -U -nname[:rev] -Nname[:rev] -orange -sstate[:rev] -t[textfile] file...."; X rplaccessor = nil; delstrt = nil; X accessfile = textfile = caller = nil; X branchflag = commentflag = chgheadstate = false; X lockhead = false; unlockcaller=false; X initflag= textflag = false; X strict_selected = 0; X X caller=getcaller(); X laststate = statelst = nil; X lastassoc = assoclst = nil; X curlock = rmvlock = newlocklst = rmvlocklst = nil; X curaccess = rmaccess = rmvaccessor = newaccessor = nil; X delaccessflag = false; X X /* preprocessing command options */ X while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) { X switch ((*argv)[1]) { X X case 'i': /* initail version */ X initflag = true; X break; X X case 'b': /* change default branch */ X if (branchflag)warn("Redfinition of option -b"); X branchflag= true; X branchsym = (*argv)+2; X break; X X case 'c': /* change comment symbol */ X if (commentflag)warn("Redefinition of option -c"); X commentflag = true; X commsyml = (*argv)+2; X break; X X case 'a': /* add new accessor */ X if ( (*argv)[2] == '\0') { X error("Login name missing after -a"); X } X if ( (temp = getaccessor((*argv)+1)) ) { X if ( newaccessor ) X curaccess->nextaccess = temp->nextaccess; X else X newaccessor = temp->nextaccess; X temp->nextaccess = nil; X curaccess = temp; X } X break; X X case 'A': /* append access list according to accessfile */ X if ( (*argv)[2] == '\0') { X error("Missing file name after -A"); X break; X } X if ( accessfile) warn("Redefinition of option -A"); X *argv = *argv+2; X if( pairfilenames(1, argv, true, false) > 0) { X releaselst(newaccessor); X newaccessor = curaccess = nil; X releaselst(rmvaccessor); X rmvaccessor = rmaccess = nil; X accessfile = RCSfilename; X } X else X accessfile = nil; X break; X X case 'e': /* remove accessors */ X if ( (*argv)[2] == '\0' ) { X delaccessflag = true; X break; X } X if ( (temp = getaccessor((*argv)+1)) ) { X if ( rmvaccessor ) X rmaccess->nextaccess = temp->nextaccess; X else X rmvaccessor = temp->nextaccess; X temptr = temp->nextaccess; X temp->nextaccess = nil; X rmaccess = temp; X while( temptr ) { X newaccessor = removeaccess(temptr,newaccessor,false); X temptr = temptr->nextaccess; X } X curaccess = temp = newaccessor; X while( temp){ X curaccess = temp; X temp = temp->nextaccess; X } X } X break; X X case 'l': /* lock a revision if it is unlocked */ X if ( (*argv)[2] == '\0'){ /* lock head or def. branch */ X lockhead = true; X break; X } X lockpt = (struct Lockrev *)talloc(sizeof(struct Lockrev)); X lockpt->revno = (*argv)+2; X lockpt->nextrev = nil; X if ( curlock ) X curlock->nextrev = lockpt; X else X newlocklst = lockpt; X curlock = lockpt; X break; X X case 'u': /* release lock of a locked revision */ X if ( (*argv)[2] == '\0'){ /* unlock head */ X unlockcaller=true; X break; X } X lockpt = (struct Lockrev *)talloc(sizeof(struct Lockrev)); X lockpt->revno = (*argv)+2; X lockpt->nextrev = nil; X if (rmvlock) X rmvlock->nextrev = lockpt; X else X rmvlocklst = lockpt; X rmvlock = lockpt; X X curlock = rmnewlocklst(lockpt); X break; X X case 'L': /* set strict locking */ X if (strict_selected++) { /* Already selected L or U? */ X if (!strictlock) /* Already selected -U? */ X warn("Option -L overrides -U"); X } X strictlock = true; X break; X X case 'U': /* release strict locking */ X if (strict_selected++) { /* Already selected L or U? */ X if (strictlock) /* Already selected -L? */ X warn("Option -L overrides -U"); X } X else X strictlock = false; X break; X X case 'n': /* add new association: error, if name exists */ X if ( (*argv)[2] == '\0') { X error("Missing symbolic name after -n"); X break; X } X getassoclst(false, (*argv)+1); X break; X X case 'N': /* add or change association */ X if ( (*argv)[2] == '\0') { X error("Missing symbolic name after -N"); X break; X } X getassoclst(true, (*argv)+1); X break; X X case 'o': /* delete revisins */ X if (delrev) warn("Redefinition of option -o"); X if ( (*argv)[2] == '\0' ) { X error("Missing revision range after -o"); X break; X } X getdelrev( (*argv)+1 ); X break; X X case 's': /* change state attribute of a revision */ X if ( (*argv)[2] == '\0') { X error("State missing after -s"); X break; X } X getstates( (*argv)+1); X break; X X case 't': /* change descriptive text */ X textflag=true; X if ((*argv)[2]!='\0'){ X if (textfile!=nil)warn("Redefinition of -t option"); X textfile = (*argv)+2; X } X break; X X case 'q': X quietflag = true; X break; X default: X faterror("Unknown option: %s\n%s", *argv, comdusge); X }; X } /* end processing of options */ X X if (argc<1) faterror("No input file\n%s", comdusge); X if (nerror) { /* exit, if any error in command options */ X diagnose("%s aborted",cmdid); X exit(1); X } X if (accessfile) /* get replacement for access list */ X getrplaccess(); X if (nerror) { X diagnose("%s aborted",cmdid); X exit(1); X } X X /* now handle all filenames */ X do { X rewriteflag = false; X finptr=frewrite=NULL; X X if ( initflag ) { X switch( pairfilenames(argc, argv, false, false) ) { X case -1: break; /* not exist; ok */ X case 0: continue; /* error */ X case 1: error("file %s exists already", RCSfilename); X VOID fclose(finptr); X continue; X } X } X else { X switch( pairfilenames(argc, argv, true, false) ) { X case -1: continue; /* not exist */ X case 0: continue; /* errors */ X case 1: break; /* file exists; ok*/ X } X } X X X /* now RCSfilename contains the name of the RCS file, and X * workfilename contains the name of the working file. X * if !initflag, finptr contains the file descriptor for the X * RCS file. The admin node is initialized. X */ X X diagnose("RCS file: %s", RCSfilename); X X if (!trydiraccess(RCSfilename)) continue; /* give up */ X if (!initflag && !checkaccesslist(caller)) continue; /* give up */ X if (!trysema(RCSfilename,true)) continue; /* give up */ X X gettree(); /* read in delta tree */ X X /* update admin. node */ X if (strict_selected) StrictLocks = strictlock; X if (commentflag) Comment = commsyml; X X /* update default branch */ X if (branchflag && expandsym(branchsym, branchnum)) { X if (countnumflds(branchnum)>0) { X branchdummy.num=branchnum; X Dbranch = &branchdummy; X } else X Dbranch = nil; X } X X /* update access list */ X if ( delaccessflag ) AccessList = nil; X if ( accessfile ) { X temp = rplaccessor; X while( temp ) { X temptr = temp->nextaccess; X if ( addnewaccess(temp) ) X temp->nextaccess = nil; X temp = temptr; X } X } X temp = rmvaccessor; X while(temp) { /* remove accessors from accesslist */ X AccessList = removeaccess(temp, AccessList,true); X temp = temp->nextaccess; X } X temp = newaccessor; X while( temp) { /* add new accessors */ X temptr = temp->nextaccess; X if ( addnewaccess( temp ) ) X temp->nextaccess = nil; X temp = temptr; X } X X updateassoc(); /* update association list */ X X updatelocks(); /* update locks */ X X /* update state attribution */ X if (chgheadstate) { X /* change state of default branch or head */ X if (Dbranch==nil) { X if (Head==nil) X warn("Can't change states in an empty tree"); X else Head->state = headstate; X } else { X rcs_setstate(Dbranch->num,headstate); /* Can't set directly */ X } X } X curstate = statelst; X while( curstate ) { X rcs_setstate(curstate->revno,curstate->status); X curstate = curstate->nextstatus; X } X X cuthead = cuttail = nil; X if ( delrev && removerevs()) { X /* rebuild delta tree if some deltas are deleted */ X if ( cuttail ) X VOID genrevs(cuttail->num, (char *)nil,(char *)nil, X (char *)nil, gendeltas); X buildtree(); X } X X X /* prepare for rewriting the RCS file */ X newRCSfilename=mktempfile(RCSfilename,NEWRCSFILE); X oldumask = umask(0222); /* turn off write bits */ X if ((frewrite=fopen(newRCSfilename, "w"))==NULL) { X VOID fclose(finptr); X error("Can't open file %s",newRCSfilename); X continue; X } X VOID umask(oldumask); X putadmin(frewrite); X if ( Head ) X puttree(Head, frewrite); X putdesc(initflag,textflag,textfile,quietflag); X rewriteflag = false; X X if ( Head) { X if (!delrev) { X /* no revision deleted */ X fastcopy(finptr,frewrite); X } else { X if ( cuttail ) X buildeltatext(gendeltas); X else X scanlogtext((struct hshentry *)nil,empty); X /* copy rest of delta text nodes that are not deleted */ X } X } X ffclose(frewrite); frewrite = NULL; X if ( ! nerror ) { /* move temporary file to RCS file if no error */ X ignoreints(); /* ignore interrupts */ X if(rename(newRCSfilename,RCSfilename)<0) { X error("Can't create RCS file %s; saved in %s", X RCSfilename, newRCSfilename); X newRCSfilename[0] = '\0'; /* avoid deletion by cleanup */ X restoreints(); X VOID cleanup(); X break; X } X newRCSfilename[0]='\0'; /* avoid re-unlinking by cleanup()*/ X /* update mode */ X result=0; X if (!initflag) /* preserve mode bits */ X result=chmod(RCSfilename,RCSstat.st_mode & ~0222); X elsif (haveworkstat==0) /* initialization, and work file exists */ X result=chmod(RCSfilename,workstat.st_mode & ~0222); X if (result<0) warn("Can't set mode of %s",RCSfilename); X X restoreints(); /* catch them all again */ X diagnose("done"); X } else { X diagnose("%s aborted; %s unchanged.",cmdid,RCSfilename); X status = 1; X nerror = 0; X } X } while (cleanup(), X ++argv, --argc >=1); X X exit(status); X} /* end of main (rcs) */ X X X Xgetassoclst(flag, sp) Xint flag; Xchar * sp; X/* Function: associate a symbolic name to a revision or branch, */ X/* and store in assoclst */ X X{ X struct Symrev * pt; X char * temp, *temp2; X int c; X X while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n') ; X temp = sp; X temp2=checkid(sp, ':'); /* check for invalid symbolic name */ X sp = temp2; c = *sp; *sp = '\0'; X while( c == ' ' || c == '\t' || c == '\n') c = *++sp; X X if ( c != ':' && c != '\0') { X error("Invalid string %s after option -n or -N",sp); X return; X } X X pt = (struct Symrev *)talloc(sizeof(struct Symrev)); X pt->ssymbol = temp; X pt->override = flag; X if (c == '\0') /* delete symbol */ X pt->revno = nil; X else { X while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ; X if ( c == '\0' ) X pt->revno = nil; X else X pt->revno = sp; X } X pt->nextsym = nil; X if (lastassoc) X lastassoc->nextsym = pt; X else X assoclst = pt; X lastassoc = pt; X return; X} X X X Xstruct access * getaccessor( sp) Xchar *sp; X/* Function: get the accessor list of options -e and -a, */ X/* and store in curpt */ X X X{ X struct access * curpt, * pt, *pre; X char *temp; X register c; X X while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ; X if ( c == '\0') { X error("Missing login name after option -a or -e"); X return nil; X } X X curpt = pt = nil; X while( c != '\0') { X temp=checkid(sp,','); X pt = (struct access *)talloc(sizeof(struct access)); X pt->login = sp; X if ( curpt ) X pre->nextaccess = pt; X else X curpt = pt; X pt->nextaccess = curpt; X pre = pt; X sp = temp; c = *sp; *sp = '\0'; X while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp); X } X return pt; X} X X X Xgetstates(sp) Xchar *sp; X/* Function: get one state attribute and the corresponding */ X/* revision and store in statelst */ X X{ X char *temp, *temp2; X struct Status *pt; X register c; X X while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n') ; X temp = sp; X temp2=checkid(sp,':'); /* check for invalid state attribute */ X sp = temp2; c = *sp; *sp = '\0'; X while( c == ' ' || c == '\t' || c == '\n' ) c = *++sp; X X if ( c == '\0' ) { /* change state of def. branch or Head */ X chgheadstate = true; X headstate = temp; X return; X } X else if ( c != ':' ) { X error("Missing ':' after state in option -s"); X return; X } X X while( (c = *++sp) == ' ' || c == '\t' || c == '\n') ; X pt = (struct Status *)talloc(sizeof(struct Status)); X pt->status = temp; X pt->revno = sp; X pt->nextstatus = nil; X if (laststate) X laststate->nextstatus = pt; X else X statelst = pt; X laststate = pt; X} X X X Xgetrplaccess() X/* Function : get the accesslist of the 'accessfile' */ X/* and place in rplaccessor */ X{ X register char *id, *nextp; X struct access *newaccess, *oldaccess; X X if ( (finptr=fopen(accessfile, "r")) == NULL) { X faterror("Can't open file %s", accessfile); X } X Lexinit(); X nextp = &accessorlst[0]; X X if ( ! getkey(Khead)) faterror("Missing head in %s", accessfile); X VOID getnum(); X if ( ! getlex(SEMI) ) serror("Missing ';' after head in %s",accessfile); X X if (getkey(Kbranch)) { /* optional */ X Dbranch=getnum(); X if (!getlex(SEMI)) serror("Missing ';' after branch list"); X } X X X#ifdef COMPAT2 X /* read suffix. Only in release 2 format */ X if (getkey(Ksuffix)) { X if (nexttok==STRING) { X readstring(); nextlex(); /*through away the suffix*/ X } elsif(nexttok==ID) { X nextlex(); X } X if ( ! getlex(SEMI) ) serror("Missing ';' after suffix in %s",accessfile); X } X#endif X X if (! getkey(Kaccess))fatserror("Missing access list in %s",accessfile); X oldaccess = nil; X while( id =getid() ) { X newaccess = (struct access *)talloc(sizeof(struct access)); X newaccess->login = nextp; X newaccess->nextaccess = nil; X while( ( *nextp++ = *id++) != '\0') ; X if ( oldaccess ) X oldaccess->nextaccess = newaccess; X else X rplaccessor = newaccess; X oldaccess = newaccess; X } X if ( ! getlex(SEMI))serror("Missing ';' after access list in %s",accessfile); X return; X} X X X Xgetdelrev(sp) Xchar *sp; X/* Function: get revision range or branch to be deleted, */ X/* and place in delrev */ X{ X int c; X struct delrevpair *pt; X X if (delrev) free((char *)delrev); X X pt = (struct delrevpair *)talloc(sizeof(struct delrevpair)); X while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ; X X if ( c == '<' || c == '-' ) { /* -o -rev or <rev */ X while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t') ; X pt->strt = sp; pt->code = 1; X while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp); X *sp = '\0'; X pt->end = nil; delrev = pt; X return; X } X else { X pt->strt = sp; X while( c != ' ' && c != '\n' && c != '\t' && c != '\0' X && c != '-' && c != '<' ) c = *++sp; X *sp = '\0'; X while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp; X if ( c == '\0' ) { /* -o rev or branch */ X pt->end = nil; pt->code = 0; X delrev = pt; X return; X } X if ( c != '-' && c != '<') { X faterror("Invalid range %s %s after -o", pt->strt, sp); X free((char *)pt); X return; X } X while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ; X if ( c == '\0') { /* -o rev- or rev< */ X pt->end = nil; pt->code = 2; X delrev = pt; X return; X } X } X /* -o rev1-rev2 or rev1<rev2 */ X pt->end = sp; pt->code = 3; delrev = pt; X while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp; X *sp = '\0'; X} X X X X Xscanlogtext(delta,func) Xstruct hshentry * delta; enum stringwork func; X/* Function: Scans delta text nodes up to and including the one given X * by delta, or up to last one present, if delta==nil. X * For the one given by delta (if delta!=nil), the log message is saved into X * curlogmsg and the text is processed according to parameter func. X * Assumes the initial lexeme must be read in first. X * Does not advance nexttok after it is finished, except if delta==nil. X */ X{ struct hshentry * nextdelta; X X do { X rewriteflag = false; X nextlex(); X if (!(nextdelta=getnum())) { X if(delta) X faterror("Can't find delta for revision %s", delta->num); X else return; /* no more delta text nodes */ X } X if ( nextdelta->selector != DELETE) { X rewriteflag = true; X VOID fprintf(frewrite,DELNUMFORM,nextdelta->num,Klog); X } X if (!getkey(Klog) || nexttok!=STRING) X serror("Missing log entry"); X elsif (delta==nextdelta) { X VOID savestring(curlogmsg,logsize); X delta->log=curlogmsg; X } else {readstring(); X if (delta!=nil) delta->log=""; X } X nextlex(); X if (!getkey(Ktext) || nexttok!=STRING) X fatserror("Missing delta text"); X X if(delta==nextdelta) X /* got the one we're looking for */ X switch (func) { X case copy: copystring(); X break; X case edit: editstring((struct hshentry *)nil); X break; X default: faterror("Wrong scanlogtext"); X } X else readstring(); /* skip over it */ X X } while (delta!=nextdelta); X} X X X Xreleaselst(sourcelst) Xstruct access * sourcelst; X/* Function: release the storages whose address are in sourcelst */ X X{ X struct access * pt; X X pt = sourcelst; X while(pt) { X struct access *pn = pt->nextaccess; X free((char *)pt); X pt = pn; X } X} X X X Xstruct Lockrev * rmnewlocklst(which) Xstruct Lockrev * which; X/* Function: remove lock to revision which->revno from newlocklst */ X X{ X struct Lockrev * pt, *pre; X X while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){ X struct Lockrev *pn = newlocklst->nextrev; X free((char *)newlocklst); X newlocklst = pn; X } X X pt = pre = newlocklst; X while( pt ) { X if ( ! strcmp(pt->revno, which->revno) ) { X pre->nextrev = pt->nextrev; X free((char *)pt); X pt = pre->nextrev; X } X else { X pre = pt; X pt = pt->nextrev; X } X } X return pre; X} X X X Xstruct access * removeaccess( who, sourcelst,flag) Xstruct access * who, * sourcelst; Xint flag; X/* Function: remove the accessor-- who from sourcelst */ X X{ X struct access *pt, *pre; X X pt = sourcelst; X while( pt && (! strcmp(who->login, pt->login) )) { X pre = pt->nextaccess; X free((char *)pt); X pt = pre; X flag = false; X } X pre = sourcelst = pt; X while( pt ) { X if ( ! strcmp(who->login, pt->login) ) { X pre->nextaccess = pt->nextaccess; X free((char *)pt); X pt = pre->nextaccess; X flag = false; X } X else { X pre = pt; X pt = pt->nextaccess; X } X } X if ( flag ) warn("Can't remove a nonexisting accessor %s",who->login); X return sourcelst; X} X X X Xint addnewaccess( who ) Xstruct access * who; X/* Function: add new accessor-- who into AccessList */ X X{ X struct access *pt, *pre; X X pre = pt = AccessList; X X while( pt ) { X if ( strcmp( who->login, pt->login) ) { X pre = pt; X pt = pt->nextaccess; X } X else X return 0; X } X if ( pre == pt ) X AccessList = who; X else X pre->nextaccess = who; X return 1; X} X X Xsendmail(Delta, who) Xchar * Delta, *who; X/* Function: mail to who, informing him that his lock on delta was X * broken by caller. Ask first whether to go ahead. Return false on X * error or if user decides not to break the lock. X */ X{ X char * messagefile; X int old1, old2, c, response; X FILE * mailmess; X X X VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who); X VOID fprintf(stderr, "Do you want to break the lock? [ny](n): "); X response=c=getchar(); X while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/ X if (response=='\n'||response=='n'||response=='N') return false; X X /* go ahead with breaking */ X messagefile=mktempfile("/tmp/", "RCSmailXXXXXX"); X if ( (mailmess = fopen(messagefile, "w")) == NULL) { X faterror("Can't open file %s", messagefile); X } X X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/')); X VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname()); X VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller); X VOID fputs("State the reason for breaking the lock:\n", stderr); X VOID fputs("(terminate with ^D or single '.')\n>> ", stderr); X X old1 = '\n'; old2 = ' '; X for (; ;) { X c = getchar(); X if ( c == EOF ) { X VOID putc('\n',stderr); X VOID fprintf(mailmess, "%c\n", old1); X break; X } X else if ( c == '\n' && old1 == '.' && old2 == '\n') X break; X else { X VOID fputc( old1, mailmess); X old2 = old1; old1 = c; X if (c== '\n') VOID fputs(">> ", stderr); X } X } X ffclose(mailmess); X X /* ignore the exit status, even if delivermail unsuccessful */ X VOID run(messagefile,(char*)nil, X#ifdef SENDMAIL X "/usr/lib/sendmail", X#else X# ifdef DELIVERMAIL X "/etc/delivermail","-w", X# else X "/bin/mail", X# endif X#endif X who,(char*)nil); X VOID unlink(messagefile); X return(true); X} X X X Xstatic breaklock(who,delta) Xchar * who; struct hshentry * delta; X/* function: Finds the lock held by who on delta, X * and removes it. X * Sends mail if a lock different from the caller's is broken. X * Prints an error message if there is no such lock or error. X */ X{ X register struct lock * next, * trail; X char * num; X struct lock dummy; X int whor, numr; X X num=delta->num; X dummy.nextlock=next=Locks; X trail = &dummy; X while (next!=nil) { X if (num != nil) X numr = strcmp(num, next->delta->num); X X whor=strcmp(who,next->login); X if (whor==0 && numr==0) break; /* exact match */ X if (numr==0 && whor !=0) { X if (!sendmail( num, next->login)){ X diagnose("%s still locked by %s",num,next->login); X return; X } else break; /* continue after loop */ X } X trail=next; X next=next->nextlock; X } X if (next!=nil) { X /*found one */ X diagnose("%s unlocked",next->delta->num); X trail->nextlock=next->nextlock; X next->delta->lockedby=nil; X Locks=dummy.nextlock; X } else { X error("no lock set on revision %s", num); X } X} X X X Xstruct hshentry *searchcutpt(object, length, store) Xchar * object; Xint length; Xstruct hshentry * * store; X/* Function: Search store and return entry with number being object. */ X/* cuttail = nil, if the entry is Head; otherwise, cuttail */ X/* is the entry point to the one with number being object */ X X{ X while( compartial( (*store++)->num, object, length) ) ; X store--; X X if ( *store == Head) X cuthead = nil; X else X cuthead = *(store -1); X return *store; X} X X X Xint branchpoint(strt, tail) Xstruct hshentry *strt, *tail; X/* Function: check whether the deltas between strt and tail */ X/* are locked or branch point, return 1 if any is */ X/* locked or branch point; otherwise, return 0 and */ X/* mark DELETE on selector */ X X{ X struct hshentry *pt; X struct lock *lockpt; X int flag; X X X pt = strt; X flag = false; X while( pt != tail) { X if ( pt->branches ){ /* a branch point */ X flag = true; X error("Can't remove branch point %s", pt->num); X } X lockpt = Locks; X while(lockpt && lockpt->delta != pt) X lockpt = lockpt->nextlock; X if ( lockpt ) { X flag = true; X error("Can't remove locked revision %s",pt->num); X } X pt = pt->next; X } X X if ( ! flag ) { X pt = strt; X while( pt != tail ) { X pt->selector = DELETE; X diagnose("deleting revision %s ",pt->num); X pt = pt->next; X } X } X return flag; X} X X X Xremoverevs() X/* Function: get the revision range to be removed, and place the */ X/* first revision removed in delstrt, the revision before */ X/* delstrt in cuthead( nil, if delstrt is head), and the */ X/* revision after the last removed revision in cuttail(nil */ X/* if the last is a leaf */ X X{ X struct hshentry *target, *target2, * temp, *searchcutpt(); X int length, flag; X X flag = false; X if ( ! expandsym(delrev->strt, &numrev[0]) ) return 0; X target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas); X if ( ! target ) return 0; X if ( cmpnum(target->num, &numrev[0]) ) flag = true; X length = countnumflds( &numrev[0] ); X X if ( delrev->code == 0 ) { /* -o rev or -o branch */ X if ( length % 2) X temp=searchcutpt(target->num,length+1,gendeltas); X else if (flag) { X error("Revision %s does not exist", &numrev[0]); X return 0; X } X else X temp = searchcutpt(&numrev[0],length,gendeltas); X cuttail = target->next; X if ( branchpoint(temp, cuttail) ) { X cuttail = nil; X return 0; X } X delstrt = temp; /* first revision to be removed */ X return 1; X } X X if ( length % 2 ) { /* invalid branch after -o */ X error("Invalid branch range %s after -o", &numrev[0]); X return 0; X } X X if ( delrev->code == 1 ) { /* -o -rev */ X if ( length > 2 ) { X temp = searchcutpt( target->num, length-1, gendeltas); X cuttail = target->next; X } X else { X temp = searchcutpt(target->num, length, gendeltas); X cuttail = target; X while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) ) X cuttail = cuttail->next; X } X if ( branchpoint(temp, cuttail) ){ X cuttail = nil; X return 0; X } X delstrt = temp; X return 1; X } X X if ( delrev->code == 2 ) { /* -o rev- */ X if ( length == 2 ) { X temp = searchcutpt(target->num, 1,gendeltas); X if ( flag) X cuttail = target; X else X cuttail = target->next; X } X else { X if ( flag){ X cuthead = target; X if ( !(temp = target->next) ) return 0; X } X else X temp = searchcutpt(target->num, length, gendeltas); X getbranchno(temp->num, &numrev[0]); /* get branch number */ X target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas); X } X if ( branchpoint( temp, cuttail ) ) { X cuttail = nil; X return 0; X } X delstrt = temp; X return 1; X } X X /* -o rev1-rev2 */ X if ( ! expandsym(delrev->end, &numrev[0]) ) return 0; X if ( length != countnumflds( &numrev[0] ) ) { X error("Invalid revision range %s-%s", target->num, &numrev[0]); X return 0; X } X if ( length > 2 && compartial( &numrev[0], target->num, length-1) ) { X error("Invalid revision range %s-%s", target->num, &numrev[0]); X return 0; X } X X target2 = genrevs( &numrev[0], (char *)nil, (char *)nil, (char *)nil,gendeltas); X if ( ! target2 ) return 0; X X if ( length > 2) { /* delete revisions on branches */ X if ( cmpnum(target->num, target2->num) > 0) { X if ( cmpnum(target2->num, &numrev[0]) ) X flag = true; X else X flag = false; X temp = target; X target = target2; X target2 = temp; X } X if ( flag ) { X if ( ! cmpnum(target->num, target2->num) ) { X error("Revisions %s-%s don't exist", delrev->strt,delrev->end); X return 0; X } X cuthead = target; X temp = target->next; X } X else X temp = searchcutpt(target->num, length, gendeltas); X cuttail = target2->next; X } X else { /* delete revisions on trunk */ X if ( cmpnum( target->num, target2->num) < 0 ) { X temp = target; X target = target2; X target2 = temp; X } X else X if ( cmpnum(target2->num, &numrev[0]) ) X flag = true; X else X flag = false; X if ( flag ) { X if ( ! cmpnum(target->num, target2->num) ) { X error("Revisions %s-%s don't exist", delrev->strt, delrev->end); X return 0; X } X cuttail = target2; X } X else X cuttail = target2->next; X temp = searchcutpt(target->num, length, gendeltas); X } X if ( branchpoint(temp, cuttail) ) { X cuttail = nil; X return 0; X } X delstrt = temp; X return 1; X} X X X Xupdateassoc() X/* Function: add or delete(if revno is nil) association */ X/* which is stored in assoclst */ X X{ X struct Symrev * curassoc; X struct assoc * pre, * pt; X struct hshentry * target; X X /* add new associations */ X curassoc = assoclst; X while( curassoc ) { X if ( curassoc->revno == nil ) { /* delete symbol */ X pre = pt = Symbols; X while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) { X pre = pt; X pt = pt->nextassoc; X } X if ( pt ) X if ( pre == pt ) X Symbols = pt->nextassoc; X else X pre->nextassoc = pt->nextassoc; X else X warn("Can't delete nonexisting symbol %s",curassoc->ssymbol); X } X else if ( expandsym( curassoc->revno, &numrev[0] ) ) { X /* add symbol */ X target = (struct hshentry *) talloc(sizeof(struct hshentry)); X target->num = &numrev[0]; X VOID addsymbol(target, curassoc->ssymbol, curassoc->override); X } X curassoc = curassoc->nextsym; X } X X} X X X Xupdatelocks() X/* Function: remove lock for caller or first lock if unlockcaller==true; X * remove locks which are stored in rmvlocklst, X * add new locks which are stored in newlocklst, X * add lock for Dbranch or Head if lockhead==true. X */ X{ X struct hshentry *target; X struct Lockrev *lockpt; X X if(unlockcaller == true) { /* find lock for caller */ X if ( Head ) { X if (Locks) { X target=findlock(caller,true); X if (target==nil) { X breaklock(caller, Locks->delta); /* remove most recent lock */ X } else { X diagnose("%s unlocked",target->num); X } X } else { X warn("There are no locks set."); X } X } else { X warn("Can't unlock an empty tree"); X } X } X X /* remove locks which are stored in rmvlocklst */ X lockpt = rmvlocklst; X while( lockpt ) { X if (expandsym(lockpt->revno, numrev)) { X target = genrevs(numrev, (char *)nil, (char *)nil, (char *)nil, gendeltas); X if ( target ) X if ( !(countnumflds(numrev)%2) && cmpnum(target->num,numrev)) X error("Can't unlock nonexisting revision %s",lockpt->revno); X else X breaklock(caller, target); X /* breaklock does its own diagnose */ X } X lockpt = lockpt->nextrev; X } X X /* add new locks which stored in newlocklst */ X lockpt = newlocklst; X while( lockpt ) { X setlock(lockpt->revno,caller); X lockpt = lockpt->nextrev; X } X X if ( lockhead == true) { /* lock default branch or head */ X if (Dbranch) { X setlock(Dbranch->num,caller); X } elsif ( Head) { X if (addlock(Head, caller)) X diagnose("%s locked",Head->num); X } else { X warn("Can't lock an empty tree"); X } X } X X} X X X Xsetlock(rev,who) Xchar * rev, * who; X/* Function: Given a revision or branch number, finds the correponding X * delta and locks it for who. X */ X{ X struct lock *lpt; X struct hshentry *target; X X if (expandsym(rev, &numrev[0]) ){ X target = genrevs(&numrev[0],(char *) nil,(char *) nil, X (char *)nil, gendeltas); X if ( target ) X if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num,&numrev[0])) X error("Can't lock nonexisting revision %s",numrev); X else X if(lpt=addlock(target, who)) X diagnose("%s locked",lpt->delta->num); X } X} X X X Xrcs_setstate(rev,status) Xchar * rev, * status; X/* Function: Given a revision or branch number, finds the corresponding delta X * and sets its state to status. X */ X{ X struct hshentry *target; X X if ( expandsym(rev, &numrev[0]) ) { X target = genrevs(&numrev[0],(char *) nil, (char *)nil, X (char *) nil, gendeltas); X if ( target ) X if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num, &numrev[0]) ) X error("Can't set state of nonexisting revision %s to %s", X numrev,status); X else X target->state = status; X } X} X X X X X Xbuildeltatext(deltas) Xstruct hshentry ** deltas; X/* Function: put the delta text on frewrite and make necessary */ X/* change to delta text */ X{ X int i, c, exit_stats; X X cuttail->selector = DELETE; X initeditfiles("/tmp/"); X scanlogtext(deltas[0], copy); X i = 1; X if ( cuthead ) { X cutfilename=mktempfile("/tmp/", "RCScutXXXXXX"); X if ( (fcut = fopen(cutfilename, "w")) == NULL) { X faterror("Can't open temporary file %s", cutfilename); X } X X while( deltas[i-1] != cuthead ) { X scanlogtext(deltas[i++], edit); X } X X finishedit((struct hshentry *)nil); rewind(fcopy); X while( (c = getc(fcopy)) != EOF) VOID putc(c, fcut); X swapeditfiles(false); X ffclose(fcut); X } X X while( deltas[i-1] != cuttail) X scanlogtext(deltas[i++], edit); X finishedit((struct hshentry *)nil); ffclose(fcopy); X X if ( cuthead ) { X diffilename=mktempfile("/tmp/", "RCSdifXXXXXX"); X exit_stats = run((char*)nil,diffilename, X DIFF,"-n",cutfilename,resultfile,(char*)nil); X if (exit_stats != 0 && exit_stats != (1 << BYTESIZ)) X faterror ("diff failed"); X if(!putdtext(cuttail->num,curlogmsg,diffilename,frewrite)) return; X } X else X if (!putdtext(cuttail->num,curlogmsg,resultfile,frewrite)) return; X X scanlogtext((struct hshentry *)nil,empty); /* read the rest of the deltas */ X} X X X Xbuildtree() X/* Function: actually removes revisions whose selector field */ X/* is DELETE, and rebuilds the linkage of deltas. */ X/* asks for reconfirmation if deleting last revision*/ X{ X int c, response; X X struct hshentry * Delta; X struct branchhead *pt, *pre; X X if ( cuthead ) X if ( cuthead->next == delstrt ) X cuthead->next = cuttail; X else { X pre = pt = cuthead->branches; X while( pt && pt->hsh != delstrt ) { X pre = pt; X pt = pt->nextbranch; X } X if ( cuttail ) X pt->hsh = cuttail; X else if ( pt == pre ) X cuthead->branches = pt->nextbranch; X else X pre->nextbranch = pt->nextbranch; X } X else { X if ( cuttail == nil && !quietflag) { X VOID fprintf(stderr,"Do you really want to delete all revisions ?[ny](n): "); X c = response = getchar(); X while( c != EOF && c != '\n') c = getchar(); X if ( response != 'y' && response != 'Y') { X diagnose("No revision deleted"); X Delta = delstrt; X while( Delta) { X Delta->selector = 'S'; X Delta = Delta->next; X } X return; X } X } X Head = cuttail; X } X return; X} X X@ X X X4.11.2.1 Xlog X@Start of Amiga RCS port branch. X@ Xtext X@d6 1 Xa6 5 X<<<<<<< rcs.c X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/rcs.c,v 4.11.1.1 89/08/11 01:42:01 rsbx Exp Locker: rsbx $ Purdue CS"; X======= X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 1.2 89/09/17 13:35:01 rick Exp $ Purdue CS"; X>>>>>>> 1.2 Xa36 11 X<<<<<<< rcs.c X * Revision 4.11.1.1 89/08/11 01:42:01 rsbx X * Start of cbmvax RCS source branch. X======= X * Revision 1.2 89/09/17 13:35:01 rick X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com) X * All changes done with conditional compile (#ifdef AMIGA). This version X * compiles correctly with Lattice C version 5.02 or later. X>>>>>>> 1.2 X * X<<<<<<< rcs.c Xa37 3 X * checked in with -k by rsbx at 89.08.10.16.06.26. X * X * Revision 4.11 89/05/01 15:12:06 narten Xa53 11 X======= X * Revision 1.4 89/09/16 09:42:43 rick X * Modified AMIGA changes to work with Lattice C X * X * Revision 1.3 89/09/10 09:26:56 rick X * Moved TARGETDIR to rcs: X * X * Revision 1.2 88/09/03 15:08:35 rick X * Port to AmigaDos. All done with conditional compiles X * X>>>>>>> 1.2 Xa133 3 X#ifdef AMIGA X#include "stat.h" X#else Xa135 9 X<<<<<<< rcs.c X======= X#endif X#ifdef BSD X#include <sysexits.h> X#else X#define EX_OK 0 X#endif X>>>>>>> 1.2 Xa578 5 X#ifdef AMIGA X if (finptr != NULL) X fclose(finptr); X unlink(RCSfilename); X#endif Xa590 3 X#ifdef AMIGA X result=chmod(RCSfilename,RCSstat.st_attr | S_IWRITE); X#else Xa591 1 X#endif Xa592 3 X#ifdef AMIGA X result=chmod(RCSfilename,workstat.st_attr | S_IWRITE); X#else Xa593 1 X#endif Xd673 1 Xa673 1 X curpt = pt = pre = nil; Xd1007 1 Xa1007 3 X#ifdef AMIGA X return false; X#else Xa1057 1 X#endif AMIGA Xa1060 1 X<<<<<<< rcs.c Xa1062 3 X======= Xstruct hshentry * breaklock(who,delta) X>>>>>>> 1.2 Xa1485 3 X#ifdef AMIGA X cutfilename=mktempfile("t:", "RCScutXXXXXX"); X#else Xa1486 1 X#endif Xa1505 3 X#ifdef AMIGA X diffilename=mktempfile("t:", "RCSdifXXXXXX"); X#else Xa1506 1 X<<<<<<< rcs.c Xa1508 5 X======= X#endif X VOID sprintf(command, "%s -n %s %s >%s", DIFF,cutfilename, resultfile, diffilename); X exit_stats = system (command); X>>>>>>> 1.2 Xa1549 3 X#ifdef AMIGA X fflush(stderr); X#endif X@ X X X4.11.2.2 Xlog X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS Xsources I have here (and are later than the ones Rick used). X@ Xtext X@d6 5 Xa10 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.1 89/10/13 19:17:47 rsbx Exp Locker: rsbx $ Purdue CS"; Xd41 1 Xa41 3 X * Revision 4.11.2.1 89/10/13 19:17:47 rsbx X * Start of Amiga RCS port branch. X * Xd44 6 Xd51 1 Xd72 11 Xd168 2 Xd176 1 Xa1049 1 X#ifdef AMIGA Xd1061 2 Xa1062 40 X VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who); X VOID fprintf(stderr, "Do you want to break the lock? [ny](n): "); X response=c=getchar(); X while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/ X if (response=='\n'||response=='n'||response=='N') return false; X X /* go ahead with breaking */ X messagefile=mktempfile("/tmp/", "RCSmailXXXXXX"); X if ( (mailmess = fopen(messagefile, "w")) == NULL) { X faterror("Can't open file %s", messagefile); X } X X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/')); X VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname()); X VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller); X VOID fputs("State the reason for breaking the lock:\n", stderr); X VOID fputs("(terminate with ^D or single '.')\n>> ", stderr); X X old1 = '\n'; old2 = ' '; X for (; ;) { X c = getchar(); X if ( c == EOF ) { X VOID putc('\n',stderr); X VOID fprintf(mailmess, "%c\n", old1); X break; X } X else if ( c == '\n' && old1 == '.' && old2 == '\n') X break; X else { X VOID fputc( old1, mailmess); X old2 = old1; old1 = c; X if (c== '\n') VOID fputs(">> ", stderr); X } X } X ffclose(mailmess); X X /* ignore the exit status, even if delivermail unsuccessful */ X VOID run(messagefile,(char*)nil, X#ifdef SENDMAIL X "/usr/lib/sendmail", Xa1063 24 X# ifdef DELIVERMAIL X "/etc/delivermail","-w", X# else X "/bin/mail", X# endif X#endif X who,(char*)nil); X VOID unlink(messagefile); X return(true); X} X X#else X Xsendmail(Delta, who) Xchar * Delta, *who; X/* Function: mail to who, informing him that his lock on delta was X * broken by caller. Ask first whether to go ahead. Return false on X * error or if user decides not to break the lock. X */ X{ X char * messagefile; X int old1, old2, c, response; X FILE * mailmess; X Xd1114 1 Xa1115 1 X#endif AMIGA Xd1118 1 Xd1120 4 Xa1123 1 Xstatic void breaklock(who,delta) Xd1307 1 Xa1307 1 X genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas); Xd1575 1 Xa1575 2 X#endif X/* <<<<<<< rcs.c */ Xd1578 2 Xa1579 1 X/* ======= Xd1582 1 Xa1582 1 X>>>>>>> 1.2 */ X@ X X X4.11.2.3 Xlog X@Changed file path handling to deal with Amiga file path sematics. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.2 89/10/15 15:43:36 rsbx Exp $ Purdue CS"; Xa36 4 X * Revision 4.11.2.2 89/10/15 15:43:36 rsbx X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS X * sources I have here (and are later than the ones Rick used). X * Xd160 1 Xa160 1 Xextern char * fnamepart(); Xd1051 1 Xa1051 1 X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",fnamepart(RCSfilename)); Xd1116 1 Xa1116 1 X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",fnamepart(RCSfilename)); X@ X X X4.11.2.4 Xlog X@Changes to sendmail(). X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.3 89/10/16 19:06:13 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.11.2.3 89/10/16 19:06:13 rsbx X * Changed file path handling to deal with Amiga file path sematics. X * Xd1031 11 Xd1043 54 Xa1103 4 X#ifdef AMIGA X VOID fprintf(stderr, "Breaking of locks not supported by this Amiga RCS revision\n"); X return false; X#else Xd1158 1 Xa1159 1 X} Xd1616 1 Xd1619 4 X@ X X X4.11.2.5 Xlog X@NULL finptr after closing it. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.4 89/10/17 13:17:35 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.11.2.4 89/10/17 13:17:35 rsbx X * Changes to sendmail(). X * Xd606 1 Xa606 1 X fclose(finptr); finptr = NULL; X@ X X X4.11.2.6 Xlog X@Changes to make the delete bit to track the write bit. Made protection Xbit manipulation less insane. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.5 89/10/30 13:38:35 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.11.2.5 89/10/30 13:38:35 rsbx X * NULL finptr after closing it. X * Xd608 3 Xa610 8 X if (finptr != NULL) { X fclose(finptr); finptr = NULL; X if (chmod(RCSfilename, RCSstat.st_attr|S_IDELETE)<0) X warn("Can't adjust mode of %s",RCSfilename); X if (unlink(RCSfilename) != 0) { /* Remove failed */ X error("Can't unlink %s",RCSfilename); X } X } Xd625 1 Xa625 1 X result=chmod(RCSfilename,RCSstat.st_attr & ~(S_IWRITE|S_IDELETE)); Xd631 1 Xa631 1 X result=chmod(RCSfilename,workstat.st_attr & ~(S_IWRITE|S_IDELETE)); Xd1533 1 Xa1533 1 X cutfilename=mktempfile("t:", "RCScutXXXXXXXX"); Xd1535 1 Xa1535 1 X cutfilename=mktempfile("/tmp/", "RCScutXXXXXXXX"); Xd1557 1 Xa1557 1 X diffilename=mktempfile("t:", "RCSdifXXXXXXXX"); Xd1559 1 Xa1559 1 X diffilename=mktempfile("/tmp/", "RCSdifXXXXXXXX"); X@ X X X4.11.2.7 Xlog X@Fixed a "/tmp/" that slipped through. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.6 89/11/01 14:42:32 rsbx Exp $ Purdue CS"; Xa36 4 X * Revision 4.11.2.6 89/11/01 14:42:32 rsbx X * Changes to make the delete bit to track the write bit. Made protection X * bit manipulation less insane. X * Xa1535 3 X#ifdef AMIGA X initeditfiles("t:"); X#else Xa1536 1 X#endif X@ X X X4.11.2.8 Xlog X@WaitChild() on the Amiga returns the completion code from a child process Xwithout shifting it up 8 bits like the Unix wait() does. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.7 89/11/05 23:14:17 rsbx Exp $ Purdue CS"; Xa36 3 X * Revision 4.11.2.7 89/11/05 23:14:17 rsbx X * Fixed a "/tmp/" that slipped through. X * Xa1578 3 X#ifdef AMIGA X if (exit_stats != 0 && exit_stats != 1) X#else Xa1579 1 X#endif X@ X X X4.11.1.1 Xlog X@Start of cbmvax RCS source branch. X@ Xtext X@d6 1 Xa6 1 X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/rcs.c,v 4.11 89/05/01 15:12:06 narten Exp $ Purdue CS"; Xa36 3 X * Revision 4.11 89/05/01 15:12:06 narten X * checked in with -k by rsbx at 89.08.10.16.06.26. X * X@ SHAR_EOF echo "End of archive 7 (of 14)" # if you want to concatenate archives, remove anything after this line exit