ident.c revision 285890
1/*- 2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/usr.bin/ident/ident.c 285890 2015-07-26 11:21:36Z bapt $"); 29 30#include <sys/types.h> 31#include <sys/sbuf.h> 32 33#include <ctype.h> 34#include <err.h> 35#include <stdbool.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <unistd.h> 39#include <xlocale.h> 40 41static bool 42parse_id(FILE *fp, struct sbuf *buf, locale_t l) 43{ 44 int c; 45 bool isid = false; 46 bool subversion = false; 47 48 sbuf_putc(buf, '$'); 49 while ((c = fgetc(fp)) != EOF) { 50 sbuf_putc(buf, c); 51 if (!isid) { 52 if (c == '$') { 53 sbuf_clear(buf); 54 sbuf_putc(buf, '$'); 55 continue; 56 } 57 if (c == ':') { 58 c = fgetc(fp); 59 /* accept :: for subversion compatibility */ 60 if (c == ':') { 61 subversion = true; 62 sbuf_putc(buf, c); 63 c = fgetc(fp); 64 } 65 if (c == ' ') { 66 sbuf_putc(buf, c); 67 isid = true; 68 continue; 69 } 70 return (false); 71 } 72 73 if (!isalpha_l(c, l)) 74 return (false); 75 } else { 76 if (c == '\n') 77 return (false); 78 if (c == '$') { 79 sbuf_finish(buf); 80 /* should end with a space */ 81 c = sbuf_data(buf)[sbuf_len(buf) - 2]; 82 if (!subversion) { 83 if (c != ' ') 84 return (0); 85 } else if (subversion) { 86 if (c != ' ' && c != '#') 87 return (0); 88 } 89 printf(" %s\n", sbuf_data(buf)); 90 return (true); 91 } 92 } 93 } 94 95 return (false); 96} 97 98static int 99scan(FILE *fp, const char *name, bool quiet) 100{ 101 int c; 102 bool hasid = false; 103 struct sbuf *id = sbuf_new_auto(); 104 locale_t l; 105 106 l = newlocale(LC_ALL_MASK, "C", NULL); 107 108 if (name != NULL) 109 printf("%s:\n", name); 110 111 while ((c = fgetc(fp)) != EOF) { 112 if (c == '$') { 113 sbuf_clear(id); 114 if (parse_id(fp, id, l)) 115 hasid = true; 116 } 117 } 118 sbuf_delete(id); 119 freelocale(l); 120 121 if (!hasid) { 122 if (!quiet) 123 fprintf(stderr, "%s warning: no id keywords in %s\n", 124 getprogname(), name ? name : "standard input"); 125 126 return (EXIT_FAILURE); 127 } 128 129 return (EXIT_SUCCESS); 130} 131 132int 133main(int argc, char **argv) 134{ 135 bool quiet = false; 136 int ch, i; 137 int ret = EXIT_SUCCESS; 138 FILE *fp; 139 140 while ((ch = getopt(argc, argv, "qV")) != -1) { 141 switch (ch) { 142 case 'q': 143 quiet = true; 144 break; 145 case 'V': 146 /* Do nothing, compat with GNU rcs's ident */ 147 return (EXIT_SUCCESS); 148 default: 149 errx(EXIT_FAILURE, "usage: %s [-q] [-V] [file...]", 150 getprogname()); 151 } 152 } 153 154 argc -= optind; 155 argv += optind; 156 157 if (argc == 0) 158 return (scan(stdin, NULL, quiet)); 159 160 for (i = 0; i < argc; i++) { 161 fp = fopen(argv[i], "r"); 162 if (fp == NULL) { 163 warn("%s", argv[i]); 164 ret = EXIT_FAILURE; 165 continue; 166 } 167 if (scan(fp, argv[i], quiet) != EXIT_SUCCESS) 168 ret = EXIT_FAILURE; 169 fclose(fp); 170 } 171 172 return (ret); 173} 174