root/lib/lang/lang.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lang_init
  2. placelstr
  3. lang_add_string
  4. lang_parse_from_mem
  5. load_builtin_lang_strings
  6. lang_map_preparsed_from_mem
  7. lang_load_from_file
  8. lang_str
  9. lang_strhash31

   1 #include "stdlib.h"
   2 #include "stddef.h"
   3 #include "string.h"
   4 #include "lang.h"
   5 #include "fileutil.h"
   6 
   7 static char* preparsed_lang_default_start=0;
   8 //static char* preparsed_lang_default_end=0;  // seems no longer needed
   9 
  10 // This is threshold to determine is this id in .lng or just string
  11 #define MAX_LANGID 0x1000
  12 
  13 /*
  14  *  Warning: lang string references are stored as 15 bit offsets to save space
  15  *  This will break once any language resource exceeds approx. 32766 bytes in size
  16  *
  17  *  the language buffer is slightly larger than optimal, due to the reason
  18  *  that no effort is being made to identify escape sequences
  19  *  while calculating total string length in lang_parse_from_mem()
  20  *  for example, the English resource has ~50 bytes surplus when loaded (as of 03/2016)
  21  */
  22 
  23 //-------------------------------------------------------------------
  24 
  25 static short* strings = NULL;        // string offset list (allocated at heap or mapped from gui_lang.c);
  26 static int count = 0;                // current maximal string id (init at lang_init with GUI_LANG_ITEMS)
  27 static char* langbuf = NULL;         // buffer for loaded lang strings
  28 static int langbuflen = 0;           // length of langbuf
  29 static int lbpointer;                // used while loading lang strings
  30 
  31 //-------------------------------------------------------------------
  32 void lang_init(int num) {
  33 
  34     if (strings) {
  35         free(strings);
  36         count = 0;
  37     }
  38 
  39     ++num;
  40     strings = malloc(num*sizeof(short));
  41     if (strings) {
  42         memset(strings, 0, num*sizeof(short));
  43         count = num;
  44     }
  45 
  46 }
  47 
  48 // create place for string in langbuf
  49 //-------------------------------------------------------------------
  50 static char* placelstr(int size) {
  51     char *ret = langbuf + lbpointer;
  52     lbpointer += size;
  53     if (lbpointer <= langbuflen) {
  54         return ret;
  55     }
  56     return 0;
  57 }
  58 
  59 // add to string list string "str" with id "num"
  60 //-------------------------------------------------------------------
  61 static void lang_add_string(int num, const char *str) {
  62     int f=0;
  63     char *p;
  64 
  65     if (strings && num<count) {
  66 
  67        p = placelstr(strlen(str)+1);
  68        if (p) {
  69            strings[num] = -(1 + p - langbuf); // lang string offsets are encoded as negative
  70            for (; *str; ++str) {
  71                 if (f) {
  72                     if (*str == '"' || *str == '\\') *(p-1)=*str;
  73                     else if (*str == 'n') *(p-1)='\n';
  74                     else *p++=*str;
  75                     f = 0;
  76                 } else {
  77                     *p++=*str;
  78                     if (*str == '\\') {
  79                         f = 1;
  80                     }
  81                 }
  82            }
  83            *p=0;
  84        }
  85     }
  86 }
  87 
  88 // Parsing of loaded .lng file
  89 // buf - source array (content of file.lng )
  90 //-------------------------------------------------------------------
  91 int lang_parse_from_mem(char *buf, int size) {
  92     char *p, *s, *e, *b;
  93     int i, langbufneed;
  94     char** pstrtmp;
  95 
  96         if  ( size <= 0 )
  97           return 0;
  98 
  99     langbufneed = 0;
 100     lbpointer = 0;
 101     // allocate temporary array for storing pointers to found strings
 102     pstrtmp = malloc(count*sizeof(char*));
 103     if (!pstrtmp) {
 104         return 0;
 105     }
 106     // needs to be zeroed
 107     memset(pstrtmp, 0, count*sizeof(char*));
 108 
 109     // initialize _final_ offset array with built-in strings
 110     char* load_builtin_lang_strings(int, short*);
 111     load_builtin_lang_strings(count-1, strings);
 112 
 113     e = buf-1;
 114     while(e) {
 115         p = e+1;
 116         while (*p && (*p=='\r' || *p=='\n')) ++p; //skip empty lines
 117         i = strtol(p, &e, 0/*autodetect base oct-dec-hex*/);    // convert "*p" to long "i" and return pointer beyond to e
 118         if (e!=p) {
 119             p = e;
 120             e = strpbrk(p, "\r\n");        //break string with zero on \r|\n
 121             if (e) *e=0;
 122 
 123             while (*p && *p!='\"') ++p;    // cut string from "" if it exists
 124             if (*p) ++p;
 125             s = p;
 126             while (*p && (*p!='\"' || *(p-1)=='\\')) ++p;
 127             *p=0;
 128 
 129             // store string address and add its length to total
 130             if ((i > 0) && (i<count)) {
 131                 // ignore string IDs that have zero length built-in string
 132                 // rationale: built-in strings are always complete (have English fallback),
 133                 // except for IDs that are disabled for the port
 134                 //
 135                 // lang_str() only returns built-in strings at this point
 136                 b = lang_str(i);
 137                 if (b && b[0]!=0) {
 138                     langbufneed += strlen(s) + 1;
 139                     pstrtmp[i] = s;
 140                 }
 141             }
 142         } else { //skip invalid line
 143             e = strpbrk(p, "\r\n");
 144             if (e) *e=0;
 145         }
 146     }
 147 
 148     if ((langbufneed>langbuflen)||(!langbuf)) { // existing buffer is too small or not allocated
 149         if (langbuf) {
 150             free(langbuf);
 151         }
 152         langbuf = malloc(langbufneed);
 153         if (langbuf) {
 154             langbuflen = langbufneed;
 155         }
 156         else {
 157             langbuflen = 0;
 158         }
 159     }
 160     // zeroing is not required (holes between strings will contain junk, but that doesn't hurt)
 161     // memset(langbuf, 0, langbuflen);
 162 
 163     for (i=1; i<count; i++) {
 164         if (pstrtmp[i]) {   // add string if it exists
 165             lang_add_string(i, pstrtmp[i]);
 166         }
 167     }
 168 
 169     free(pstrtmp);
 170         return 1;
 171 }
 172 
 173 // init string offset array to built-in defaults
 174 //-------------------------------------------------------------------
 175 char* load_builtin_lang_strings(int cnt, short* array) {
 176     int i;
 177     char *p = preparsed_lang_default_start;
 178 
 179     for ( i = 1; i<=cnt; i++ )
 180     {
 181         array[i] = 1 + p - preparsed_lang_default_start;
 182         while (*p) p++;
 183         p++;
 184     }
 185     return p;
 186 }
 187 
 188 // This function have to be called before any other string load
 189 //-------------------------------------------------------------------
 190 void lang_map_preparsed_from_mem( char* gui_lang_default, int num )
 191 {
 192 
 193     preparsed_lang_default_start = gui_lang_default;
 194     lang_init( num );
 195     // preparsed_lang_default_end =  // variable not currently needed
 196     load_builtin_lang_strings(num, strings);
 197 
 198 }
 199 
 200 //-------------------------------------------------------------------
 201 void lang_load_from_file(const char *filename) {
 202     process_file(filename, lang_parse_from_mem, 1);
 203 }
 204 
 205 
 206 //-------------------------------------------------------------------
 207 char* lang_str(int str) {
 208     if (str && str<MAX_LANGID) {
 209         if (strings && str<count && strings[str]) {
 210             if (strings[str]>0) {
 211                 // string from builtin resource
 212                 return preparsed_lang_default_start + strings[str] - 1;
 213             }
 214             else if (langbuf) {
 215                 // string from loaded lang file
 216                 return langbuf - strings[str] - 1;
 217             }
 218         }
 219     } else { // not ID, just char*
 220         return (char*)str;
 221     }
 222     return "";
 223 }
 224 
 225 //-------------------------------------------------------------------
 226 // make hash of string
 227 unsigned int lang_strhash31(int langid)
 228 {
 229     if ( langid<MAX_LANGID ) 
 230                 return langid;
 231 
 232         unsigned char* str = (unsigned char*)langid;
 233         unsigned hash=0;
 234         for ( ; *str; str++ )
 235                 hash = *str ^ (hash<<6) ^ (hash>>25);
 236         if ( hash<MAX_LANGID )
 237                 hash |= (1<<31);
 238         return hash;
 239 }

/* [<][>][^][v][top][bottom][index][help] */