ident.c revision 9
1/* Copyright (C) 1982, 1988, 1989 Walter Tichy
2   Copyright 1990, 1991 by Paul Eggert
3   Distributed under license by the Free Software Foundation, Inc.
4
5This file is part of RCS.
6
7RCS is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12RCS is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with RCS; see the file COPYING.  If not, write to
19the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
21Report problems and direct all questions to:
22
23    rcs-bugs@cs.purdue.edu
24
25*/
26
27/*
28 *                     RCS identification operation
29 */
30
31/* $Log: ident.c,v $
32 * Revision 5.3  1991/09/10  22:15:46  eggert
33 * Open files with FOPEN_R, not FOPEN_R_WORK,
34 * because they might be executables, not working files.
35 *
36 * Revision 5.2  1991/08/19  03:13:55  eggert
37 * Report read errors immediately.
38 *
39 * Revision 5.1  1991/02/25  07:12:37  eggert
40 * Don't report empty keywords.  Check for I/O errors.
41 *
42 * Revision 5.0  1990/08/22  08:12:37  eggert
43 * Don't limit output to known keywords.
44 * Remove arbitrary limits and lint.  Ansify and Posixate.
45 *
46 * Revision 4.5  89/05/01  15:11:54  narten
47 * changed copyright header to reflect current distribution rules
48 *
49 * Revision 4.4  87/10/23  17:09:57  narten
50 * added exit(0) so exit return code would be non random
51 *
52 * Revision 4.3  87/10/18  10:23:55  narten
53 * Updating version numbers. Changes relative to 1.1 are actually relative
54 * to 4.1
55 *
56 * Revision 1.3  87/07/09  09:20:52  trinkle
57 * Added check to make sure there is at least one arg before comparing argv[1]
58 * with "-q".  This necessary on machines that don't allow dereferncing null
59 * pointers (i.e. Suns).
60 *
61 * Revision 1.2  87/03/27  14:21:47  jenkins
62 * Port to suns
63 *
64 * Revision 4.1  83/05/10  16:31:02  wft
65 * Added option -q and input from reading stdin.
66 * Marker matching is now done with trymatch() (independent of keywords).
67 *
68 * Revision 3.4  83/02/18  17:37:49  wft
69 * removed printing of new line after last file.
70 *
71 * Revision 3.3  82/12/04  12:48:55  wft
72 * Added LOCKER.
73 *
74 * Revision 3.2  82/11/28  18:24:17  wft
75 * removed Suffix; added ungetc to avoid skipping over trailing KDELIM.
76 *
77 * Revision 3.1  82/10/13  15:58:51  wft
78 * fixed type of variables receiving from getc() (char-->int).
79*/
80
81#include  "rcsbase.h"
82
83static int match P((FILE*));
84static void scanfile P((FILE*,char const*,int));
85
86mainProg(identId, "ident", "$Id: ident.c,v 5.3 1991/09/10 22:15:46 eggert Exp $")
87/*  Ident searches the named files for all occurrences
88 *  of the pattern $keyword:...$, where the keywords are
89 *  Author, Date, Header, Id, Log, RCSfile, Revision, Source, and State.
90 */
91
92{
93   FILE *fp;
94   int quiet;
95   int status = EXIT_SUCCESS;
96
97   if ((quiet  =  argc > 1 && strcmp("-q",argv[1])==0)) {
98        argc--; argv++;
99   }
100
101   if (argc<2)
102	scanfile(stdin, (char*)0, quiet);
103
104   while ( --argc > 0 ) {
105      if (!(fp = fopen(*++argv, FOPEN_R))) {
106	 VOID fprintf(stderr,  "%s error: can't open %s\n", cmdid, *argv);
107	 status = EXIT_FAILURE;
108      } else {
109	 scanfile(fp, *argv, quiet);
110	 if (argc>1) VOID putchar('\n');
111      }
112   }
113   if (ferror(stdout) || fclose(stdout)!=0) {
114      VOID fprintf(stderr,  "%s error: write error\n", cmdid);
115      status = EXIT_FAILURE;
116   }
117   exitmain(status);
118}
119
120#if lint
121	exiting void identExit() { _exit(EXIT_FAILURE); }
122#endif
123
124
125	static void
126scanfile(file, name, quiet)
127	register FILE *file;
128	char const *name;
129	int quiet;
130/* Function: scan an open file with descriptor file for keywords.
131 * Return false if there's a read error.
132 */
133{
134   register int c;
135
136   if (name)
137      VOID printf("%s:\n", name);
138   else
139      name = "input";
140   c = 0;
141   for (;;) {
142      if (c < 0) {
143	 if (feof(file))
144	    break;
145	 if (ferror(file))
146	    goto read_error;
147      }
148      if (c == KDELIM) {
149	 if ((c = match(file)))
150	    continue;
151	 quiet = true;
152      }
153      c = getc(file);
154   }
155   if (!quiet)
156      VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name);
157   if (fclose(file) == 0)
158      return;
159
160 read_error:
161   VOID fprintf(stderr, "%s error: %s: read error\n", cmdid, name);
162   exit(EXIT_FAILURE);
163}
164
165
166
167	static int
168match(fp)   /* group substring between two KDELIM's; then do pattern match */
169   register FILE *fp;
170{
171   char line[BUFSIZ];
172   register int c;
173   register char * tp;
174
175   tp = line;
176   while ((c = getc(fp)) != VDELIM) {
177      if (c < 0)
178	 return c;
179      switch (ctab[c]) {
180	 case LETTER: case Letter:
181	    *tp++ = c;
182	    if (tp < line+sizeof(line)-4)
183	       break;
184	    /* fall into */
185	 default:
186	    return c ? c : '\n'/* anything but 0 or KDELIM or EOF */;
187      }
188   }
189   if (tp == line)
190      return c;
191   *tp++ = c;
192   if ((c = getc(fp)) != ' ')
193      return c ? c : '\n';
194   *tp++ = c;
195   while( (c = getc(fp)) != KDELIM ) {
196      if (c < 0  &&  feof(fp) | ferror(fp))
197	    return c;
198      switch (ctab[c]) {
199	 default:
200	    *tp++ = c;
201	    if (tp < line+sizeof(line)-2)
202	       break;
203	    /* fall into */
204	 case NEWLN: case UNKN:
205	    return c ? c : '\n';
206      }
207   }
208   if (tp[-1] != ' ')
209      return c;
210   *tp++ = c;     /*append trailing KDELIM*/
211   *tp   = '\0';
212   VOID fprintf(stdout, "     %c%s\n", KDELIM, line);
213   return 0;
214}
215