1 /*
2  * Convert Apple .strings file (UTF-16 BE text file) to GNU gettext .po files.
3  *
4  * Copyright 2007-2014 by Apple Inc.
5  *
6  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
7  *
8  * Usage:
9  *
10  *   strings2po filename.strings filename.po
11  *
12  * Compile with:
13  *
14  *   gcc -o strings2po strings2po.c
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 
20 
21 /*
22  * The .strings file format is simple:
23  *
24  * // comment
25  * "id" = "str";
26  *
27  * Both the id and str strings use standard C quoting for special characters
28  * like newline and the double quote character.
29  */
30 
31 /*
32  * Local functions...
33  */
34 
35 static int	read_strings(FILE *strings, char *buffer, size_t bufsize,
36 		             char **id, char **str);
37 static void	write_po(FILE *po, const char *what, const char *s);
38 
39 
40 /*
41  *   main() - Convert .strings file to .po.
42  */
43 
44 int					/* O - Exit code */
main(int argc,char * argv[])45 main(int  argc,				/* I - Number of command-line args */
46      char *argv[])			/* I - Command-line arguments */
47 {
48   FILE	*strings,			/* .strings file */
49 	*po;				/* .po file */
50   char	iconv[1024],			/* iconv command */
51 	buffer[8192],			/* Line buffer */
52 	*id,				/* ID string */
53 	*str;				/* Translation string */
54   int	count;				/* Number of messages converted */
55 
56 
57   if (argc != 3)
58   {
59     puts("Usage: strings2po filename.strings filename.po");
60     return (1);
61   }
62 
63  /*
64   * Cheat by using iconv to convert the .strings file from UTF-16 to UTF-8
65   * which is what we need for the .po file (and it makes things a lot
66   * simpler...)
67   */
68 
69   snprintf(iconv, sizeof(iconv), "iconv -f utf-16 -t utf-8 '%s'", argv[1]);
70   if ((strings = popen(iconv, "r")) == NULL)
71   {
72     perror(argv[1]);
73     return (1);
74   }
75 
76   if ((po = fopen(argv[2], "w")) == NULL)
77   {
78     perror(argv[2]);
79     pclose(strings);
80     return (1);
81   }
82 
83   count = 0;
84 
85   while (read_strings(strings, buffer, sizeof(buffer), &id, &str))
86   {
87     count ++;
88     write_po(po, "msgid", id);
89     write_po(po, "msgstr", str);
90   }
91 
92   pclose(strings);
93   fclose(po);
94 
95   printf("%s: %d messages.\n", argv[2], count);
96 
97   return (0);
98 }
99 
100 
101 /*
102  * 'read_strings()' - Read a line from a .strings file.
103  */
104 
105 static int				/* O - 1 on success, 0 on failure */
read_strings(FILE * strings,char * buffer,size_t bufsize,char ** id,char ** str)106 read_strings(FILE   *strings,		/* I - .strings file */
107              char   *buffer,		/* I - Line buffer */
108 	     size_t bufsize,		/* I - Size of line buffer */
109              char   **id,		/* O - Pointer to ID string */
110 	     char   **str)		/* O - Pointer to translation string */
111 {
112   char	*bufptr;			/* Pointer into buffer */
113 
114 
115   while (fgets(buffer, (int)bufsize, strings))
116   {
117     if (buffer[0] != '\"')
118       continue;
119 
120     *id = buffer + 1;
121 
122     for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++)
123       if (*bufptr == '\\')
124         bufptr ++;
125 
126     if (*bufptr != '\"')
127       continue;
128 
129     *bufptr++ = '\0';
130 
131     while (*bufptr && *bufptr != '\"')
132       bufptr ++;
133 
134     if (!*bufptr)
135       continue;
136 
137     bufptr ++;
138     *str = bufptr;
139 
140     for (; *bufptr && *bufptr != '\"'; bufptr ++)
141       if (*bufptr == '\\')
142         bufptr ++;
143 
144     if (*bufptr != '\"')
145       continue;
146 
147     *bufptr = '\0';
148 
149     return (1);
150   }
151 
152   return (0);
153 }
154 
155 
156 /*
157  * 'write_po()' - Write a line to the .po file.
158  */
159 
160 static void
write_po(FILE * po,const char * what,const char * s)161 write_po(FILE       *po,		/* I - .po file */
162          const char *what,		/* I - Type of string */
163 	 const char *s)			/* I - String to write */
164 {
165   fprintf(po, "%s \"%s\"\n", what, s);
166 }
167