1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1995 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <limits.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <libgen.h> 34 #include <libintl.h> 35 #include <locale.h> 36 #include <unistd.h> 37 #include <sys/param.h> 38 39 #include "genmsg.h" 40 41 #define MSG_SUFFIX ".msg" 42 #define NEW_SUFFIX ".new" 43 44 #if !defined(TEXT_DOMAIN) 45 #define TEXT_DOMAIN "genmsg" 46 #endif 47 48 /* 49 * External functions. 50 */ 51 extern void write_msgfile(char *); /* from util.c */ 52 extern int read_projfile(char *); /* from util.c */ 53 extern void write_projfile(char *); /* from util.c */ 54 extern void read_msgfile(char *); /* from util.c */ 55 extern int is_writable(char *); /* from util.c */ 56 extern int file_copy(char *, char *); /* from util.c */ 57 extern void init_lex(void); /* from genmsg.l */ 58 extern void init_linemsgid(void); /* from genmsg.l */ 59 60 /* Program name. */ 61 char *program; 62 63 /* File pointer for auto-message-numbering. */ 64 FILE *newfp = NULL; 65 66 /* Input source file. */ 67 char *srcfile; 68 69 /* Tag for message comments. */ 70 char *mctag = NULL; 71 72 /* Tag for set number comments. */ 73 char *sctag = NULL; 74 75 /* Mode mask to define the genmsg tasks. */ 76 Mode active_mode = NoMode; 77 78 /* 79 * This flag will be TRUE if a catgets() call is found 80 * in the input file. 81 */ 82 int is_cat_found = FALSE; 83 84 /* Suppress an error message if this flag is TRUE. */ 85 int suppress_error = FALSE; 86 87 /* Prefix and suffix of messages for testing. */ 88 char *premsg = NULL; 89 char *sufmsg = NULL; 90 91 static void usage(void); 92 static void validate_options(void); 93 94 int 95 main(int argc, char **argv) 96 { 97 int c; 98 extern char *optarg; /* from getopt */ 99 extern int optind; /* from getopt */ 100 extern FILE *yyin; /* from lex */ 101 extern int yyparse(void); 102 char *msgfile = NULL; 103 char *projfile = NULL; 104 char *newprojfile = NULL; 105 char *cpppath = NULL; 106 int do_msgfile = FALSE; 107 int tmpfd = -1; 108 109 program = basename(argv[0]); 110 111 (void) setlocale(LC_ALL, ""); 112 (void) textdomain(TEXT_DOMAIN); 113 114 while ((c = getopt(argc, argv, "arndfg:o:l:p:c:s:m:M:txvb")) != EOF) { 115 switch (c) { 116 case 'o': 117 SetActiveMode(MessageMode); 118 msgfile = optarg; 119 break; 120 case 'a': 121 SetActiveMode(AppendMode); 122 break; 123 case 'l': 124 projfile = optarg; 125 SetActiveMode(AutoNumMode); 126 break; 127 case 'r': 128 SetActiveMode(ReverseMode); 129 break; 130 case 'p': 131 cpppath = optarg; 132 SetActiveMode(PreProcessMode); 133 break; 134 case 'g': 135 newprojfile = optarg; 136 suppress_error = TRUE; 137 SetActiveMode(ProjectMode); 138 break; 139 case 'c': 140 mctag = optarg; 141 SetActiveMode(MsgCommentMode); 142 break; 143 case 's': 144 sctag = optarg; 145 SetActiveMode(SetCommentMode); 146 break; 147 case 'b': 148 SetActiveMode(BackCommentMode); 149 break; 150 case 'n': 151 SetActiveMode(LineInfoMode); 152 break; 153 case 'm': 154 premsg = optarg; 155 SetActiveMode(PrefixMode); 156 break; 157 case 'M': 158 sufmsg = optarg; 159 SetActiveMode(SuffixMode); 160 break; 161 case 't': 162 SetActiveMode(TripleMode); 163 break; 164 case 'd': 165 SetActiveMode(DoubleLineMode); 166 break; 167 case 'f': 168 SetActiveMode(OverwriteMode); 169 break; 170 case 'x': 171 suppress_error = TRUE; 172 SetActiveMode(NoErrorMode); 173 break; 174 case 'v': 175 (void) printf("genmsg version %s\n", "%I%"); 176 exit(EXIT_SUCCESS); 177 break; 178 default: 179 usage(); 180 break; 181 } 182 } 183 184 if (optind >= argc) { 185 usage(); 186 } 187 188 validate_options(); 189 190 if (IsActiveMode(AutoNumMode)) { 191 int len; 192 char *tmp; 193 if (read_projfile(projfile)) { 194 tmp = basename(projfile); 195 len = strlen(tmp); 196 if ((newprojfile = malloc(len + sizeof (NEW_SUFFIX))) 197 == NULL) { 198 prg_err(gettext("fatal: out of memory")); 199 exit(EXIT_FAILURE); 200 } 201 (void) sprintf(newprojfile, "%s%s", tmp, NEW_SUFFIX); 202 } else { 203 newprojfile = basename(projfile); 204 } 205 } 206 207 if ((IsActiveMode(AutoNumMode) || IsActiveMode(ProjectMode)) && 208 (is_writable(IsActiveMode(OverwriteMode) ? 209 projfile : newprojfile) == FALSE)) { 210 prg_err(gettext("cannot write \"%s\": permission denied"), 211 IsActiveMode(OverwriteMode) ? projfile : newprojfile); 212 exit(EXIT_FAILURE); 213 } 214 215 if (IsActiveMode(AppendMode) && msgfile) { 216 read_msgfile(msgfile); 217 } 218 219 if (!msgfile) { 220 char *tmp = basename(argv[optind]); 221 int len = strlen(tmp); 222 if ((msgfile = malloc(len + sizeof (MSG_SUFFIX))) 223 == NULL) { 224 prg_err(gettext("fatal: out of memory")); 225 exit(EXIT_FAILURE); 226 } 227 (void) sprintf(msgfile, "%s%s", tmp, MSG_SUFFIX); 228 } 229 230 while (optind < argc) { 231 is_cat_found = FALSE; 232 srcfile = argv[optind]; 233 234 if (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode)) { 235 init_linemsgid(); 236 } 237 238 if (IsActiveMode(PreProcessMode)) { 239 char cmd[MAXPATHLEN]; 240 (void) sprintf(cmd, "%s %s", cpppath, srcfile); 241 if ((yyin = (FILE *) popen(cmd, "r")) == NULL) { 242 prg_err( 243 gettext("fatal: cannot execute \"%s\""), 244 cpppath); 245 exit(EXIT_FAILURE); 246 } 247 } else { 248 if ((yyin = fopen(srcfile, "r")) == NULL) { 249 prg_err(/* stupid cstyle */ 250 gettext("cannot open \"%s\""), srcfile); 251 goto end; 252 } 253 } 254 255 init_lex(); 256 yyparse(); 257 258 if (IsActiveMode(PreProcessMode)) { 259 if (pclose(yyin) != 0) { 260 prg_err(gettext("\"%s\" failed for \"%s\""), 261 cpppath, srcfile); 262 goto end; 263 } 264 } 265 266 if (is_cat_found == FALSE) { 267 if (!IsActiveMode(PreProcessMode)) { 268 (void) fclose(yyin); 269 } 270 goto end; 271 } 272 273 if (!do_msgfile) { 274 do_msgfile = TRUE; 275 } 276 277 if (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode)) { 278 char *tmp = basename(srcfile); 279 char newfile[MAXPATHLEN]; 280 char tmpfile[32]; 281 282 if (IsActiveMode(OverwriteMode)) { 283 (void) sprintf(newfile, "%s", srcfile); 284 } else { 285 (void) sprintf(newfile, "%s%s", 286 tmp, NEW_SUFFIX); 287 } 288 289 if (is_writable(newfile) == FALSE) { 290 prg_err( 291 gettext("cannot create \"%s\": permission denied"), 292 newfile); 293 goto end; 294 } 295 296 (void) sprintf(tmpfile, "%s", "/tmp/gensmg.XXXXXX"); 297 if ((tmpfd = mkstemp(tmpfile)) == -1) { 298 prg_err(/* stupid cstyle */ 299 gettext("cannot create \"%s\""), tmpfile); 300 if (!IsActiveMode(PreProcessMode)) { 301 (void) fclose(yyin); 302 } 303 goto end; 304 } 305 (void) close(tmpfd); 306 if ((newfp = fopen(tmpfile, "w")) == NULL) { 307 prg_err(/* stupid cstyle */ 308 gettext("cannot create \"%s\""), tmpfile); 309 if (!IsActiveMode(PreProcessMode)) { 310 (void) fclose(yyin); 311 } 312 (void) unlink(tmpfile); 313 goto end; 314 } 315 316 if (IsActiveMode(PreProcessMode)) { 317 if ((yyin = fopen(srcfile, "r")) == NULL) { 318 prg_err(/* stupid cstyle */ 319 gettext("cannot open \"%s\""), srcfile); 320 (void) unlink(tmpfile); 321 goto end; 322 } 323 } else { 324 rewind(yyin); 325 } 326 327 SetActiveMode(ReplaceMode); 328 init_lex(); 329 yyparse(); 330 ResetActiveMode(ReplaceMode); 331 332 (void) fclose(newfp); 333 newfp = NULL; 334 335 (void) fclose(yyin); 336 337 (void) file_copy(tmpfile, newfile); 338 339 (void) unlink(tmpfile); 340 341 goto end; 342 } 343 344 if (!IsActiveMode(PreProcessMode)) { 345 (void) fclose(yyin); 346 } 347 348 end: 349 optind++; 350 } 351 352 if (!do_msgfile) { /* no more business. */ 353 return (EXIT_SUCCESS); 354 } 355 356 if (!IsActiveMode(ReverseMode) && !IsActiveMode(ProjectMode)) { 357 write_msgfile(msgfile); 358 } 359 360 if (IsActiveMode(AutoNumMode) || IsActiveMode(ProjectMode)) { 361 write_projfile(IsActiveMode(OverwriteMode) ? 362 projfile : newprojfile); 363 } 364 return (EXIT_SUCCESS); 365 } 366 367 static void 368 validate_options(void) 369 { 370 /* -r doesn't work with either -a or -l. */ 371 if (IsActiveMode(ReverseMode) && 372 (IsActiveMode(AutoNumMode) || IsActiveMode(AppendMode))) { 373 usage(); 374 } 375 /* -b should be accompanied with -c, -s, -d, and -n. */ 376 if (IsActiveMode(BackCommentMode) && 377 (!IsActiveMode(MsgCommentMode) && 378 !IsActiveMode(SetCommentMode) && 379 !IsActiveMode(DoubleLineMode) && 380 !IsActiveMode(LineInfoMode))) { 381 usage(); 382 } 383 if (IsActiveMode(ProjectMode) && 384 (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode) || 385 IsActiveMode(AppendMode) || IsActiveMode(MsgCommentMode) || 386 IsActiveMode(LineInfoMode) || IsActiveMode(OverwriteMode) || 387 IsActiveMode(PrefixMode) || IsActiveMode(SuffixMode) || 388 IsActiveMode(TripleMode) || IsActiveMode(DoubleLineMode) || 389 IsActiveMode(MessageMode) || IsActiveMode(NoErrorMode))) { 390 usage(); 391 } 392 } 393 394 static void 395 usage(void) 396 { 397 (void) fprintf(stderr, 398 gettext("Usage: %s [-o message-file] [-a] [-d] [-p preprocessor]\n" 399 " [-s set-tag] [-c message-tag] [-b] [-n]\n" 400 " [-l project-file] [-r] [-f] [-g project-file]\n" 401 " [-m prefix] [-M suffix] [-t] [-x] files ...\n"), 402 program); 403 exit(EXIT_FAILURE); 404 } 405