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