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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 /* 34 * Create message files in a specific format. 35 * the gettxt message retrieval function must know the format of 36 * the data file created by this utility. 37 * 38 * FORMAT OF MESSAGE FILES 39 40 __________________________ 41 | Number of messages | 42 -------------------------- 43 | offset to the 1st mesg | 44 -------------------------- 45 | offset to the 2nd mesg | 46 -------------------------- 47 | offset to the 3rd mesg | 48 -------------------------- 49 | . | 50 | . | 51 | . | 52 -------------------------- 53 | offset to the nth mesg | 54 -------------------------- 55 | message #1 56 -------------------------- 57 | message #2 58 -------------------------- 59 | message #3 60 -------------------------- 61 . 62 . 63 . 64 -------------------------- 65 | message #n 66 -------------------------- 67 * 68 */ 69 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <unistd.h> 73 #include <string.h> 74 #include <sys/types.h> 75 #include <sys/stat.h> 76 #include <signal.h> 77 #include <errno.h> 78 #include <libgen.h> 79 80 /* 81 * Definitions 82 */ 83 84 #define LINESZ 2048 /* max line in input base */ 85 #define STDERR 2 86 #define P_locale "/usr/lib/locale/" /* locale info directory */ 87 #define L_locale sizeof(P_locale) 88 #define MESSAGES "/LC_MESSAGES/" /* messages category */ 89 90 /* 91 * internal functions 92 */ 93 94 static char *syserr(void); /* Returns description of error */ 95 static void usage(void); /* Displays valid invocations */ 96 static int mymkdir(char *); /* Creates sub-directories */ 97 static void clean(int); /* removes work file */ 98 99 /* 100 * static variables 101 */ 102 103 static char *cmdname; /* Last qualifier of arg0 */ 104 static char *workp; /* name of the work file */ 105 106 int 107 main(argc, argv) 108 int argc; 109 char *argv[]; 110 { 111 int c; /* contains option letter */ 112 char *ifilep; /* input file name */ 113 char *ofilep; /* output file name */ 114 char *localep; /* locale name */ 115 char *localedirp; /* full-path name of parent directory 116 * of the output file */ 117 char *outfilep; /* full-path name of output file */ 118 FILE *fp_inp; /* input file FILE pointer */ 119 FILE *fp_outp; /* output file FILE pointer */ 120 char *bufinp, *bufworkp; /* pointers to input and work areas */ 121 int *bufoutp; /* pointer to the output area */ 122 char *msgp; /* pointer to the a message */ 123 int num_msgs; /* number of messages in input file */ 124 int iflag; /* -i option was specified */ 125 int oflag; /* -o option was slecified */ 126 int nitems; /* number of bytes to write */ 127 char *pathoutp; /* full-path name of output file */ 128 struct stat buf; /* buffer to stat the work file */ 129 unsigned size; /* used for argument to malloc */ 130 int i; 131 132 /* Initializations */ 133 134 localep = (char *)NULL; 135 num_msgs = 0; 136 iflag = 0; 137 oflag = 0; 138 139 /* Get name of command */ 140 141 if (cmdname = strrchr(argv[0], '/')) 142 ++cmdname; 143 else 144 cmdname = argv[0]; 145 146 /* Check for invalid number of arguments */ 147 148 if (argc < 3 && argc > 6) 149 usage(); 150 151 /* Get command line options */ 152 153 while ((c = getopt(argc, argv, "oi:")) != EOF) { 154 switch (c) { 155 case 'o': 156 oflag++; 157 break; 158 case 'i': 159 iflag++; 160 localep = optarg; 161 break; 162 case '?': 163 usage(); 164 break; 165 } 166 } 167 168 /* Initialize pointers to input and output file names */ 169 170 ifilep = argv[optind]; 171 ofilep = argv[optind + 1]; 172 173 /* check for invalid invocations */ 174 175 if (iflag && oflag && argc != 6) 176 usage(); 177 if (iflag && ! oflag && argc != 5) 178 usage(); 179 if (! iflag && oflag && argc != 4) 180 usage(); 181 if (! iflag && ! oflag && argc != 3) 182 usage(); 183 184 /* Construct a full-path to the output file */ 185 186 if (localep) { 187 size = L_locale + strlen(localep) + 188 sizeof(MESSAGES) + strlen(ofilep); 189 if ((pathoutp = malloc(2 * (size + 1))) == NULL) { 190 (void)fprintf(stderr, "%s: malloc error (size = %d)\n", 191 cmdname, size); 192 exit(1); 193 } 194 localedirp = pathoutp + size + 1; 195 (void)strcpy(pathoutp, P_locale); 196 (void)strcpy(&pathoutp[L_locale - 1], localep); 197 (void)strcat(pathoutp, MESSAGES); 198 (void)strcpy(localedirp, pathoutp); 199 (void)strcat(pathoutp, ofilep); 200 } 201 202 /* Check for overwrite error conditions */ 203 204 if (! oflag) { 205 if (iflag) { 206 if (access(pathoutp, 0) == 0) { 207 (void)fprintf(stderr, "%s: Message file \"%s\" already exists;\ndid not overwrite it\n", cmdname, pathoutp); 208 if (localep) 209 free(pathoutp); 210 exit(1); 211 } 212 } 213 else 214 if (access(ofilep, 0) == 0) { 215 (void)fprintf(stderr, "%s: Message file \"%s\" already exists;\ndid not overwrite it\n", cmdname, ofilep); 216 if (localep) 217 free(pathoutp); 218 exit(1); 219 } 220 } 221 222 /* Open input file */ 223 if ((fp_inp = fopen(ifilep, "r")) == NULL) { 224 (void)fprintf(stderr, "%s: %s: %s\n", 225 cmdname, ifilep, syserr()); 226 exit(1); 227 } 228 229 /* Allocate buffer for input and work areas */ 230 231 if ((bufinp = malloc(2 * LINESZ)) == NULL) { 232 (void)fprintf(stderr, "%s: malloc error (size = %d)\n", 233 cmdname, 2 * LINESZ); 234 exit(1); 235 } 236 bufworkp = bufinp + LINESZ; 237 238 if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 239 (void)sigset(SIGINT, clean); 240 241 /* Open work file */ 242 243 workp = tempnam(".", "xx"); 244 if ((fp_outp = fopen(workp, "a+")) == NULL) { 245 (void)fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr()); 246 if (localep) 247 free(pathoutp); 248 free(bufinp); 249 exit(1); 250 } 251 252 /* Search for C-escape sequences in input file and 253 * replace them by the appropriate characters. 254 * The modified lines are copied to the work area 255 * and written to the work file */ 256 257 for(;;) { 258 if (!fgets(bufinp, LINESZ, fp_inp)) { 259 if (!feof(fp_inp)) { 260 (void)fprintf(stderr,"%s: %s: %s\n", 261 cmdname, ifilep, syserr()); 262 free(bufinp); 263 if (localep) 264 free(pathoutp); 265 exit(1); 266 } 267 break; 268 } 269 if(*(bufinp+strlen(bufinp)-1) != '\n') { 270 (void)fprintf(stderr, "%s: %s: data base file: error on line %d\n", cmdname, ifilep, num_msgs); 271 free(bufinp); 272 exit(1); 273 } 274 *(bufinp + strlen(bufinp) -1) = (char)0; /* delete newline */ 275 num_msgs++; 276 (void)strccpy(bufworkp, bufinp); 277 nitems = strlen(bufworkp) + 1; 278 if (fwrite(bufworkp, sizeof(*bufworkp), nitems, fp_outp) != nitems) { 279 (void)fprintf(stderr, "%s: %s: %s\n", 280 cmdname, workp, syserr()); 281 exit(1); 282 } 283 } 284 free(bufinp); 285 (void)fclose(fp_outp); 286 287 /* Open and stat the work file */ 288 289 if ((fp_outp = fopen(workp, "r")) == NULL) { 290 (void)fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr()); 291 exit(1); 292 } 293 if ((stat(workp, &buf)) != 0) { 294 (void)fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr()); 295 } 296 297 /* Find the size of the output message file 298 * and copy the control information and the messages 299 * to the output file */ 300 301 size = sizeof(int) + num_msgs * sizeof(int) + buf.st_size; 302 303 if ( (bufoutp = (int *)malloc((uint)size)) == NULL ) { 304 (void)fprintf(stderr, "%s: malloc error (size = %d)\n", 305 cmdname, size); 306 exit(1); 307 } 308 bufinp = (char *)bufoutp; 309 if ( (fread(bufinp + sizeof(int) + num_msgs * sizeof(int), sizeof(*bufinp), buf.st_size, fp_outp)) != buf.st_size ) { 310 free(bufinp); 311 (void) fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr()); 312 } 313 (void) fclose(fp_outp); 314 (void) unlink(workp); 315 free(workp); 316 msgp = bufinp + sizeof(int) + num_msgs * sizeof(int); 317 *bufoutp = num_msgs; 318 *(bufoutp + 1) = (bufinp + sizeof(int) + num_msgs * sizeof(int)) - bufinp; 319 320 for(i = 2; i <= num_msgs; i++) { 321 *(bufoutp + i) = (msgp + strlen(msgp) + 1) - bufinp; 322 msgp = msgp + strlen(msgp) + 1; 323 } 324 325 if (iflag) { 326 outfilep = pathoutp; 327 if (mymkdir(localedirp) == 0) { 328 free(bufinp); 329 if (localep) 330 free(pathoutp); 331 exit(1); 332 } 333 } 334 else 335 outfilep = ofilep; 336 337 if ((fp_outp = fopen(outfilep, "w")) == NULL) { 338 (void)fprintf(stderr, "%s: %s: %s\n", 339 cmdname, outfilep, syserr()); 340 free(bufinp); 341 if (localep) 342 free(pathoutp); 343 exit(1); 344 } 345 346 if (fwrite((char *)bufinp, sizeof(*bufinp), size, fp_outp) != size) { 347 (void)fprintf(stderr, "%s: %s: %s\n", 348 cmdname, ofilep, syserr()); 349 free(bufinp); 350 if (localep) 351 free(pathoutp); 352 exit(1); 353 } 354 free(bufinp); 355 if (localep) 356 free(pathoutp); 357 return (0); 358 } 359 360 /* 361 * syserr() 362 * 363 * Return a pointer to a system error message. 364 */ 365 static char * 366 syserr() 367 { 368 return (strerror(errno)); 369 } 370 371 static void 372 usage() 373 { 374 (void)fprintf(stderr, "Usage: %s [-o] inputstrings outputmsgs\n", 375 cmdname); 376 (void)fprintf(stderr, " %s [-o] [-i locale] inputstrings outputmsgs\n", cmdname); 377 exit(1); 378 } 379 380 static int 381 mymkdir(localdir) 382 char *localdir; 383 { 384 char *dirp; 385 char *s1 = localdir; 386 char *path; 387 388 if ((path = malloc(strlen(localdir)+1)) == NULL) 389 return(0); 390 *path = '\0'; 391 while( (dirp = strtok(s1, "/")) != NULL ) { 392 s1 = (char *)NULL; 393 (void)strcat(path, "/"); 394 (void)strcat(path, dirp); 395 if (access(path, 3) == 0) 396 continue; 397 if (mkdir(path, 0777) == -1) { 398 (void)fprintf(stderr, "%s: %s: %s\n", 399 cmdname, path, syserr()); 400 free(path); 401 return(0); 402 } 403 } 404 free(path); 405 return(1); 406 } 407 408 /* ARGSUSED */ 409 static void 410 clean(int sig) 411 { 412 (void)sigset(SIGINT, SIG_IGN); 413 if (workp) 414 (void) unlink(workp); 415 exit(1); 416 } 417 418