home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs57pc3.zip / rcs / src / rcskeep.c < prev    next >
C/C++ Source or Header  |  1995-06-16  |  11KB  |  453 lines

  1. /* Extract RCS keyword string values from working files.  */
  2.  
  3. /* Copyright 1982, 1988, 1989 Walter Tichy
  4.    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
  5.    Distributed under license by the Free Software Foundation, Inc.
  6.  
  7. This file is part of RCS.
  8.  
  9. RCS is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2, or (at your option)
  12. any later version.
  13.  
  14. RCS is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with RCS; see the file COPYING.
  21. If not, write to the Free Software Foundation,
  22. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23.  
  24. Report problems and direct all questions to:
  25.  
  26.     rcs-bugs@cs.purdue.edu
  27.  
  28. */
  29.  
  30. /*
  31.  * $Log: rcskeep.c,v $
  32.  * Revision 5.10  1995/06/16 06:19:24  eggert
  33.  * Update FSF address.
  34.  *
  35.  * Revision 5.9  1995/06/01 16:23:43  eggert
  36.  * (getoldkeys): Don't panic if a Name: is empty.
  37.  *
  38.  * Revision 5.8  1994/03/17 14:05:48  eggert
  39.  * Remove lint.
  40.  *
  41.  * Revision 5.7  1993/11/09 17:40:15  eggert
  42.  * Use simpler timezone parsing strategy now that we're using ISO 8601 format.
  43.  *
  44.  * Revision 5.6  1993/11/03 17:42:27  eggert
  45.  * Scan for Name keyword.  Improve quality of diagnostics.
  46.  *
  47.  * Revision 5.5  1992/07/28  16:12:44  eggert
  48.  * Statement macro names now end in _.
  49.  *
  50.  * Revision 5.4  1991/08/19  03:13:55  eggert
  51.  * Tune.
  52.  *
  53.  * Revision 5.3  1991/04/21  11:58:25  eggert
  54.  * Shorten names to keep them distinct on shortname hosts.
  55.  *
  56.  * Revision 5.2  1990/10/04  06:30:20  eggert
  57.  * Parse time zone offsets; future RCS versions may output them.
  58.  *
  59.  * Revision 5.1  1990/09/20  02:38:56  eggert
  60.  * ci -k now checks dates more thoroughly.
  61.  *
  62.  * Revision 5.0  1990/08/22  08:12:53  eggert
  63.  * Retrieve old log message if there is one.
  64.  * Don't require final newline.
  65.  * Remove compile-time limits; use malloc instead.  Tune.
  66.  * Permit dates past 1999/12/31.  Ansify and Posixate.
  67.  *
  68.  * Revision 4.6  89/05/01  15:12:56  narten
  69.  * changed copyright header to reflect current distribution rules
  70.  * 
  71.  * Revision 4.5  88/08/09  19:13:03  eggert
  72.  * Remove lint and speed up by making FILE *fp local, not global.
  73.  * 
  74.  * Revision 4.4  87/12/18  11:44:21  narten
  75.  * more lint cleanups (Guy Harris)
  76.  * 
  77.  * Revision 4.3  87/10/18  10:35:50  narten
  78.  * Updating version numbers. Changes relative to 1.1 actually relative
  79.  * to 4.1
  80.  * 
  81.  * Revision 1.3  87/09/24  14:00:00  narten
  82.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  83.  * warnings)
  84.  * 
  85.  * Revision 1.2  87/03/27  14:22:29  jenkins
  86.  * Port to suns
  87.  * 
  88.  * Revision 4.1  83/05/10  16:26:44  wft
  89.  * Added new markers Id and RCSfile; extraction added.
  90.  * Marker matching with trymatch().
  91.  * 
  92.  * Revision 3.2  82/12/24  12:08:26  wft
  93.  * added missing #endif.
  94.  *
  95.  * Revision 3.1  82/12/04  13:22:41  wft
  96.  * Initial revision.
  97.  *
  98.  */
  99.  
  100. #include  "rcsbase.h"
  101.  
  102. libId(keepId, "$Id: rcskeep.c,v 5.10 1995/06/16 06:19:24 eggert Exp $")
  103.  
  104. static int badly_terminated P((void));
  105. static int checknum P((char const*));
  106. static int get0val P((int,RILE*,struct buf*,int));
  107. static int getval P((RILE*,struct buf*,int));
  108. static int keepdate P((RILE*));
  109. static int keepid P((int,RILE*,struct buf*));
  110. static int keeprev P((RILE*));
  111.  
  112. int prevkeys;
  113. struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
  114.  
  115.     int
  116. getoldkeys(fp)
  117.     register RILE *fp;
  118. /* Function: Tries to read keyword values for author, date,
  119.  * revision number, and state out of the file fp.
  120.  * If fp is null, workname is opened and closed instead of using fp.
  121.  * The results are placed into
  122.  * prevauthor, prevdate, prevname, prevrev, prevstate.
  123.  * Aborts immediately if it finds an error and returns false.
  124.  * If it returns true, it doesn't mean that any of the
  125.  * values were found; instead, check to see whether the corresponding arrays
  126.  * contain the empty string.
  127.  */
  128. {
  129.     register int c;
  130.     char keyword[keylength+1];
  131.     register char * tp;
  132.     int needs_closing;
  133.     int prevname_found;
  134.  
  135.     if (prevkeys)
  136.     return true;
  137.  
  138.     needs_closing = false;
  139.     if (!fp) {
  140.     if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) {
  141.         eerror(workname);
  142.         return false;
  143.     }
  144.     needs_closing = true;
  145.     }
  146.  
  147.     /* initialize to empty */
  148.     bufscpy(&prevauthor, "");
  149.     bufscpy(&prevdate, "");
  150.     bufscpy(&prevname, "");  prevname_found = 0;
  151.     bufscpy(&prevrev, "");
  152.     bufscpy(&prevstate, "");
  153.  
  154.     c = '\0'; /* anything but KDELIM */
  155.     for (;;) {
  156.         if ( c==KDELIM) {
  157.         do {
  158.         /* try to get keyword */
  159.         tp = keyword;
  160.         for (;;) {
  161.             Igeteof_(fp, c, goto ok;)
  162.             switch (c) {
  163.             default:
  164.                 if (keyword+keylength <= tp)
  165.                 break;
  166.                 *tp++ = c;
  167.                 continue;
  168.  
  169.             case '\n': case KDELIM: case VDELIM:
  170.                 break;
  171.             }
  172.             break;
  173.         }
  174.         } while (c==KDELIM);
  175.             if (c!=VDELIM) continue;
  176.         *tp = c;
  177.         Igeteof_(fp, c, break;)
  178.         switch (c) {
  179.         case ' ': case '\t': break;
  180.         default: continue;
  181.         }
  182.  
  183.         switch (trymatch(keyword)) {
  184.             case Author:
  185.         if (!keepid(0, fp, &prevauthor))
  186.             return false;
  187.         c = 0;
  188.                 break;
  189.             case Date:
  190.         if (!(c = keepdate(fp)))
  191.             return false;
  192.                 break;
  193.             case Header:
  194.             case Id:
  195.         if (!(
  196.               getval(fp, (struct buf*)0, false) &&
  197.               keeprev(fp) &&
  198.               (c = keepdate(fp)) &&
  199.               keepid(c, fp, &prevauthor) &&
  200.               keepid(0, fp, &prevstate)
  201.         ))
  202.             return false;
  203.         /* Skip either ``who'' (new form) or ``Locker: who'' (old).  */
  204.         if (getval(fp, (struct buf*)0, true) &&
  205.             getval(fp, (struct buf*)0, true))
  206.             c = 0;
  207.         else if (nerror)
  208.             return false;
  209.         else
  210.             c = KDELIM;
  211.         break;
  212.             case Locker:
  213.         (void) getval(fp, (struct buf*)0, false);
  214.         c = 0;
  215.         break;
  216.             case Log:
  217.             case RCSfile:
  218.             case Source:
  219.         if (!getval(fp, (struct buf*)0, false))
  220.             return false;
  221.         c = 0;
  222.                 break;
  223.         case Name:
  224.         if (getval(fp, &prevname, false)) {
  225.             if (*prevname.string)
  226.             checkssym(prevname.string);
  227.             prevname_found = 1;
  228.         }
  229.         c = 0;
  230.         break;
  231.             case Revision:
  232.         if (!keeprev(fp))
  233.             return false;
  234.         c = 0;
  235.                 break;
  236.             case State:
  237.         if (!keepid(0, fp, &prevstate))
  238.             return false;
  239.         c = 0;
  240.                 break;
  241.             default:
  242.                continue;
  243.             }
  244.         if (!c)
  245.         Igeteof_(fp, c, c=0;)
  246.         if (c != KDELIM) {
  247.         workerror("closing %c missing on keyword", KDELIM);
  248.         return false;
  249.         }
  250.         if (prevname_found &&
  251.         *prevauthor.string && *prevdate.string &&
  252.         *prevrev.string && *prevstate.string
  253.         )
  254.                 break;
  255.         }
  256.     Igeteof_(fp, c, break;)
  257.     }
  258.  
  259.  ok:
  260.     if (needs_closing)
  261.     Ifclose(fp);
  262.     else
  263.     Irewind(fp);
  264.     prevkeys = true;
  265.     return true;
  266. }
  267.  
  268.     static int
  269. badly_terminated()
  270. {
  271.     workerror("badly terminated keyword value");
  272.     return false;
  273. }
  274.  
  275.     static int
  276. getval(fp, target, optional)
  277.     register RILE *fp;
  278.     struct buf *target;
  279.     int optional;
  280. /* Reads a keyword value from FP into TARGET.
  281.  * Returns true if one is found, false otherwise.
  282.  * Does not modify target if it is 0.
  283.  * Do not report an error if OPTIONAL is set and KDELIM is found instead.
  284.  */
  285. {
  286.     int c;
  287.     Igeteof_(fp, c, return badly_terminated();)
  288.     return get0val(c, fp, target, optional);
  289. }
  290.  
  291.     static int
  292. get0val(c, fp, target, optional)
  293.     register int c;
  294.     register RILE *fp;
  295.     struct buf *target;
  296.     int optional;
  297. /* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
  298.  * Same as getval, except C is the lookahead character.
  299.  */
  300. {   register char * tp;
  301.     char const *tlim;
  302.     register int got1;
  303.  
  304.     if (target) {
  305.     bufalloc(target, 1);
  306.     tp = target->string;
  307.     tlim = tp + target->size;
  308.     } else
  309.     tlim = tp = 0;
  310.     got1 = false;
  311.     for (;;) {
  312.     switch (c) {
  313.         default:
  314.         got1 = true;
  315.         if (tp) {
  316.             *tp++ = c;
  317.             if (tlim <= tp)
  318.             tp = bufenlarge(target, &tlim);
  319.         }
  320.         break;
  321.  
  322.         case ' ':
  323.         case '\t':
  324.         if (tp) {
  325.             *tp = 0;
  326. #            ifdef KEEPTEST
  327.             VOID printf("getval: %s\n", target);
  328. #            endif
  329.         }
  330.         return got1;
  331.  
  332.         case KDELIM:
  333.         if (!got1 && optional)
  334.             return false;
  335.         /* fall into */
  336.         case '\n':
  337.         case 0:
  338.         return badly_terminated();
  339.     }
  340.     Igeteof_(fp, c, return badly_terminated();)
  341.     }
  342. }
  343.  
  344.  
  345.     static int
  346. keepdate(fp)
  347.     RILE *fp;
  348. /* Function: reads a date prevdate; checks format
  349.  * Return 0 on error, lookahead character otherwise.
  350.  */
  351. {
  352.     struct buf prevday, prevtime;
  353.     register int c;
  354.  
  355.     c = 0;
  356.     bufautobegin(&prevday);
  357.     if (getval(fp,&prevday,false)) {
  358.     bufautobegin(&prevtime);
  359.     if (getval(fp,&prevtime,false)) {
  360.         Igeteof_(fp, c, c=0;)
  361.         if (c) {
  362.         register char const *d = prevday.string, *t = prevtime.string;
  363.         bufalloc(&prevdate, strlen(d) + strlen(t) + 9);
  364.         VOID sprintf(prevdate.string, "%s%s %s%s",
  365.             /* Parse dates put out by old versions of RCS.  */
  366.               isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2])
  367.             ? "19" : "",
  368.             d, t,
  369.             strchr(t,'-') || strchr(t,'+')  ?  ""  :  "+0000"
  370.         );
  371.         }
  372.     }
  373.     bufautoend(&prevtime);
  374.     }
  375.     bufautoend(&prevday);
  376.     return c;
  377. }
  378.  
  379.     static int
  380. keepid(c, fp, b)
  381.     int c;
  382.     RILE *fp;
  383.     struct buf *b;
  384. /* Get previous identifier from C+FP into B.  */
  385. {
  386.     if (!c)
  387.         Igeteof_(fp, c, return false;)
  388.     if (!get0val(c, fp, b, false))
  389.         return false;
  390.     checksid(b->string);
  391.     return !nerror;
  392. }
  393.  
  394.     static int
  395. keeprev(fp)
  396.     RILE *fp;
  397. /* Get previous revision from FP into prevrev.  */
  398. {
  399.     return getval(fp,&prevrev,false) && checknum(prevrev.string);
  400. }
  401.  
  402.  
  403.     static int
  404. checknum(s)
  405.     char const *s;
  406. {
  407.     register char const *sp;
  408.     register int dotcount = 0;
  409.     for (sp=s; ; sp++) {
  410.     switch (*sp) {
  411.         case 0:
  412.         if (dotcount & 1)
  413.             return true;
  414.         else
  415.             break;
  416.         
  417.         case '.':
  418.         dotcount++;
  419.         continue;
  420.         
  421.         default:
  422.         if (isdigit(*sp))
  423.             continue;
  424.         break;
  425.     }
  426.     break;
  427.     }
  428.     workerror("%s is not a revision number", s);
  429.     return false;
  430. }
  431.  
  432.  
  433.  
  434. #ifdef KEEPTEST
  435.  
  436. /* Print the keyword values found.  */
  437.  
  438. char const cmdid[] ="keeptest";
  439.  
  440.     int
  441. main(argc, argv)
  442. int  argc; char  *argv[];
  443. {
  444.         while (*(++argv)) {
  445.         workname = *argv;
  446.         getoldkeys((RILE*)0);
  447.                 VOID printf("%s:  revision: %s, date: %s, author: %s, name: %s, state: %s\n",
  448.                 *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string);
  449.     }
  450.     exitmain(EXIT_SUCCESS);
  451. }
  452. #endif
  453.