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