1/* 2 * "$Id: po2strings.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * Convert a GNU gettext .po file to an Apple .strings file. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * 8 * These coded instructions, statements, and computer programs are the 9 * property of Apple Inc. and are protected by Federal copyright 10 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 11 * which should have been included with this file. If this file is 12 * file is missing or damaged, see the license at "http://www.cups.org/". 13 * 14 * Usage: 15 * 16 * po2strings filename.strings filename.po 17 * 18 * Compile with: 19 * 20 * gcc -o po2strings po2strings.c `cups-config --libs` 21 */ 22 23#include <cups/cups-private.h> 24 25 26/* 27 * The .strings file format is simple: 28 * 29 * // comment 30 * "msgid" = "msgstr"; 31 * 32 * The GNU gettext .po format is also fairly simple: 33 * 34 * #. comment 35 * msgid "some text" 36 * msgstr "localized text" 37 * 38 * The comment, msgid, and msgstr text can span multiple lines using the form: 39 * 40 * #. comment 41 * #. more comments 42 * msgid "" 43 * "some long text" 44 * msgstr "" 45 * "localized text spanning " 46 * "multiple lines" 47 * 48 * Both the msgid and msgstr strings use standard C quoting for special 49 * characters like newline and the double quote character. 50 */ 51 52/* 53 * main() - Convert .po file to .strings. 54 */ 55 56int /* O - Exit code */ 57main(int argc, /* I - Number of command-line args */ 58 char *argv[]) /* I - Command-line arguments */ 59{ 60 int i; /* Looping var */ 61 const char *pofile, /* .po filename */ 62 *stringsfile; /* .strings filename */ 63 cups_file_t *po, /* .po file */ 64 *strings; /* .strings file */ 65 char s[4096], /* String buffer */ 66 *ptr, /* Pointer into buffer */ 67 *temp, /* New string */ 68 *msgid, /* msgid string */ 69 *msgstr; /* msgstr string */ 70 size_t length; /* Length of combined strings */ 71 int use_msgid; /* Use msgid strings for msgstr? */ 72 73 74 /* 75 * Process command-line arguments... 76 */ 77 78 pofile = NULL; 79 stringsfile = NULL; 80 use_msgid = 0; 81 82 for (i = 1; i < argc; i ++) 83 { 84 if (!strcmp(argv[i], "-m")) 85 use_msgid = 1; 86 else if (argv[i][0] == '-') 87 { 88 puts("Usage: po2strings [-m] filename.po filename.strings"); 89 return (1); 90 } 91 else if (!pofile) 92 pofile = argv[i]; 93 else if (!stringsfile) 94 stringsfile = argv[i]; 95 else 96 { 97 puts("Usage: po2strings [-m] filename.po filename.strings"); 98 return (1); 99 } 100 } 101 102 if (!pofile || !stringsfile) 103 { 104 puts("Usage: po2strings [-m] filename.po filename.strings"); 105 return (1); 106 } 107 108 /* 109 * Read strings from the .po file and write to the .strings file... 110 */ 111 112 if ((po = cupsFileOpen(pofile, "r")) == NULL) 113 { 114 perror(pofile); 115 return (1); 116 } 117 118 if ((strings = cupsFileOpen(stringsfile, "w")) == NULL) 119 { 120 perror(stringsfile); 121 cupsFileClose(po); 122 return (1); 123 } 124 125 msgid = msgstr = NULL; 126 127 while (cupsFileGets(po, s, sizeof(s)) != NULL) 128 { 129 if (s[0] == '#' && s[1] == '.') 130 { 131 /* 132 * Copy comment string... 133 */ 134 135 if (msgid && msgstr) 136 { 137 /* 138 * First output the last localization string... 139 */ 140 141 if (*msgid) 142 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, 143 (use_msgid || !*msgstr) ? msgid : msgstr); 144 145 free(msgid); 146 free(msgstr); 147 msgid = msgstr = NULL; 148 } 149 150 cupsFilePrintf(strings, "//%s\n", s + 2); 151 } 152 else if (s[0] == '#' || !s[0]) 153 { 154 /* 155 * Skip blank and file comment lines... 156 */ 157 158 continue; 159 } 160 else 161 { 162 /* 163 * Strip the trailing quote... 164 */ 165 166 if ((ptr = strrchr(s, '\"')) == NULL) 167 continue; 168 169 *ptr = '\0'; 170 171 /* 172 * Find start of value... 173 */ 174 175 if ((ptr = strchr(s, '\"')) == NULL) 176 continue; 177 178 ptr ++; 179 180 /* 181 * Create or add to a message... 182 */ 183 184 if (!strncmp(s, "msgid", 5)) 185 { 186 /* 187 * Output previous message as needed... 188 */ 189 190 if (msgid && msgstr) 191 { 192 if (*msgid) 193 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, 194 (use_msgid || !*msgstr) ? msgid : msgstr); 195 } 196 197 if (msgid) 198 free(msgid); 199 200 if (msgstr) 201 free(msgstr); 202 203 msgid = strdup(ptr); 204 msgstr = NULL; 205 } 206 else if (s[0] == '\"' && (msgid || msgstr)) 207 { 208 /* 209 * Append to current string... 210 */ 211 212 size_t ptrlen = strlen(ptr); /* Length of string */ 213 214 length = strlen(msgstr ? msgstr : msgid); 215 216 if ((temp = realloc(msgstr ? msgstr : msgid, 217 length + ptrlen + 1)) == NULL) 218 { 219 free(msgid); 220 if (msgstr) 221 free(msgstr); 222 perror("Unable to allocate string"); 223 return (1); 224 } 225 226 if (msgstr) 227 { 228 /* 229 * Copy the new portion to the end of the msgstr string - safe 230 * to use strcpy because the buffer is allocated to the correct 231 * size... 232 */ 233 234 msgstr = temp; 235 236 memcpy(msgstr + length, ptr, ptrlen + 1); 237 } 238 else 239 { 240 /* 241 * Copy the new portion to the end of the msgid string - safe 242 * to use strcpy because the buffer is allocated to the correct 243 * size... 244 */ 245 246 msgid = temp; 247 248 memcpy(msgid + length, ptr, ptrlen + 1); 249 } 250 } 251 else if (!strncmp(s, "msgstr", 6) && msgid) 252 { 253 /* 254 * Set the string... 255 */ 256 257 if (msgstr) 258 free(msgstr); 259 260 if ((msgstr = strdup(ptr)) == NULL) 261 { 262 free(msgid); 263 perror("Unable to allocate msgstr"); 264 return (1); 265 } 266 } 267 } 268 } 269 270 if (msgid && msgstr) 271 { 272 if (*msgid) 273 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, 274 (use_msgid || !*msgstr) ? msgid : msgstr); 275 } 276 277 if (msgid) 278 free(msgid); 279 280 if (msgstr) 281 free(msgstr); 282 283 cupsFileClose(po); 284 cupsFileClose(strings); 285 286 return (0); 287} 288 289 290/* 291 * End of "$Id: po2strings.c 11560 2014-02-06 20:10:19Z msweet $". 292 */ 293