1238438Sdteske/* Identify RCS keyword strings in files. */ 2238438Sdteske 3247280Sdteske/* Copyright 1982, 1988, 1989 Walter Tichy 4252980Sdteske Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 5238438Sdteske Distributed under license by the Free Software Foundation, Inc. 6238438Sdteske 7238438SdteskeThis file is part of RCS. 8238438Sdteske 9238438SdteskeRCS is free software; you can redistribute it and/or modify 10238438Sdteskeit under the terms of the GNU General Public License as published by 11238438Sdteskethe Free Software Foundation; either version 2, or (at your option) 12238438Sdteskeany later version. 13238438Sdteske 14238438SdteskeRCS is distributed in the hope that it will be useful, 15238438Sdteskebut WITHOUT ANY WARRANTY; without even the implied warranty of 16252987SdteskeMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17238438SdteskeGNU General Public License for more details. 18238438Sdteske 19238438SdteskeYou should have received a copy of the GNU General Public License 20252987Sdteskealong with RCS; see the file COPYING. 21238438SdteskeIf not, write to the Free Software Foundation, 22238438Sdteske59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23238438Sdteske 24238438SdteskeReport problems and direct all questions to: 25238438Sdteske 26238438Sdteske rcs-bugs@cs.purdue.edu 27238438Sdteske 28249751Sdteske*/ 29256361Sdteske 30256361Sdteske/* 31256361Sdteske * Revision 5.9 1995/06/16 06:19:24 eggert 32256361Sdteske * Update FSF address. 33256361Sdteske * 34249751Sdteske * Revision 5.8 1995/06/01 16:23:43 eggert 35238438Sdteske * (exiterr, reportError): New functions, needed for DOS and OS/2 ports. 36249751Sdteske * (scanfile): Use them. 37263980Sdteske * 38263980Sdteske * Revision 5.7 1994/03/20 04:52:58 eggert 39263980Sdteske * Remove `exiting' from identExit. 40263980Sdteske * 41263980Sdteske * Revision 5.6 1993/11/09 17:40:15 eggert 42263980Sdteske * Add -V. 43249751Sdteske * 44249751Sdteske * Revision 5.5 1993/11/03 17:42:27 eggert 45249751Sdteske * Test for char == EOF, not char < 0. 46249751Sdteske * 47249751Sdteske * Revision 5.4 1992/01/24 18:44:19 eggert 48249751Sdteske * lint -> RCS_lint 49249751Sdteske * 50249751Sdteske * Revision 5.3 1991/09/10 22:15:46 eggert 51249751Sdteske * Open files with FOPEN_R, not FOPEN_R_WORK, 52249751Sdteske * because they might be executables, not working files. 53249751Sdteske * 54249751Sdteske * Revision 5.2 1991/08/19 03:13:55 eggert 55258420Sdteske * Report read errors immediately. 56238438Sdteske * 57238438Sdteske * Revision 5.1 1991/02/25 07:12:37 eggert 58238438Sdteske * Don't report empty keywords. Check for I/O errors. 59238438Sdteske * 60238438Sdteske * Revision 5.0 1990/08/22 08:12:37 eggert 61238438Sdteske * Don't limit output to known keywords. 62238438Sdteske * Remove arbitrary limits and lint. Ansify and Posixate. 63238438Sdteske * 64238438Sdteske * Revision 4.5 89/05/01 15:11:54 narten 65258420Sdteske * changed copyright header to reflect current distribution rules 66250701Sdteske * 67250701Sdteske * Revision 4.4 87/10/23 17:09:57 narten 68258420Sdteske * added exit(0) so exit return code would be non random 69258420Sdteske * 70250701Sdteske * Revision 4.3 87/10/18 10:23:55 narten 71250701Sdteske * Updating version numbers. Changes relative to 1.1 are actually relative 72250701Sdteske * to 4.1 73250701Sdteske * 74258420Sdteske * Revision 1.3 87/07/09 09:20:52 trinkle 75258420Sdteske * Added check to make sure there is at least one arg before comparing argv[1] 76258420Sdteske * with "-q". This necessary on machines that don't allow dereferncing null 77250701Sdteske * pointers (i.e. Suns). 78250701Sdteske * 79250701Sdteske * Revision 1.2 87/03/27 14:21:47 jenkins 80250701Sdteske * Port to suns 81250701Sdteske * 82250701Sdteske * Revision 4.1 83/05/10 16:31:02 wft 83250701Sdteske * Added option -q and input from reading stdin. 84250701Sdteske * Marker matching is now done with trymatch() (independent of keywords). 85250701Sdteske * 86258420Sdteske * Revision 3.4 83/02/18 17:37:49 wft 87258420Sdteske * removed printing of new line after last file. 88258420Sdteske * 89258420Sdteske * Revision 3.3 82/12/04 12:48:55 wft 90258420Sdteske * Added LOCKER. 91258420Sdteske * 92258420Sdteske * Revision 3.2 82/11/28 18:24:17 wft 93258420Sdteske * removed Suffix; added ungetc to avoid skipping over trailing KDELIM. 94258420Sdteske * 95258420Sdteske * Revision 3.1 82/10/13 15:58:51 wft 96258420Sdteske * fixed type of variables receiving from getc() (char-->int). 97258420Sdteske*/ 98251278Sdteske 99251278Sdteske#include "rcsbase.h" 100251278Sdteske 101251278Sdteskestatic int match P((FILE*)); 102251278Sdteskestatic int scanfile P((FILE*,char const*,int)); 103251278Sdteskestatic void reportError P((char const*)); 104251278Sdteske 105251278SdteskemainProg(identId, "ident", "$FreeBSD: releng/10.2/gnu/usr.bin/rcs/ident/ident.c 87625 2001-12-10 20:44:31Z peter $") 106251278Sdteske/* Ident searches the named files for all occurrences 107251278Sdteske * of the pattern $@: text $ where @ is a keyword. 108251278Sdteske */ 109251278Sdteske 110251278Sdteske{ 111251278Sdteske FILE *fp; 112251278Sdteske int quiet = 0; 113251278Sdteske int status = EXIT_SUCCESS; 114251278Sdteske char const *a; 115251278Sdteske 116251278Sdteske while ((a = *++argv) && *a=='-') 117251278Sdteske while (*++a) 118251278Sdteske switch (*a) { 119251278Sdteske case 'q': 120251278Sdteske quiet = 1; 121251278Sdteske break; 122251278Sdteske 123251278Sdteske case 'V': 124251278Sdteske VOID printf("RCS version %s\n", RCS_version_string); 125251278Sdteske quiet = -1; 126251278Sdteske break; 127251278Sdteske 128251278Sdteske default: 129251278Sdteske VOID fprintf(stderr, 130251278Sdteske "ident: usage: ident -{qV} [file...]\n" 131251278Sdteske ); 132251278Sdteske exitmain(EXIT_FAILURE); 133258420Sdteske break; 134258420Sdteske } 135258420Sdteske 136258420Sdteske if (0 <= quiet) 137258420Sdteske if (!a) 138258420Sdteske VOID scanfile(stdin, (char*)0, quiet); 139258420Sdteske else 140258420Sdteske do { 141258420Sdteske if (!(fp = fopen(a, FOPEN_RB))) { 142258420Sdteske reportError(a); 143238438Sdteske status = EXIT_FAILURE; 144238438Sdteske } else if ( 145238438Sdteske scanfile(fp, a, quiet) != 0 146238438Sdteske || (argv[1] && putchar('\n') == EOF) 147238438Sdteske ) 148238438Sdteske break; 149238438Sdteske } while ((a = *++argv)); 150238438Sdteske 151238438Sdteske if (ferror(stdout) || fclose(stdout)!=0) { 152238438Sdteske reportError("standard output"); 153238438Sdteske status = EXIT_FAILURE; 154238438Sdteske } 155238438Sdteske exitmain(status); 156238438Sdteske} 157238438Sdteske 158238438Sdteske#if RCS_lint 159238438Sdteske# define exiterr identExit 160238438Sdteske#endif 161238438Sdteske void 162238438Sdteskeexiterr() 163238438Sdteske{ 164238438Sdteske _exit(EXIT_FAILURE); 165238438Sdteske} 166238438Sdteske 167238438Sdteske static void 168238438SdteskereportError(s) 169238438Sdteske char const *s; 170238438Sdteske{ 171238438Sdteske int e = errno; 172238438Sdteske VOID fprintf(stderr, "%s error: ", cmdid); 173238438Sdteske errno = e; 174238438Sdteske perror(s); 175238438Sdteske} 176238438Sdteske 177238438Sdteske 178238438Sdteske static int 179238438Sdteskescanfile(file, name, quiet) 180238438Sdteske register FILE *file; 181238438Sdteske char const *name; 182241700Sdteske int quiet; 183238438Sdteske/* Function: scan an open file with descriptor file for keywords. 184238438Sdteske * Return -1 if there's a write error; exit immediately on a read error. 185238438Sdteske */ 186238438Sdteske{ 187238438Sdteske register int c; 188238438Sdteske 189238438Sdteske if (name) { 190238438Sdteske VOID printf("%s:\n", name); 191238438Sdteske if (ferror(stdout)) 192238438Sdteske return -1; 193238438Sdteske } else 194238438Sdteske name = "standard input"; 195238438Sdteske c = 0; 196238438Sdteske while (c != EOF || ! (feof(file)|ferror(file))) { 197260678Sdteske if (c == KDELIM) { 198263980Sdteske if ((c = match(file))) 199238438Sdteske continue; 200238438Sdteske if (ferror(stdout)) 201247280Sdteske return -1; 202247280Sdteske quiet = true; 203247280Sdteske } 204247280Sdteske c = getc(file); 205247280Sdteske } 206247280Sdteske if (ferror(file) || fclose(file) != 0) { 207247280Sdteske reportError(name); 208247280Sdteske /* 209247280Sdteske * The following is equivalent to exit(EXIT_FAILURE), but we invoke 210247280Sdteske * exiterr to keep lint happy. The DOS and OS/2 ports need exiterr. 211247280Sdteske */ 212247280Sdteske VOID fflush(stderr); 213247280Sdteske VOID fflush(stdout); 214247280Sdteske exiterr(); 215247280Sdteske } 216247280Sdteske if (!quiet) 217247280Sdteske VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name); 218247280Sdteske return 0; 219247280Sdteske} 220247280Sdteske 221247280Sdteske 222247280Sdteske 223247280Sdteske static int 224247280Sdteskematch(fp) /* group substring between two KDELIM's; then do pattern match */ 225247280Sdteske register FILE *fp; 226247280Sdteske{ 227247280Sdteske char line[BUFSIZ]; 228247280Sdteske register int c; 229247280Sdteske register char * tp; 230247280Sdteske 231247280Sdteske tp = line; 232247280Sdteske while ((c = getc(fp)) != VDELIM) { 233247280Sdteske if (c == EOF && feof(fp) | ferror(fp)) 234247280Sdteske return c; 235247280Sdteske switch (ctab[c]) { 236247280Sdteske case LETTER: case Letter: case DIGIT: 237247280Sdteske *tp++ = c; 238247280Sdteske if (tp < line+sizeof(line)-4) 239247280Sdteske break; 240247280Sdteske /* fall into */ 241247280Sdteske default: 242247280Sdteske return c ? c : '\n'/* anything but 0 or KDELIM or EOF */; 243247280Sdteske } 244247280Sdteske } 245247280Sdteske if (tp == line) 246247280Sdteske return c; 247247280Sdteske *tp++ = c; 248247280Sdteske if ((c = getc(fp)) != ' ') 249247280Sdteske return c ? c : '\n'; 250247280Sdteske *tp++ = c; 251247280Sdteske while( (c = getc(fp)) != KDELIM ) { 252247280Sdteske if (c == EOF && feof(fp) | ferror(fp)) 253247280Sdteske return c; 254247280Sdteske switch (ctab[c]) { 255247280Sdteske default: 256247280Sdteske *tp++ = c; 257247280Sdteske if (tp < line+sizeof(line)-2) 258247280Sdteske break; 259247280Sdteske /* fall into */ 260247280Sdteske case NEWLN: case UNKN: 261247280Sdteske return c ? c : '\n'; 262247280Sdteske } 263247280Sdteske } 264247280Sdteske if (tp[-1] != ' ') 265247280Sdteske return c; 266247280Sdteske *tp++ = c; /*append trailing KDELIM*/ 267249751Sdteske *tp = '\0'; 268249751Sdteske VOID printf(" %c%s\n", KDELIM, line); 269250702Sdteske return 0; 270249751Sdteske} 271249751Sdteske