ident.c revision 22996
1193323Sed/* Identify RCS keyword strings in files.  */
2224145Sdim
3193323Sed/* Copyright 1982, 1988, 1989 Walter Tichy
4193323Sed   Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5193323Sed   Distributed under license by the Free Software Foundation, Inc.
6193323Sed
7224145SdimThis file is part of RCS.
8193323Sed
9193323SedRCS is free software; you can redistribute it and/or modify
10193323Sedit under the terms of the GNU General Public License as published by
11193323Sedthe Free Software Foundation; either version 2, or (at your option)
12193323Sedany later version.
13193323Sed
14193323SedRCS is distributed in the hope that it will be useful,
15193323Sedbut WITHOUT ANY WARRANTY; without even the implied warranty of
16193323SedMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17193323SedGNU General Public License for more details.
18193323Sed
19193323SedYou should have received a copy of the GNU General Public License
20193323Sedalong with RCS; see the file COPYING.
21193323SedIf not, write to the Free Software Foundation,
22193323Sed59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23193323Sed
24193323SedReport problems and direct all questions to:
25193323Sed
26193323Sed    rcs-bugs@cs.purdue.edu
27193323Sed
28193323Sed*/
29263508Sdim
30234353Sdim/*
31234353Sdim * Revision 5.9  1995/06/16 06:19:24  eggert
32234353Sdim * Update FSF address.
33234353Sdim *
34234353Sdim * Revision 5.8  1995/06/01 16:23:43  eggert
35195340Sed * (exiterr, reportError): New functions, needed for DOS and OS/2 ports.
36243830Sdim * (scanfile): Use them.
37243830Sdim *
38243830Sdim * Revision 5.7  1994/03/20 04:52:58  eggert
39243830Sdim * Remove `exiting' from identExit.
40249423Sdim *
41249423Sdim * Revision 5.6  1993/11/09 17:40:15  eggert
42263508Sdim * Add -V.
43263508Sdim *
44263508Sdim * Revision 5.5  1993/11/03 17:42:27  eggert
45263508Sdim * Test for char == EOF, not char < 0.
46263508Sdim *
47263508Sdim * Revision 5.4  1992/01/24  18:44:19  eggert
48263508Sdim * lint -> RCS_lint
49263508Sdim *
50263508Sdim * Revision 5.3  1991/09/10  22:15:46  eggert
51263508Sdim * Open files with FOPEN_R, not FOPEN_R_WORK,
52263508Sdim * because they might be executables, not working files.
53263508Sdim *
54263508Sdim * Revision 5.2  1991/08/19  03:13:55  eggert
55263508Sdim * Report read errors immediately.
56263508Sdim *
57263508Sdim * Revision 5.1  1991/02/25  07:12:37  eggert
58263508Sdim * Don't report empty keywords.  Check for I/O errors.
59263508Sdim *
60263508Sdim * Revision 5.0  1990/08/22  08:12:37  eggert
61263508Sdim * Don't limit output to known keywords.
62263508Sdim * Remove arbitrary limits and lint.  Ansify and Posixate.
63263508Sdim *
64263508Sdim * Revision 4.5  89/05/01  15:11:54  narten
65193323Sed * changed copyright header to reflect current distribution rules
66263508Sdim *
67263508Sdim * Revision 4.4  87/10/23  17:09:57  narten
68263508Sdim * added exit(0) so exit return code would be non random
69263508Sdim *
70263508Sdim * Revision 4.3  87/10/18  10:23:55  narten
71263508Sdim * Updating version numbers. Changes relative to 1.1 are actually relative
72263508Sdim * to 4.1
73263508Sdim *
74263508Sdim * Revision 1.3  87/07/09  09:20:52  trinkle
75263508Sdim * Added check to make sure there is at least one arg before comparing argv[1]
76263508Sdim * with "-q".  This necessary on machines that don't allow dereferncing null
77263508Sdim * pointers (i.e. Suns).
78198090Srdivacky *
79200581Srdivacky * Revision 1.2  87/03/27  14:21:47  jenkins
80263508Sdim * Port to suns
81263508Sdim *
82263508Sdim * Revision 4.1  83/05/10  16:31:02  wft
83263508Sdim * Added option -q and input from reading stdin.
84198090Srdivacky * Marker matching is now done with trymatch() (independent of keywords).
85198090Srdivacky *
86193323Sed * Revision 3.4  83/02/18  17:37:49  wft
87193323Sed * removed printing of new line after last file.
88198090Srdivacky *
89193323Sed * Revision 3.3  82/12/04  12:48:55  wft
90198090Srdivacky * Added LOCKER.
91198090Srdivacky *
92198090Srdivacky * Revision 3.2  82/11/28  18:24:17  wft
93193323Sed * removed Suffix; added ungetc to avoid skipping over trailing KDELIM.
94193323Sed *
95193323Sed * Revision 3.1  82/10/13  15:58:51  wft
96193323Sed * fixed type of variables receiving from getc() (char-->int).
97193323Sed*/
98193323Sed
99193323Sed#include  "rcsbase.h"
100193323Sed
101static int match P((FILE*));
102static int scanfile P((FILE*,char const*,int));
103static void reportError P((char const*));
104
105mainProg(identId, "ident", "$Id$")
106/*  Ident searches the named files for all occurrences
107 *  of the pattern $@: text $ where @ is a keyword.
108 */
109
110{
111   FILE *fp;
112   int quiet = 0;
113   int status = EXIT_SUCCESS;
114   char const *a;
115
116   while ((a = *++argv)  &&  *a=='-')
117	while (*++a)
118	    switch (*a) {
119		case 'q':
120		    quiet = 1;
121		    break;
122
123		case 'V':
124		    VOID printf("RCS version %s\n", RCS_version_string);
125		    quiet = -1;
126		    break;
127
128		default:
129		    VOID fprintf(stderr,
130			"ident: usage: ident -{qV} [file...]\n"
131		    );
132		    exitmain(EXIT_FAILURE);
133		    break;
134	    }
135
136   if (0 <= quiet)
137       if (!a)
138	    VOID scanfile(stdin, (char*)0, quiet);
139       else
140	    do {
141		if (!(fp = fopen(a, FOPEN_RB))) {
142		    reportError(a);
143		    status = EXIT_FAILURE;
144		} else if (
145		    scanfile(fp, a, quiet) != 0
146		    || (argv[1]  &&  putchar('\n') == EOF)
147		)
148		    break;
149	    } while ((a = *++argv));
150
151   if (ferror(stdout) || fclose(stdout)!=0) {
152      reportError("standard output");
153      status = EXIT_FAILURE;
154   }
155   exitmain(status);
156}
157
158#if RCS_lint
159#	define exiterr identExit
160#endif
161	void
162exiterr()
163{
164	_exit(EXIT_FAILURE);
165}
166
167	static void
168reportError(s)
169	char const *s;
170{
171	int e = errno;
172	VOID fprintf(stderr, "%s error: ", cmdid);
173	errno = e;
174	perror(s);
175}
176
177
178	static int
179scanfile(file, name, quiet)
180	register FILE *file;
181	char const *name;
182	int quiet;
183/* Function: scan an open file with descriptor file for keywords.
184 * Return -1 if there's a write error; exit immediately on a read error.
185 */
186{
187   register int c;
188
189   if (name) {
190      VOID printf("%s:\n", name);
191      if (ferror(stdout))
192	 return -1;
193   } else
194      name = "standard input";
195   c = 0;
196   while (c != EOF  ||  ! (feof(file)|ferror(file))) {
197      if (c == KDELIM) {
198	 if ((c = match(file)))
199	    continue;
200	 if (ferror(stdout))
201	    return -1;
202	 quiet = true;
203      }
204      c = getc(file);
205   }
206   if (ferror(file) || fclose(file) != 0) {
207      reportError(name);
208      /*
209      * The following is equivalent to exit(EXIT_FAILURE), but we invoke
210      * exiterr to keep lint happy.  The DOS and OS/2 ports need exiterr.
211      */
212      VOID fflush(stderr);
213      VOID fflush(stdout);
214      exiterr();
215   }
216   if (!quiet)
217      VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name);
218   return 0;
219}
220
221
222
223	static int
224match(fp)   /* group substring between two KDELIM's; then do pattern match */
225   register FILE *fp;
226{
227   char line[BUFSIZ];
228   register int c;
229   register char * tp;
230
231   tp = line;
232   while ((c = getc(fp)) != VDELIM) {
233      if (c == EOF  &&  feof(fp) | ferror(fp))
234	 return c;
235      switch (ctab[c]) {
236	 case LETTER: case Letter:
237	    *tp++ = c;
238	    if (tp < line+sizeof(line)-4)
239	       break;
240	    /* fall into */
241	 default:
242	    return c ? c : '\n'/* anything but 0 or KDELIM or EOF */;
243      }
244   }
245   if (tp == line)
246      return c;
247   *tp++ = c;
248   if ((c = getc(fp)) != ' ')
249      return c ? c : '\n';
250   *tp++ = c;
251   while( (c = getc(fp)) != KDELIM ) {
252      if (c == EOF  &&  feof(fp) | ferror(fp))
253	    return c;
254      switch (ctab[c]) {
255	 default:
256	    *tp++ = c;
257	    if (tp < line+sizeof(line)-2)
258	       break;
259	    /* fall into */
260	 case NEWLN: case UNKN:
261	    return c ? c : '\n';
262      }
263   }
264   if (tp[-1] != ' ')
265      return c;
266   *tp++ = c;     /*append trailing KDELIM*/
267   *tp   = '\0';
268   VOID printf("     %c%s\n", KDELIM, line);
269   return 0;
270}
271