111894Speter/* Identify RCS keyword strings in files. */ 211894Speter 311894Speter/* Copyright 1982, 1988, 1989 Walter Tichy 411894Speter Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 59Sjkh Distributed under license by the Free Software Foundation, Inc. 69Sjkh 79SjkhThis file is part of RCS. 89Sjkh 99SjkhRCS is free software; you can redistribute it and/or modify 109Sjkhit under the terms of the GNU General Public License as published by 119Sjkhthe Free Software Foundation; either version 2, or (at your option) 129Sjkhany later version. 139Sjkh 149SjkhRCS is distributed in the hope that it will be useful, 159Sjkhbut WITHOUT ANY WARRANTY; without even the implied warranty of 169SjkhMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 179SjkhGNU General Public License for more details. 189Sjkh 199SjkhYou should have received a copy of the GNU General Public License 2011894Speteralong with RCS; see the file COPYING. 2111894SpeterIf not, write to the Free Software Foundation, 2211894Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 239Sjkh 249SjkhReport problems and direct all questions to: 259Sjkh 269Sjkh rcs-bugs@cs.purdue.edu 279Sjkh 289Sjkh*/ 299Sjkh 309Sjkh/* 3111894Speter * Revision 5.9 1995/06/16 06:19:24 eggert 3211894Speter * Update FSF address. 338858Srgrimes * 3411894Speter * Revision 5.8 1995/06/01 16:23:43 eggert 3511894Speter * (exiterr, reportError): New functions, needed for DOS and OS/2 ports. 3611894Speter * (scanfile): Use them. 3711894Speter * 3811894Speter * Revision 5.7 1994/03/20 04:52:58 eggert 3911894Speter * Remove `exiting' from identExit. 4011894Speter * 4111894Speter * Revision 5.6 1993/11/09 17:40:15 eggert 4211894Speter * Add -V. 4311894Speter * 4411894Speter * Revision 5.5 1993/11/03 17:42:27 eggert 4511894Speter * Test for char == EOF, not char < 0. 4611894Speter * 4711894Speter * Revision 5.4 1992/01/24 18:44:19 eggert 4811894Speter * lint -> RCS_lint 4911894Speter * 509Sjkh * Revision 5.3 1991/09/10 22:15:46 eggert 519Sjkh * Open files with FOPEN_R, not FOPEN_R_WORK, 529Sjkh * because they might be executables, not working files. 539Sjkh * 549Sjkh * Revision 5.2 1991/08/19 03:13:55 eggert 559Sjkh * Report read errors immediately. 569Sjkh * 579Sjkh * Revision 5.1 1991/02/25 07:12:37 eggert 589Sjkh * Don't report empty keywords. Check for I/O errors. 599Sjkh * 609Sjkh * Revision 5.0 1990/08/22 08:12:37 eggert 619Sjkh * Don't limit output to known keywords. 629Sjkh * Remove arbitrary limits and lint. Ansify and Posixate. 639Sjkh * 649Sjkh * Revision 4.5 89/05/01 15:11:54 narten 659Sjkh * changed copyright header to reflect current distribution rules 668858Srgrimes * 679Sjkh * Revision 4.4 87/10/23 17:09:57 narten 689Sjkh * added exit(0) so exit return code would be non random 698858Srgrimes * 709Sjkh * Revision 4.3 87/10/18 10:23:55 narten 719Sjkh * Updating version numbers. Changes relative to 1.1 are actually relative 729Sjkh * to 4.1 738858Srgrimes * 749Sjkh * Revision 1.3 87/07/09 09:20:52 trinkle 759Sjkh * Added check to make sure there is at least one arg before comparing argv[1] 769Sjkh * with "-q". This necessary on machines that don't allow dereferncing null 779Sjkh * pointers (i.e. Suns). 788858Srgrimes * 799Sjkh * Revision 1.2 87/03/27 14:21:47 jenkins 809Sjkh * Port to suns 818858Srgrimes * 829Sjkh * Revision 4.1 83/05/10 16:31:02 wft 839Sjkh * Added option -q and input from reading stdin. 849Sjkh * Marker matching is now done with trymatch() (independent of keywords). 858858Srgrimes * 869Sjkh * Revision 3.4 83/02/18 17:37:49 wft 879Sjkh * removed printing of new line after last file. 889Sjkh * 899Sjkh * Revision 3.3 82/12/04 12:48:55 wft 909Sjkh * Added LOCKER. 919Sjkh * 929Sjkh * Revision 3.2 82/11/28 18:24:17 wft 939Sjkh * removed Suffix; added ungetc to avoid skipping over trailing KDELIM. 949Sjkh * 959Sjkh * Revision 3.1 82/10/13 15:58:51 wft 969Sjkh * fixed type of variables receiving from getc() (char-->int). 979Sjkh*/ 989Sjkh 999Sjkh#include "rcsbase.h" 1009Sjkh 1019Sjkhstatic int match P((FILE*)); 10211894Speterstatic int scanfile P((FILE*,char const*,int)); 10311894Speterstatic void reportError P((char const*)); 1049Sjkh 10550472SpetermainProg(identId, "ident", "$FreeBSD$") 1069Sjkh/* Ident searches the named files for all occurrences 10711894Speter * of the pattern $@: text $ where @ is a keyword. 1089Sjkh */ 1099Sjkh 1109Sjkh{ 1119Sjkh FILE *fp; 11211894Speter int quiet = 0; 1139Sjkh int status = EXIT_SUCCESS; 11411894Speter char const *a; 1159Sjkh 11611894Speter while ((a = *++argv) && *a=='-') 11711894Speter while (*++a) 11811894Speter switch (*a) { 11911894Speter case 'q': 12011894Speter quiet = 1; 12111894Speter break; 1229Sjkh 12311894Speter case 'V': 12411894Speter VOID printf("RCS version %s\n", RCS_version_string); 12511894Speter quiet = -1; 12611894Speter break; 1279Sjkh 12811894Speter default: 12911894Speter VOID fprintf(stderr, 13011894Speter "ident: usage: ident -{qV} [file...]\n" 13111894Speter ); 13211894Speter exitmain(EXIT_FAILURE); 13311894Speter break; 13411894Speter } 13511894Speter 13611894Speter if (0 <= quiet) 13711894Speter if (!a) 13811894Speter VOID scanfile(stdin, (char*)0, quiet); 13911894Speter else 14011894Speter do { 14111894Speter if (!(fp = fopen(a, FOPEN_RB))) { 14211894Speter reportError(a); 14311894Speter status = EXIT_FAILURE; 14411894Speter } else if ( 14511894Speter scanfile(fp, a, quiet) != 0 14611894Speter || (argv[1] && putchar('\n') == EOF) 14711894Speter ) 14811894Speter break; 14911894Speter } while ((a = *++argv)); 15011894Speter 1519Sjkh if (ferror(stdout) || fclose(stdout)!=0) { 15211894Speter reportError("standard output"); 1539Sjkh status = EXIT_FAILURE; 1549Sjkh } 1559Sjkh exitmain(status); 1569Sjkh} 1579Sjkh 15811894Speter#if RCS_lint 15911894Speter# define exiterr identExit 1609Sjkh#endif 16111894Speter void 16211894Speterexiterr() 16311894Speter{ 16411894Speter _exit(EXIT_FAILURE); 16511894Speter} 1669Sjkh 16711894Speter static void 16811894SpeterreportError(s) 16911894Speter char const *s; 17011894Speter{ 17111894Speter int e = errno; 17211894Speter VOID fprintf(stderr, "%s error: ", cmdid); 17311894Speter errno = e; 17411894Speter perror(s); 17511894Speter} 1769Sjkh 17711894Speter 17811894Speter static int 1799Sjkhscanfile(file, name, quiet) 1809Sjkh register FILE *file; 1819Sjkh char const *name; 1829Sjkh int quiet; 1839Sjkh/* Function: scan an open file with descriptor file for keywords. 18411894Speter * Return -1 if there's a write error; exit immediately on a read error. 1859Sjkh */ 1869Sjkh{ 1879Sjkh register int c; 1889Sjkh 18911894Speter if (name) { 1909Sjkh VOID printf("%s:\n", name); 19111894Speter if (ferror(stdout)) 19211894Speter return -1; 19311894Speter } else 19411894Speter name = "standard input"; 1959Sjkh c = 0; 19611894Speter while (c != EOF || ! (feof(file)|ferror(file))) { 1979Sjkh if (c == KDELIM) { 1989Sjkh if ((c = match(file))) 1999Sjkh continue; 20011894Speter if (ferror(stdout)) 20111894Speter return -1; 2029Sjkh quiet = true; 2039Sjkh } 2049Sjkh c = getc(file); 2059Sjkh } 20611894Speter if (ferror(file) || fclose(file) != 0) { 20711894Speter reportError(name); 20811894Speter /* 20911894Speter * The following is equivalent to exit(EXIT_FAILURE), but we invoke 21011894Speter * exiterr to keep lint happy. The DOS and OS/2 ports need exiterr. 21111894Speter */ 21211894Speter VOID fflush(stderr); 21311894Speter VOID fflush(stdout); 21411894Speter exiterr(); 21511894Speter } 2169Sjkh if (!quiet) 2179Sjkh VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name); 21811894Speter return 0; 2199Sjkh} 2209Sjkh 2219Sjkh 2229Sjkh 2239Sjkh static int 2249Sjkhmatch(fp) /* group substring between two KDELIM's; then do pattern match */ 2259Sjkh register FILE *fp; 2269Sjkh{ 2279Sjkh char line[BUFSIZ]; 2289Sjkh register int c; 2299Sjkh register char * tp; 2309Sjkh 2319Sjkh tp = line; 2329Sjkh while ((c = getc(fp)) != VDELIM) { 23311894Speter if (c == EOF && feof(fp) | ferror(fp)) 2349Sjkh return c; 2359Sjkh switch (ctab[c]) { 23687625Speter case LETTER: case Letter: case DIGIT: 2379Sjkh *tp++ = c; 2389Sjkh if (tp < line+sizeof(line)-4) 2399Sjkh break; 2409Sjkh /* fall into */ 2419Sjkh default: 2429Sjkh return c ? c : '\n'/* anything but 0 or KDELIM or EOF */; 2439Sjkh } 2449Sjkh } 2459Sjkh if (tp == line) 2469Sjkh return c; 2479Sjkh *tp++ = c; 2489Sjkh if ((c = getc(fp)) != ' ') 2499Sjkh return c ? c : '\n'; 2509Sjkh *tp++ = c; 2519Sjkh while( (c = getc(fp)) != KDELIM ) { 25211894Speter if (c == EOF && feof(fp) | ferror(fp)) 2539Sjkh return c; 2549Sjkh switch (ctab[c]) { 2559Sjkh default: 2569Sjkh *tp++ = c; 2579Sjkh if (tp < line+sizeof(line)-2) 2589Sjkh break; 2599Sjkh /* fall into */ 2609Sjkh case NEWLN: case UNKN: 2619Sjkh return c ? c : '\n'; 2629Sjkh } 2639Sjkh } 2649Sjkh if (tp[-1] != ' ') 2659Sjkh return c; 2669Sjkh *tp++ = c; /*append trailing KDELIM*/ 2679Sjkh *tp = '\0'; 26811894Speter VOID printf(" %c%s\n", KDELIM, line); 2699Sjkh return 0; 2709Sjkh} 271