langcomp.c

Go to the documentation of this file.
00001 /* Compiler for language definition files.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  * 
00011  * $Id: langcomp.c 1265 2007-08-26 15:33:06Z geniusdex $
00012  *
00013  */
00014 
00015 /*
00016  * A language definition file contains all strings which Services sends to
00017  * users in a particular language.  A language file may contain comments
00018  * (lines beginning with "#") and blank lines.  All other lines must adhere
00019  * to the following format:
00020  *
00021  * Each string definition begins with the C name of a message (as defined
00022  * in the file "index"--see below).  This must be alone on a line, preceded
00023  * and followed by no blank space.  Following this line are zero or more
00024  * lines of text; each line of text must begin with exactly one tab
00025  * character, which is discarded.  Newlines are retained in the strings,
00026  * except the last newline in the text, which is discarded.  A message with
00027  * no text is replaced by a null pointer in the array (not an empty
00028  * string).
00029  *
00030  * All messages in the program are listed, one per line, in the "index"
00031  * file.  No comments or blank lines are permitted in that file.  The index
00032  * file can be generated from a language file with a command like:
00033  *  grep '^[A-Z]' en_us.l >index
00034  *
00035  * This program takes one parameter, the name of the language file.  It
00036  * generates a compiled language file whose name is created by removing any
00037  * extension on the source file on the input filename.
00038  *
00039  * You may also pass a "-w" option to print warnings for missing strings.
00040  *
00041  * This program isn't very flexible, because it doesn't need to be, but
00042  * anyone who wants to try making it more flexible is welcome to.
00043  */
00044 
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <string.h>
00048 #undef getline
00049 
00050 int numstrings = 0; /* Number of strings we should have */
00051 char **stringnames; /* Names of the strings (from index file) */
00052 char **strings;     /* Strings we have loaded */
00053 
00054 int linenum = 0;    /* Current line number in input file */
00055 
00056 #ifdef _WIN32
00057 #define snprintf _snprintf
00058 #endif
00059 
00060 char *anopeStrDup(const char *src);
00061 
00062 /*************************************************************************/
00063 
00064 /* Read the index file and load numstrings and stringnames.  Return -1 on
00065  * error, 0 on success. */
00066 
00067 int read_index_file()
00068 {
00069     FILE *f;
00070     char buf[256];
00071     int i;
00072 
00073     if (!(f = fopen("index", "rb"))) {
00074     perror("fopen(index)");
00075     return -1;
00076     }
00077     while (fgets(buf, sizeof(buf), f))
00078     numstrings++;
00079     if (!(stringnames = calloc(sizeof(char *), numstrings))) {
00080     perror("calloc(stringnames)");
00081     return -1;
00082     }
00083     if (!(strings = calloc(sizeof(char *), numstrings))) {
00084     perror("calloc(strings)");
00085     return -1;
00086     }
00087     fseek(f, 0, SEEK_SET);
00088     i = 0;
00089     while (fgets(buf, sizeof(buf), f)) {
00090     if (buf[strlen(buf)-1] == '\n')
00091         buf[strlen(buf)-1] = '\0';
00092     if (!(stringnames[i++] = anopeStrDup(buf))) {
00093         perror("strdup()");
00094         return -1;
00095     }
00096     }
00097     fclose(f);
00098     return 0;
00099 }
00100 
00101 /*************************************************************************/
00102 
00103 /* Return the index of a string name in stringnames, or -1 if not found. */
00104 
00105 int stringnum(const char *name)
00106 {
00107     int i;
00108 
00109     for (i = 0; i < numstrings; i++) {
00110     if (strcmp(stringnames[i], name) == 0)
00111         return i;
00112     }
00113     return -1;
00114 }
00115 
00116 /*************************************************************************/
00117 
00118 /* Read a non-comment, non-blank line from the input file.  Return NULL at
00119  * end of file. */
00120 
00121 char *ano_getline(FILE *f)
00122 {
00123     static char buf[1024];
00124     char *s;
00125 
00126     do {
00127     if (!(fgets(buf, sizeof(buf), f)))
00128         return NULL;
00129     linenum++;
00130     } while (*buf == '#' || *buf == '\n');
00131     s = buf + strlen(buf)-1;
00132     if (*s == '\n')
00133     *s = '\0';
00134     return buf;
00135 }
00136 
00137 /*************************************************************************/
00138 
00139 /* Write a 32-bit value to a file in big-endian order. */
00140 
00141 int fput32(int val, FILE *f)
00142 {
00143     if (fputc(val>>24, f) < 0 ||
00144         fputc(val>>16, f) < 0 ||
00145         fputc(val>> 8, f) < 0 ||
00146         fputc(val    , f) < 0
00147     ) {
00148     return -1;
00149     } else {
00150     return 0;
00151     }
00152 }
00153 
00154 /*************************************************************************/
00155 char *anopeStrDup(const char *src) {
00156     char *ret=NULL;
00157     if(src) {
00158         if( (ret = (char *)malloc(strlen(src)+1)) ) {;
00159             strcpy(ret,src);
00160         }
00161     }
00162     return ret;
00163 }
00164 
00165 /*************************************************************************/
00166 int main(int ac, char **av)
00167 {
00168     char *filename = NULL, *s;
00169     char langname[254], outfile[256];
00170     FILE *in, *out;
00171     int warn = 0;
00172     int retval = 0;
00173     int curstring = -2, i;
00174     char *line;
00175     int pos;
00176     int maxerr = 50;    /* Max errors before we bail out */
00177 
00178     if (ac >= 2 && strcmp(av[1], "-w") == 0) {
00179     warn = 1;
00180     av[1] = av[2];
00181     ac--;
00182     }
00183     if (ac != 2) {
00184     fprintf(stderr, "Usage: %s [-w] <lang-file>\n", av[0]);
00185     return 1;
00186     }
00187     filename = av[1];
00188     s = strrchr(filename, '.');
00189     if (!s)
00190     s = filename + strlen(filename);
00191     if (s-filename > sizeof(langname)-3)
00192     s = filename + sizeof(langname)-1;
00193     strncpy(langname, filename, s-filename);
00194     langname[s-filename] = '\0';
00195     snprintf(outfile, sizeof(outfile), "%s", langname);
00196 
00197     if (read_index_file() < 0)
00198     return 1;
00199     if (!(in = fopen(filename, "rb"))) {
00200     perror(filename);
00201     return 1;
00202     }
00203     if (!(out = fopen(outfile, "wb"))) {
00204     perror(outfile);
00205     return 1;
00206     }
00207 
00208     while (maxerr > 0 && (line = ano_getline(in)) != NULL) {
00209     if (*line == '\t') {
00210         if (curstring == -2) {
00211         fprintf(stderr, "%s:%d: Junk at beginning of file\n",
00212             filename, linenum);
00213         retval = 1;
00214         } else if (curstring >= 0) {
00215         line++;
00216         i = strings[curstring] ? strlen(strings[curstring]) : 0;
00217         if (!(strings[curstring] =
00218             realloc(strings[curstring], i+strlen(line)+2))) {
00219             fprintf(stderr, "%s:%d: Out of memory!\n",filename,linenum);
00220             return 2;
00221         }
00222         sprintf(strings[curstring]+i, "%s\n", line);
00223         }
00224     } else {
00225 
00226         if ((curstring = stringnum(line)) < 0) {
00227         fprintf(stderr, "%s:%d: Unknown string name `%s'\n",
00228             filename, linenum, line);
00229         retval = 1;
00230         maxerr--;
00231         } else if (strings[curstring]) {
00232         fprintf(stderr, "%s:%d: Duplicate occurrence of string `%s'\n",
00233             filename, linenum, line);
00234         retval = 1;
00235         maxerr--;
00236         } else {
00237         if (!(strings[curstring] = malloc(1))) {
00238             fprintf(stderr, "%s:%d: Out of memory!\n",filename,linenum);
00239             return 2;
00240         }
00241         *strings[curstring] = '\0';
00242         }
00243 
00244         if (maxerr == 0)
00245         fprintf(stderr, "%s:%d: Too many errors!\n", filename, linenum);
00246         
00247     }
00248     }
00249 
00250     fput32(numstrings, out);
00251     pos = numstrings * 8 + 4;
00252     for (i = 0; i < numstrings; i++) {
00253     int len = strings[i] && *strings[i] ? strlen(strings[i])-1 : 0;
00254     fput32(pos, out);
00255     fput32(len, out);
00256     pos += len;
00257     }
00258     for (i = 0; i < numstrings; i++) {
00259     if (strings[i]) {
00260         if (*strings[i])
00261         strings[i][strlen(strings[i])-1] = '\0';   /* kill last \n */
00262         if (*strings[i])
00263         fputs(strings[i], out);
00264     } else if (warn) {
00265         fprintf(stderr, "%s: String `%s' missing\n", filename,
00266             stringnames[i]);
00267     }
00268     }
00269 
00270     fclose(in);
00271     fclose(out);
00272     return retval;
00273 }
00274 
00275 /*************************************************************************/

Generated on Sun Dec 30 09:26:45 2007 for Anope by  doxygen 1.5.1-20070107