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