ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/lang/langcomp.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (9 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 9094 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Compiler for language definition files.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 /*
11 * A language definition file contains all strings which Services sends to
12 * users in a particular language. A language file may contain comments
13 * (lines beginning with "#"--note that inline comments are not allowed!)
14 * and blank lines. All other lines must adhere to the following format:
15 *
16 * Each string definition begins with the C name of a message (as defined
17 * in the file "index"--see below). This must be alone on a line, preceded
18 * and followed by no blank space. Following this line are zero or more
19 * lines of text; each line of text must begin with exactly one tab
20 * character, which is discarded. Newlines are retained in the strings,
21 * except the last newline in the text, which is discarded. A message with
22 * no text is replaced by a null pointer in the array (not an empty
23 * string).
24 *
25 * All messages in the program are listed, one per line, in the "index"
26 * file. No comments or blank lines are permitted in that file. The index
27 * file can be generated from a language file with a command like:
28 * grep '^[A-Z]' en_us.l >index
29 *
30 * This program takes one parameter, the name of the language file. It
31 * generates a compiled language file whose name is created by removing any
32 * extension on the source file on the input filename.
33 *
34 * You may also pass a "-w" option to print warnings for missing strings.
35 *
36 * This program isn't very flexible, because it doesn't need to be, but
37 * anyone who wants to try making it more flexible is welcome to.
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 /* CR/LF values--used instead of '\r' and '\n' to avoid platform-dependent
46 * messiness */
47 #define CR ((char)13)
48 #define LF ((char)10)
49
50 int numstrings = 0; /* Number of strings we should have */
51 char **stringnames; /* Names of the strings (from index file) */
52 char **strings; /* Strings we have loaded */
53
54 int linenum = 0; /* Current line number in input file */
55
56 /*************************************************************************/
57
58 /* Read the index file and load numstrings and stringnames. Return -1 on
59 * error, 0 on success. */
60
61 static int read_index_file(void)
62 {
63 FILE *f;
64 char buf[256];
65 int i;
66
67 if (!(f = fopen("index", "r"))) {
68 perror("fopen(index)");
69 return -1;
70 }
71 while (fgets(buf, sizeof(buf), f))
72 numstrings++;
73 if (!(stringnames = calloc(sizeof(char *), numstrings))) {
74 perror("calloc(stringnames)");
75 return -1;
76 }
77 if (!(strings = calloc(sizeof(char *), numstrings))) {
78 perror("calloc(strings)");
79 return -1;
80 }
81 fseek(f, 0, SEEK_SET);
82 i = 0;
83 while (fgets(buf, sizeof(buf), f)) {
84 if (buf[strlen(buf)-1] == LF)
85 buf[strlen(buf)-1] = 0;
86 if (buf[strlen(buf)-1] == CR)
87 buf[strlen(buf)-1] = 0;
88 if (!(stringnames[i++] = strdup(buf))) {
89 perror("strdup()");
90 return -1;
91 }
92 }
93 fclose(f);
94 return 0;
95 }
96
97 /*************************************************************************/
98
99 /* Return the index of a string name in stringnames, or -1 if not found. */
100
101 static int stringnum(const char *name)
102 {
103 int i;
104
105 for (i = 0; i < numstrings; i++) {
106 if (strcmp(stringnames[i], name) == 0)
107 return i;
108 }
109 return -1;
110 }
111
112 /*************************************************************************/
113
114 /* Read a non-comment, non-blank line from the input file. Return NULL at
115 * end of file. */
116
117 static char *readline(FILE *f)
118 {
119 static char buf[1024];
120 char *s;
121
122 do {
123 if (!(fgets(buf, sizeof(buf), f)))
124 return NULL;
125 linenum++;
126 } while (*buf == '#' || *buf == CR || *buf == LF);
127 s = buf + strlen(buf)-1;
128 if (*s == LF)
129 *s-- = 0;
130 if (*s == CR)
131 *s = 0;
132 return buf;
133 }
134
135 /*************************************************************************/
136
137 /* Write a 32-bit value to a file in big-endian order. Returns 0 on
138 * success, -1 on error.
139 */
140
141 static int fput32(long val, FILE *f)
142 {
143 if (fputc(val>>24, f) == EOF ||
144 fputc(val>>16, f) == EOF ||
145 fputc(val>> 8, f) == EOF ||
146 fputc(val , f) == EOF
147 ) {
148 return -1;
149 } else {
150 return 0;
151 }
152 }
153
154 /*************************************************************************/
155
156 int main(int ac, char **av)
157 {
158 char *filename = NULL, *s;
159 char langname[254], outfile[256];
160 FILE *in, *out;
161 int warn = 0;
162 int retval = 0;
163 int curstring = -2, i;
164 char *line;
165 int maxerr = 50; /* Max errors before we bail out */
166 long pos, totalsize;
167
168 if (ac >= 2 && strcmp(av[1], "-w") == 0) {
169 warn = 1;
170 av[1] = av[2];
171 ac--;
172 }
173 if (ac != 2) {
174 fprintf(stderr, "Usage: %s [-w] <lang-file>\n", av[0]);
175 return 1;
176 }
177 filename = av[1];
178 s = strrchr(filename, '.');
179 if (!s)
180 s = filename + strlen(filename);
181 if (s-filename > sizeof(langname)-3)
182 s = filename + sizeof(langname)-1;
183 strncpy(langname, filename, s-filename);
184 langname[s-filename] = 0;
185 sprintf(outfile, "%s", langname);
186
187 if (read_index_file() < 0)
188 return 1;
189 if (!(in = fopen(filename, "r"))) {
190 perror(filename);
191 return 1;
192 }
193 if (!(out = fopen(outfile, "w"))) {
194 perror(outfile);
195 return 1;
196 }
197
198 while (maxerr > 0 && (line = readline(in)) != NULL) {
199 if (*line == '\t') {
200 if (curstring == -2) {
201 fprintf(stderr, "%s:%d: Junk at beginning of file\n",
202 filename, linenum);
203 retval = 1;
204 } else if (curstring >= 0) {
205 line++;
206 i = strings[curstring] ? strlen(strings[curstring]) : 0;
207 if (!(strings[curstring] =
208 realloc(strings[curstring], i+strlen(line)+2))) {
209 fprintf(stderr, "%s:%d: Out of memory!\n",
210 filename, linenum);
211 return 2;
212 }
213 sprintf(strings[curstring]+i, "%s\n", line);
214 }
215
216 } else {
217 if ((curstring = stringnum(line)) < 0) {
218 fprintf(stderr, "%s:%d: Unknown string name `%s'\n",
219 filename, linenum, line);
220 retval = 1;
221 maxerr--;
222 } else if (strings[curstring]) {
223 fprintf(stderr, "%s:%d: Duplicate occurrence of string `%s'\n",
224 filename, linenum, line);
225 retval = 1;
226 maxerr--;
227 } else {
228 if (!(strings[curstring] = malloc(1))) {
229 fprintf(stderr, "%s:%d: Out of memory!\n",
230 filename, linenum);
231 return 2;
232 }
233 *strings[curstring] = 0;
234 }
235
236 }
237 }
238
239 fclose(in);
240
241 if (retval != 0) {
242 if (maxerr == 0)
243 fprintf(stderr, "%s:%d: Too many errors!\n", filename, linenum);
244 fclose(out);
245 unlink(outfile);
246 return retval;
247 }
248
249 totalsize = 0;
250 for (i = 0; i < numstrings; i++) {
251 if (strings[i]) {
252 if (*strings[i])
253 strings[i][strlen(strings[i])-1] = 0; /* kill last \n */
254 if (*strings[i])
255 totalsize += strlen(strings[i]) + 1;
256 } else if (warn) {
257 fprintf(stderr, "%s: String `%s' missing\n", filename,
258 stringnames[i]);
259 }
260 }
261
262 if (fput32(numstrings, out) < 0 || fput32(totalsize, out) < 0) {
263 perror("fwrite()");
264 retval = 1;
265 }
266 for (i = 0; i < numstrings && retval == 0; i++) {
267 if (strings[i] && *strings[i]) {
268 if (fwrite(strings[i], strlen(strings[i])+1, 1, out) != 1) {
269 perror("fwrite()");
270 retval = 1;
271 }
272 }
273 }
274 pos = 0;
275 for (i = 0; i < numstrings && retval == 0; i++) {
276 if (strings[i] && *strings[i]) {
277 if (fput32(pos, out) < 0) {
278 perror("fwrite()");
279 retval = 1;
280 }
281 pos += strlen(strings[i]) + 1;
282 } else {
283 if (fput32(-1, out) < 0) {
284 perror("fwrite()");
285 retval = 1;
286 }
287 }
288 }
289
290 if (fclose(out) == EOF && retval == 0) {
291 perror("fclose()");
292 retval = 1;
293 }
294 if (retval)
295 unlink(outfile);
296 return retval;
297 }
298
299 /*************************************************************************/
300
301 /*
302 * Local variables:
303 * c-file-style: "stroustrup"
304 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
305 * indent-tabs-mode: nil
306 * End:
307 *
308 * vim: expandtab shiftwidth=4:
309 */