10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4933Smuffin * Common Development and Distribution License (the "License"). 6*4933Smuffin * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4933Smuffin * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*4933Smuffin * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <stdio.h> 290Sstevel@tonic-gate #include <limits.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <libgen.h> 330Sstevel@tonic-gate #include <libintl.h> 340Sstevel@tonic-gate #include <locale.h> 350Sstevel@tonic-gate #include <unistd.h> 360Sstevel@tonic-gate #include <sys/param.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include "genmsg.h" 390Sstevel@tonic-gate 400Sstevel@tonic-gate #define MSG_SUFFIX ".msg" 410Sstevel@tonic-gate #define NEW_SUFFIX ".new" 420Sstevel@tonic-gate 430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 440Sstevel@tonic-gate #define TEXT_DOMAIN "genmsg" 450Sstevel@tonic-gate #endif 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * External functions. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate extern void write_msgfile(char *); /* from util.c */ 510Sstevel@tonic-gate extern int read_projfile(char *); /* from util.c */ 520Sstevel@tonic-gate extern void write_projfile(char *); /* from util.c */ 530Sstevel@tonic-gate extern void read_msgfile(char *); /* from util.c */ 540Sstevel@tonic-gate extern int is_writable(char *); /* from util.c */ 550Sstevel@tonic-gate extern int file_copy(char *, char *); /* from util.c */ 560Sstevel@tonic-gate extern void init_lex(void); /* from genmsg.l */ 570Sstevel@tonic-gate extern void init_linemsgid(void); /* from genmsg.l */ 58*4933Smuffin extern FILE *yyin; /* from lex */ 59*4933Smuffin extern int yyparse(void); /* from genmsg.l */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* Program name. */ 620Sstevel@tonic-gate char *program; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* File pointer for auto-message-numbering. */ 650Sstevel@tonic-gate FILE *newfp = NULL; 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* Input source file. */ 680Sstevel@tonic-gate char *srcfile; 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* Tag for message comments. */ 710Sstevel@tonic-gate char *mctag = NULL; 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* Tag for set number comments. */ 740Sstevel@tonic-gate char *sctag = NULL; 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* Mode mask to define the genmsg tasks. */ 770Sstevel@tonic-gate Mode active_mode = NoMode; 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* 800Sstevel@tonic-gate * This flag will be TRUE if a catgets() call is found 810Sstevel@tonic-gate * in the input file. 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate int is_cat_found = FALSE; 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* Suppress an error message if this flag is TRUE. */ 860Sstevel@tonic-gate int suppress_error = FALSE; 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* Prefix and suffix of messages for testing. */ 890Sstevel@tonic-gate char *premsg = NULL; 900Sstevel@tonic-gate char *sufmsg = NULL; 910Sstevel@tonic-gate 920Sstevel@tonic-gate static void usage(void); 930Sstevel@tonic-gate static void validate_options(void); 940Sstevel@tonic-gate 950Sstevel@tonic-gate int 960Sstevel@tonic-gate main(int argc, char **argv) 970Sstevel@tonic-gate { 980Sstevel@tonic-gate int c; 990Sstevel@tonic-gate char *msgfile = NULL; 1000Sstevel@tonic-gate char *projfile = NULL; 1010Sstevel@tonic-gate char *newprojfile = NULL; 1020Sstevel@tonic-gate char *cpppath = NULL; 1030Sstevel@tonic-gate int do_msgfile = FALSE; 1040Sstevel@tonic-gate int tmpfd = -1; 105*4933Smuffin char *cmd, *tmp; 106*4933Smuffin char tmpfile[32]; 107*4933Smuffin size_t len; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate program = basename(argv[0]); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1120Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1130Sstevel@tonic-gate 114*4933Smuffin while ((c = getopt(argc, argv, "arndfg:o:l:p:c:s:m:M:txb")) != EOF) { 1150Sstevel@tonic-gate switch (c) { 1160Sstevel@tonic-gate case 'o': 1170Sstevel@tonic-gate SetActiveMode(MessageMode); 1180Sstevel@tonic-gate msgfile = optarg; 1190Sstevel@tonic-gate break; 1200Sstevel@tonic-gate case 'a': 1210Sstevel@tonic-gate SetActiveMode(AppendMode); 1220Sstevel@tonic-gate break; 1230Sstevel@tonic-gate case 'l': 1240Sstevel@tonic-gate projfile = optarg; 1250Sstevel@tonic-gate SetActiveMode(AutoNumMode); 1260Sstevel@tonic-gate break; 1270Sstevel@tonic-gate case 'r': 1280Sstevel@tonic-gate SetActiveMode(ReverseMode); 1290Sstevel@tonic-gate break; 1300Sstevel@tonic-gate case 'p': 1310Sstevel@tonic-gate cpppath = optarg; 1320Sstevel@tonic-gate SetActiveMode(PreProcessMode); 1330Sstevel@tonic-gate break; 1340Sstevel@tonic-gate case 'g': 1350Sstevel@tonic-gate newprojfile = optarg; 1360Sstevel@tonic-gate suppress_error = TRUE; 1370Sstevel@tonic-gate SetActiveMode(ProjectMode); 1380Sstevel@tonic-gate break; 1390Sstevel@tonic-gate case 'c': 1400Sstevel@tonic-gate mctag = optarg; 1410Sstevel@tonic-gate SetActiveMode(MsgCommentMode); 1420Sstevel@tonic-gate break; 1430Sstevel@tonic-gate case 's': 1440Sstevel@tonic-gate sctag = optarg; 1450Sstevel@tonic-gate SetActiveMode(SetCommentMode); 1460Sstevel@tonic-gate break; 1470Sstevel@tonic-gate case 'b': 1480Sstevel@tonic-gate SetActiveMode(BackCommentMode); 1490Sstevel@tonic-gate break; 1500Sstevel@tonic-gate case 'n': 1510Sstevel@tonic-gate SetActiveMode(LineInfoMode); 1520Sstevel@tonic-gate break; 1530Sstevel@tonic-gate case 'm': 1540Sstevel@tonic-gate premsg = optarg; 1550Sstevel@tonic-gate SetActiveMode(PrefixMode); 1560Sstevel@tonic-gate break; 1570Sstevel@tonic-gate case 'M': 1580Sstevel@tonic-gate sufmsg = optarg; 1590Sstevel@tonic-gate SetActiveMode(SuffixMode); 1600Sstevel@tonic-gate break; 1610Sstevel@tonic-gate case 't': 1620Sstevel@tonic-gate SetActiveMode(TripleMode); 1630Sstevel@tonic-gate break; 1640Sstevel@tonic-gate case 'd': 1650Sstevel@tonic-gate SetActiveMode(DoubleLineMode); 1660Sstevel@tonic-gate break; 1670Sstevel@tonic-gate case 'f': 1680Sstevel@tonic-gate SetActiveMode(OverwriteMode); 1690Sstevel@tonic-gate break; 1700Sstevel@tonic-gate case 'x': 1710Sstevel@tonic-gate suppress_error = TRUE; 1720Sstevel@tonic-gate SetActiveMode(NoErrorMode); 1730Sstevel@tonic-gate break; 1740Sstevel@tonic-gate default: 1750Sstevel@tonic-gate usage(); 1760Sstevel@tonic-gate break; 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (optind >= argc) { 1810Sstevel@tonic-gate usage(); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate validate_options(); 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate if (IsActiveMode(AutoNumMode)) { 1870Sstevel@tonic-gate if (read_projfile(projfile)) { 1880Sstevel@tonic-gate tmp = basename(projfile); 189*4933Smuffin len = strlen(tmp) + sizeof (NEW_SUFFIX); 190*4933Smuffin if ((newprojfile = malloc(len)) == NULL) { 1910Sstevel@tonic-gate prg_err(gettext("fatal: out of memory")); 1920Sstevel@tonic-gate exit(EXIT_FAILURE); 1930Sstevel@tonic-gate } 194*4933Smuffin (void) snprintf(newprojfile, len, "%s%s", 195*4933Smuffin tmp, NEW_SUFFIX); 1960Sstevel@tonic-gate } else { 1970Sstevel@tonic-gate newprojfile = basename(projfile); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate if ((IsActiveMode(AutoNumMode) || IsActiveMode(ProjectMode)) && 202*4933Smuffin (is_writable(IsActiveMode(OverwriteMode) ? 203*4933Smuffin projfile : newprojfile) == FALSE)) { 2040Sstevel@tonic-gate prg_err(gettext("cannot write \"%s\": permission denied"), 205*4933Smuffin IsActiveMode(OverwriteMode) ? projfile : newprojfile); 2060Sstevel@tonic-gate exit(EXIT_FAILURE); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 209*4933Smuffin if (IsActiveMode(AppendMode) && msgfile != NULL) { 2100Sstevel@tonic-gate read_msgfile(msgfile); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 213*4933Smuffin if (msgfile == NULL) { 214*4933Smuffin tmp = basename(argv[optind]); 215*4933Smuffin len = strlen(tmp) + sizeof (MSG_SUFFIX); 216*4933Smuffin if ((msgfile = malloc(len)) == NULL) { 2170Sstevel@tonic-gate prg_err(gettext("fatal: out of memory")); 2180Sstevel@tonic-gate exit(EXIT_FAILURE); 2190Sstevel@tonic-gate } 220*4933Smuffin (void) snprintf(msgfile, len, "%s%s", tmp, MSG_SUFFIX); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate while (optind < argc) { 2240Sstevel@tonic-gate is_cat_found = FALSE; 2250Sstevel@tonic-gate srcfile = argv[optind]; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate if (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode)) { 2280Sstevel@tonic-gate init_linemsgid(); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (IsActiveMode(PreProcessMode)) { 232*4933Smuffin len = strlen(cpppath) + 1 + strlen(srcfile) + 1; 233*4933Smuffin if ((cmd = malloc(len)) == NULL) { 234*4933Smuffin prg_err(gettext("fatal: out of memory")); 2350Sstevel@tonic-gate exit(EXIT_FAILURE); 2360Sstevel@tonic-gate } 237*4933Smuffin (void) snprintf(cmd, len, "%s %s", cpppath, srcfile); 238*4933Smuffin if ((yyin = popen(cmd, "r")) == NULL) { 239*4933Smuffin prg_err( 240*4933Smuffin gettext("fatal: cannot execute \"%s\""), 241*4933Smuffin cpppath); 242*4933Smuffin exit(EXIT_FAILURE); 243*4933Smuffin } 244*4933Smuffin free(cmd); 2450Sstevel@tonic-gate } else { 2460Sstevel@tonic-gate if ((yyin = fopen(srcfile, "r")) == NULL) { 247*4933Smuffin prg_err( 248*4933Smuffin gettext("cannot open \"%s\""), srcfile); 2490Sstevel@tonic-gate goto end; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate init_lex(); 254*4933Smuffin (void) yyparse(); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate if (IsActiveMode(PreProcessMode)) { 2570Sstevel@tonic-gate if (pclose(yyin) != 0) { 2580Sstevel@tonic-gate prg_err(gettext("\"%s\" failed for \"%s\""), 259*4933Smuffin cpppath, srcfile); 2600Sstevel@tonic-gate goto end; 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if (is_cat_found == FALSE) { 2650Sstevel@tonic-gate if (!IsActiveMode(PreProcessMode)) { 2660Sstevel@tonic-gate (void) fclose(yyin); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate goto end; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 271*4933Smuffin if (do_msgfile == FALSE) { 2720Sstevel@tonic-gate do_msgfile = TRUE; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode)) { 276*4933Smuffin char *newfile; 277*4933Smuffin 278*4933Smuffin tmp = basename(srcfile); 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (IsActiveMode(OverwriteMode)) { 281*4933Smuffin newfile = srcfile; 2820Sstevel@tonic-gate } else { 283*4933Smuffin len = strlen(tmp) + sizeof (NEW_SUFFIX); 284*4933Smuffin if ((newfile = malloc(len)) == NULL) { 285*4933Smuffin prg_err( 286*4933Smuffin gettext("fatal: out of memory")); 287*4933Smuffin exit(EXIT_FAILURE); 288*4933Smuffin } 289*4933Smuffin (void) snprintf(newfile, len, "%s%s", 290*4933Smuffin tmp, NEW_SUFFIX); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate if (is_writable(newfile) == FALSE) { 294*4933Smuffin prg_err(gettext( 295*4933Smuffin "cannot create \"%s\": permission denied"), newfile); 2960Sstevel@tonic-gate goto end; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 299*4933Smuffin (void) strlcpy(tmpfile, "/tmp/gensmg.XXXXXX", 300*4933Smuffin sizeof (tmpfile)); 301*4933Smuffin 3020Sstevel@tonic-gate if ((tmpfd = mkstemp(tmpfile)) == -1) { 303*4933Smuffin prg_err(gettext( 304*4933Smuffin "cannot create \"%s\""), tmpfile); 3050Sstevel@tonic-gate if (!IsActiveMode(PreProcessMode)) { 3060Sstevel@tonic-gate (void) fclose(yyin); 3070Sstevel@tonic-gate } 308*4933Smuffin goto end; 3090Sstevel@tonic-gate } 310*4933Smuffin if ((newfp = fdopen(tmpfd, "w")) == NULL) { 311*4933Smuffin prg_err(gettext( 312*4933Smuffin "cannot create \"%s\""), tmpfile); 3130Sstevel@tonic-gate if (!IsActiveMode(PreProcessMode)) { 3140Sstevel@tonic-gate (void) fclose(yyin); 3150Sstevel@tonic-gate } 316*4933Smuffin (void) close(tmpfd); 3170Sstevel@tonic-gate (void) unlink(tmpfile); 3180Sstevel@tonic-gate goto end; 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate if (IsActiveMode(PreProcessMode)) { 3220Sstevel@tonic-gate if ((yyin = fopen(srcfile, "r")) == NULL) { 323*4933Smuffin prg_err(gettext( 324*4933Smuffin "cannot open \"%s\""), srcfile); 325*4933Smuffin (void) fclose(newfp); 3260Sstevel@tonic-gate (void) unlink(tmpfile); 3270Sstevel@tonic-gate goto end; 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate } else { 3300Sstevel@tonic-gate rewind(yyin); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate SetActiveMode(ReplaceMode); 3340Sstevel@tonic-gate init_lex(); 335*4933Smuffin (void) yyparse(); 3360Sstevel@tonic-gate ResetActiveMode(ReplaceMode); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate (void) fclose(newfp); 3390Sstevel@tonic-gate newfp = NULL; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate (void) fclose(yyin); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate (void) file_copy(tmpfile, newfile); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate (void) unlink(tmpfile); 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate goto end; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate if (!IsActiveMode(PreProcessMode)) { 3510Sstevel@tonic-gate (void) fclose(yyin); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate end: 3550Sstevel@tonic-gate optind++; 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if (!do_msgfile) { /* no more business. */ 3590Sstevel@tonic-gate return (EXIT_SUCCESS); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (!IsActiveMode(ReverseMode) && !IsActiveMode(ProjectMode)) { 3630Sstevel@tonic-gate write_msgfile(msgfile); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate if (IsActiveMode(AutoNumMode) || IsActiveMode(ProjectMode)) { 3670Sstevel@tonic-gate write_projfile(IsActiveMode(OverwriteMode) ? 368*4933Smuffin projfile : newprojfile); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate return (EXIT_SUCCESS); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate static void 3740Sstevel@tonic-gate validate_options(void) 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate /* -r doesn't work with either -a or -l. */ 3770Sstevel@tonic-gate if (IsActiveMode(ReverseMode) && 378*4933Smuffin (IsActiveMode(AutoNumMode) || IsActiveMode(AppendMode))) { 3790Sstevel@tonic-gate usage(); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate /* -b should be accompanied with -c, -s, -d, and -n. */ 3820Sstevel@tonic-gate if (IsActiveMode(BackCommentMode) && 383*4933Smuffin (!IsActiveMode(MsgCommentMode) && 384*4933Smuffin !IsActiveMode(SetCommentMode) && 385*4933Smuffin !IsActiveMode(DoubleLineMode) && 386*4933Smuffin !IsActiveMode(LineInfoMode))) { 3870Sstevel@tonic-gate usage(); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate if (IsActiveMode(ProjectMode) && 390*4933Smuffin (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode) || 391*4933Smuffin IsActiveMode(AppendMode) || IsActiveMode(MsgCommentMode) || 392*4933Smuffin IsActiveMode(LineInfoMode) || IsActiveMode(OverwriteMode) || 393*4933Smuffin IsActiveMode(PrefixMode) || IsActiveMode(SuffixMode) || 394*4933Smuffin IsActiveMode(TripleMode) || IsActiveMode(DoubleLineMode) || 395*4933Smuffin IsActiveMode(MessageMode) || IsActiveMode(NoErrorMode))) { 3960Sstevel@tonic-gate usage(); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate static void 4010Sstevel@tonic-gate usage(void) 4020Sstevel@tonic-gate { 403*4933Smuffin (void) fprintf(stderr, gettext( 404*4933Smuffin "Usage: %s [-o message-file] [-a] [-d] [-p preprocessor]\n" 405*4933Smuffin " [-s set-tag] [-c message-tag] [-b] [-n]\n" 406*4933Smuffin " [-l project-file] [-r] [-f] [-g project-file]\n" 407*4933Smuffin " [-m prefix] [-M suffix] [-t] [-x] files ...\n"), 408*4933Smuffin program); 4090Sstevel@tonic-gate exit(EXIT_FAILURE); 4100Sstevel@tonic-gate } 411