ident.c revision 21673
1247280Sdteske/* Identify RCS keyword strings in files. */ 2247280Sdteske 3247280Sdteske/* Copyright 1982, 1988, 1989 Walter Tichy 4247280Sdteske Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 5247280Sdteske Distributed under license by the Free Software Foundation, Inc. 6247280Sdteske 7247280SdteskeThis file is part of RCS. 8247280Sdteske 9247280SdteskeRCS is free software; you can redistribute it and/or modify 10247280Sdteskeit under the terms of the GNU General Public License as published by 11247280Sdteskethe Free Software Foundation; either version 2, or (at your option) 12247280Sdteskeany later version. 13247280Sdteske 14247280SdteskeRCS is distributed in the hope that it will be useful, 15247280Sdteskebut WITHOUT ANY WARRANTY; without even the implied warranty of 16247280SdteskeMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17247280SdteskeGNU General Public License for more details. 18247280Sdteske 19247280SdteskeYou should have received a copy of the GNU General Public License 20247280Sdteskealong with RCS; see the file COPYING. 21247280SdteskeIf not, write to the Free Software Foundation, 22247280Sdteske59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23247280Sdteske 24247280SdteskeReport problems and direct all questions to: 25247280Sdteske 26247280Sdteske rcs-bugs@cs.purdue.edu 27247280Sdteske 28247280Sdteske*/ 29247280Sdteske 30247280Sdteske/* 31247280Sdteske * Revision 5.9 1995/06/16 06:19:24 eggert 32247280Sdteske * Update FSF address. 33247280Sdteske * 34247280Sdteske * Revision 5.8 1995/06/01 16:23:43 eggert 35247280Sdteske * (exiterr, reportError): New functions, needed for DOS and OS/2 ports. 36247280Sdteske * (scanfile): Use them. 37247280Sdteske * 38247280Sdteske * Revision 5.7 1994/03/20 04:52:58 eggert 39247280Sdteske * Remove `exiting' from identExit. 40247280Sdteske * 41247280Sdteske * Revision 5.6 1993/11/09 17:40:15 eggert 42247280Sdteske * Add -V. 43247280Sdteske * 44247280Sdteske * Revision 5.5 1993/11/03 17:42:27 eggert 45247280Sdteske * Test for char == EOF, not char < 0. 46247280Sdteske * 47247280Sdteske * Revision 5.4 1992/01/24 18:44:19 eggert 48247280Sdteske * lint -> RCS_lint 49247280Sdteske * 50247280Sdteske * Revision 5.3 1991/09/10 22:15:46 eggert 51247280Sdteske * Open files with FOPEN_R, not FOPEN_R_WORK, 52247280Sdteske * because they might be executables, not working files. 53247280Sdteske * 54247280Sdteske * Revision 5.2 1991/08/19 03:13:55 eggert 55247280Sdteske * Report read errors immediately. 56247280Sdteske * 57247280Sdteske * Revision 5.1 1991/02/25 07:12:37 eggert 58251190Sdteske * Don't report empty keywords. Check for I/O errors. 59247280Sdteske * 60247280Sdteske * Revision 5.0 1990/08/22 08:12:37 eggert 61247280Sdteske * Don't limit output to known keywords. 62247280Sdteske * Remove arbitrary limits and lint. Ansify and Posixate. 63247280Sdteske * 64247280Sdteske * Revision 4.5 89/05/01 15:11:54 narten 65247280Sdteske * changed copyright header to reflect current distribution rules 66247280Sdteske * 67247280Sdteske * Revision 4.4 87/10/23 17:09:57 narten 68247280Sdteske * added exit(0) so exit return code would be non random 69249751Sdteske * 70247280Sdteske * Revision 4.3 87/10/18 10:23:55 narten 71247280Sdteske * Updating version numbers. Changes relative to 1.1 are actually relative 72247280Sdteske * to 4.1 73247280Sdteske * 74247280Sdteske * Revision 1.3 87/07/09 09:20:52 trinkle 75247280Sdteske * Added check to make sure there is at least one arg before comparing argv[1] 76247280Sdteske * with "-q". This necessary on machines that don't allow dereferncing null 77247280Sdteske * pointers (i.e. Suns). 78247280Sdteske * 79247280Sdteske * Revision 1.2 87/03/27 14:21:47 jenkins 80247280Sdteske * Port to suns 81247280Sdteske * 82247280Sdteske * Revision 4.1 83/05/10 16:31:02 wft 83247280Sdteske * Added option -q and input from reading stdin. 84247280Sdteske * Marker matching is now done with trymatch() (independent of keywords). 85247280Sdteske * 86247280Sdteske * Revision 3.4 83/02/18 17:37:49 wft 87247280Sdteske * removed printing of new line after last file. 88247280Sdteske * 89247280Sdteske * Revision 3.3 82/12/04 12:48:55 wft 90247280Sdteske * Added LOCKER. 91247280Sdteske * 92247280Sdteske * Revision 3.2 82/11/28 18:24:17 wft 93247280Sdteske * removed Suffix; added ungetc to avoid skipping over trailing KDELIM. 94247280Sdteske * 95247280Sdteske * Revision 3.1 82/10/13 15:58:51 wft 96247280Sdteske * fixed type of variables receiving from getc() (char-->int). 97247280Sdteske*/ 98247280Sdteske 99247280Sdteske#include "rcsbase.h" 100247280Sdteske 101247280Sdteskestatic int match P((FILE*)); 102247280Sdteskestatic int scanfile P((FILE*,char const*,int)); 103247280Sdteskestatic void reportError P((char const*)); 104247280Sdteske 105247280SdteskemainProg(identId, "ident", "$FreeBSD: head/gnu/usr.bin/rcs/ident/ident.c 21673 1997-01-14 07:20:47Z jkh $") 106247280Sdteske/* Ident searches the named files for all occurrences 107247280Sdteske * of the pattern $@: text $ where @ is a keyword. 108247280Sdteske */ 109247280Sdteske 110247280Sdteske{ 111247280Sdteske FILE *fp; 112247280Sdteske int quiet = 0; 113247280Sdteske int status = EXIT_SUCCESS; 114250323Sdteske char const *a; 115250323Sdteske 116250323Sdteske while ((a = *++argv) && *a=='-') 117250323Sdteske while (*++a) 118250323Sdteske switch (*a) { 119250323Sdteske case 'q': 120250323Sdteske quiet = 1; 121250323Sdteske break; 122250323Sdteske 123247280Sdteske case 'V': 124247280Sdteske VOID printf("RCS version %s\n", RCS_version_string); 125247280Sdteske quiet = -1; 126247280Sdteske break; 127247280Sdteske 128247280Sdteske default: 129247280Sdteske VOID fprintf(stderr, 130247280Sdteske "ident: usage: ident -{qV} [file...]\n" 131247280Sdteske ); 132247280Sdteske exitmain(EXIT_FAILURE); 133247280Sdteske break; 134247280Sdteske } 135247280Sdteske 136247280Sdteske if (0 <= quiet) 137247280Sdteske if (!a) 138247280Sdteske VOID scanfile(stdin, (char*)0, quiet); 139247280Sdteske else 140247280Sdteske do { 141247280Sdteske if (!(fp = fopen(a, FOPEN_RB))) { 142247280Sdteske reportError(a); 143247280Sdteske status = EXIT_FAILURE; 144247280Sdteske } else if ( 145247280Sdteske scanfile(fp, a, quiet) != 0 146247280Sdteske || (argv[1] && putchar('\n') == EOF) 147247280Sdteske ) 148247280Sdteske break; 149247280Sdteske } while ((a = *++argv)); 150247280Sdteske 151247280Sdteske if (ferror(stdout) || fclose(stdout)!=0) { 152247280Sdteske reportError("standard output"); 153247280Sdteske status = EXIT_FAILURE; 154247280Sdteske } 155247280Sdteske exitmain(status); 156247280Sdteske} 157247280Sdteske 158247280Sdteske#if RCS_lint 159247280Sdteske# define exiterr identExit 160247280Sdteske#endif 161247280Sdteske void 162247280Sdteskeexiterr() 163247280Sdteske{ 164247280Sdteske _exit(EXIT_FAILURE); 165247280Sdteske} 166247280Sdteske 167247280Sdteske static void 168247280SdteskereportError(s) 169247280Sdteske char const *s; 170247280Sdteske{ 171247280Sdteske int e = errno; 172247280Sdteske VOID fprintf(stderr, "%s error: ", cmdid); 173247280Sdteske errno = e; 174247280Sdteske perror(s); 175247280Sdteske} 176247280Sdteske 177247280Sdteske 178247280Sdteske static int 179247280Sdteskescanfile(file, name, quiet) 180247280Sdteske register FILE *file; 181247280Sdteske char const *name; 182247280Sdteske int quiet; 183247280Sdteske/* Function: scan an open file with descriptor file for keywords. 184247280Sdteske * Return -1 if there's a write error; exit immediately on a read error. 185247280Sdteske */ 186247280Sdteske{ 187247280Sdteske register int c; 188247280Sdteske 189247280Sdteske if (name) { 190247280Sdteske VOID printf("%s:\n", name); 191250323Sdteske if (ferror(stdout)) 192247280Sdteske return -1; 193250323Sdteske } else 194250323Sdteske name = "standard input"; 195250323Sdteske c = 0; 196250323Sdteske while (c != EOF || ! (feof(file)|ferror(file))) { 197247280Sdteske if (c == KDELIM) { 198247280Sdteske if ((c = match(file))) 199247280Sdteske continue; 200247280Sdteske if (ferror(stdout)) 201247280Sdteske return -1; 202247280Sdteske quiet = true; 203251190Sdteske } 204251190Sdteske c = getc(file); 205251190Sdteske } 206251190Sdteske if (ferror(file) || fclose(file) != 0) { 207251190Sdteske reportError(name); 208251190Sdteske /* 209251190Sdteske * 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); 214251190Sdteske exiterr(); 215251190Sdteske } 216251190Sdteske if (!quiet) 217251190Sdteske VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name); 218251190Sdteske return 0; 219251190Sdteske} 220251190Sdteske 221251190Sdteske 222251190Sdteske 223251190Sdteske static int 224251190Sdteskematch(fp) /* group substring between two KDELIM's; then do pattern match */ 225251190Sdteske register FILE *fp; 226251190Sdteske{ 227247280Sdteske char line[BUFSIZ]; 228247280Sdteske register int c; 229247280Sdteske register char * tp; 230247280Sdteske 231249751Sdteske 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: 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*/ 267247280Sdteske *tp = '\0'; 268247280Sdteske VOID printf(" %c%s\n", KDELIM, line); 269247280Sdteske return 0; 270247280Sdteske} 271247280Sdteske