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