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

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