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