/[winpt]/trunk/Src/wptNLS.cpp
ViewVC logotype

Diff of /trunk/Src/wptNLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 327 by twoaday, Mon Jan 15 22:02:04 2007 UTC revision 328 by twoaday, Fri Sep 25 16:07:38 2009 UTC
# Line 1  Line 1 
1  /* wptNLS.cpp - W32 Native Language Support  /* wptNLS.cpp - W32 Native Language Support
2   *      Copyright (C) 2001, 2002, 2003, 2006 Timo Schulz   *      Copyright (C) 2001-2003, 2006, 2008, 2009 Timo Schulz
3   *      Copyright (C) 1995-1999 Free Software Foundation, Inc.   *      Copyright (C) 1995-1999 Free Software Foundation, Inc.
4   *   *
5   * This code is a stripped down version of simple-gettext.c   * This code is a stripped down version of simple-gettext.c
# Line 21  Line 21 
21    
22  #include <stdio.h>  #include <stdio.h>
23  #include <string.h>  #include <string.h>
 #include <ctype.h>  
 #include <errno.h>  
 #include <sys/types.h>  
24  #include <sys/stat.h>  #include <sys/stat.h>
25    #include <time.h>
26  #include <windows.h>  #include <windows.h>
27    
28  #include "wptNLS.h"  #include "wptNLS.h"
29  #include "wptTypes.h"  #include "wptTypes.h"
30    #include "wptUtil.h"
31    #include "wptW32API.h"
32    #include "wptVersion.h"
33    #include "StringBuffer.h"
34    
35  /* The magic number of the GNU message catalog format.  */  /* The magic number of the GNU message catalog format.  */
36  #define MAGIC         0x950412de  #define MAGIC         0x950412de
# Line 62  struct string_desc { Line 63  struct string_desc {
63      DWORD offset; /* Offset of string in file.  */      DWORD offset; /* Offset of string in file.  */
64  };  };
65    
66  struct loaded_domain {  struct loaded_domain_s {
67    char *data;      char *file_name;
68    int must_swap;      time_t modify_time;
69    DWORD nstrings;      char *data;
70    char *mapped;      int must_swap;
71    struct string_desc *orig_tab;      DWORD nstrings;
72    struct string_desc *trans_tab;      char *mapped;
73    DWORD hash_size;      struct string_desc *orig_tab;
74    DWORD *hash_tab;      struct string_desc *trans_tab;
75        DWORD hash_size;
76        DWORD *hash_tab;
77  };  };
78    typedef struct loaded_domain_s *gettext_domain_t;
79    
80  /* List of all available languages. */  /* List of all available languages. */
81  struct lang_table_s lang_list[] = {  struct lang_table_s lang_list[] = {
82      {"en", "English",   LANG_ENGLISH},      {"en", "English",   LANG_ENGLISH},
83      {"de", "German",    LANG_GERMAN},      {"de", "German",    LANG_GERMAN},
84      {"fr", "French",    LANG_FRENCH},      {"ru", "Russian",   LANG_RUSSIAN},
85      {"jp", "Japanese",  LANG_JAPANESE},      //{"fr", "French",  LANG_FRENCH},
86      // XXX: add new languages.      //{"jp", "Japanese",LANG_JAPANESE},    
87      {"pt_BR", "Portuguese (Brazil)", SUBLANG_PORTUGUESE_BRAZILIAN},      {NULL, NULL, 0}
     {NULL, 0}  
88  };  };
89    
90    
91  /* The current domain. */  /* The current gettext domain. */
92  static struct loaded_domain *the_domain;  static gettext_domain_t the_domain;
93    
94    
95  static DWORD  static DWORD
# Line 121  hash_string (const char *str_param) Line 124  hash_string (const char *str_param)
124    
125  /* Missing W32 functions. */  /* Missing W32 functions. */
126  static char*  static char*
127  w32_stpcpy (char *a,const char *b)  w32_stpcpy (char *a, const char *b)
128  {  {
129      while (*b)      while (*b)
130          *a++ = *b++;          *a++ = *b++;
# Line 130  w32_stpcpy (char *a,const char *b) Line 133  w32_stpcpy (char *a,const char *b)
133  }  }
134    
135    
136  static struct loaded_domain*  static gettext_domain_t
137  load_domain (const char *filename)  load_domain (const char *filename)
138  {  {
139      FILE *fp;      FILE *fp;
140      size_t size;      size_t size;
141      struct stat st;      struct stat st;
142      struct mo_file_header *data = NULL;      struct mo_file_header *data = NULL;
143      struct loaded_domain *domain = NULL;      gettext_domain_t domain = NULL;
144      size_t to_read;      size_t to_read;
145      char *read_ptr;      char *read_ptr;
146    
# Line 145  load_domain (const char *filename) Line 148  load_domain (const char *filename)
148      if (!fp)      if (!fp)
149         return NULL;         return NULL;
150      /* we must know about the size of the file */      /* we must know about the size of the file */
151      if( fstat( fileno(fp ), &st )      if (fstat (fileno(fp), &st) ||
152          || (size = (size_t)st.st_size) != (size_t)st.st_size          (size = (size_t)st.st_size) != (size_t)st.st_size ||
153          || size < sizeof (struct mo_file_header) ) {          size < sizeof (struct mo_file_header)) {
154          fclose( fp );            fclose (fp);
155          return NULL;          return NULL;
156      }      }
157    
# Line 159  load_domain (const char *filename) Line 162  load_domain (const char *filename)
162      to_read = size;      to_read = size;
163      read_ptr = (char *) data;      read_ptr = (char *) data;
164      do {      do {
165          size_t nb = fread( read_ptr, 1, to_read, fp );          size_t nb = fread (read_ptr, 1, to_read, fp);
166          if( nb < to_read ) {          if (nb < to_read) {
167              fclose (fp);              fclose (fp);
168              free(data);              free(data);
169              return NULL; /* read error */              return NULL; /* read error */              
                   
170          }          }
171          read_ptr += nb;          read_ptr += nb;
172          to_read -= nb;          to_read -= nb;
173      } while( to_read > 0 );      } while (to_read > 0);
174      fclose (fp);      fclose (fp);
175    
176      /* Using the magic number we can test whether it really is a message      /* Using the magic number we can test whether it really is a message
177       * catalog file.  */       * catalog file.  */
178      if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {      if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED) {
179          /* The magic number is wrong: not a message catalog file.  */          /* The magic number is wrong: not a message catalog file.  */
180          free( data );          free (data);
181          return NULL;          return NULL;
182      }      }
183    
184      domain = (struct loaded_domain *)calloc( 1, sizeof *domain );      domain = (struct loaded_domain_s *)calloc (1, sizeof *domain);
185      if (!domain)      if (!domain)
186          BUG (0);          BUG (0);
187      domain->data = (char *) data;      domain->data = (char *) data;
188      domain->must_swap = data->magic != MAGIC;      domain->must_swap = data->magic != MAGIC;
189    
190      /* Fill in the information about the available tables.  */      /* Fill in the information about the available tables.  */
191      switch( SWAPIT(domain->must_swap, data->revision) ) {      switch (SWAPIT(domain->must_swap, data->revision)) {
192        case 0:        case 0:
193            domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);            domain->nstrings = SWAPIT (domain->must_swap, data->nstrings);
194            domain->orig_tab = (struct string_desc *)            domain->orig_tab = (struct string_desc *)
195                ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));                ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset));
196            domain->trans_tab = (struct string_desc *)            domain->trans_tab = (struct string_desc *)
197                ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));                ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset));
198            domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);              domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size);  
199            domain->hash_tab = (DWORD *)              domain->hash_tab = (DWORD *)  
200                ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));                      ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset));      
201            break;            break;
202    
203        default: /* This is an invalid revision.  */        default: /* This is an invalid revision.  */
204            free( data );            free (data);
205            free( domain );            free (domain);
206            return NULL;            return NULL;
207      }      }
208    
# Line 208  load_domain (const char *filename) Line 210  load_domain (const char *filename)
210      domain->mapped = (char *)calloc( 1, domain->nstrings );      domain->mapped = (char *)calloc( 1, domain->nstrings );
211      if (!domain->mapped)      if (!domain->mapped)
212          BUG (0);          BUG (0);
213        
214        domain->file_name = strdup (filename);
215        domain->modify_time = st.st_mtime;
216      return domain;      return domain;
217  }  }
218    
219    
220    /* Returns a string representation of the users system language
221     * if we support it, 'en' otherwise.
222     */
223    static const char*
224    get_user_langid (void)
225    {
226        int lang = GetUserDefaultLangID() & 511;
227        
228        for (int i=0; lang_list[i].id != NULL; i++) {
229            if (lang == lang_list[i].langid)
230                return lang_list[i].id;
231        }
232        return "en";
233    }
234    
235    
236    /* To avoid problems that the current directory is not the
237     * same folder the WinPT.exe is located in, we extract the
238     * module directory.
239     */
240    char*
241    get_module_dir (char *buf, DWORD buflen)
242    {
243        int pos;
244        
245        if (buflen < 1 || !GetModuleFileName (glob_hinst, buf, buflen-1))
246            return NULL;
247    
248        pos = strlen (buf);
249        while (pos > 0 && buf[--pos] != '\\')
250            ;
251        buf[pos+1] = '\0';
252        return buf;
253    }
254    
255    
256    /* Returns a localisation name for a specific resource (file).
257     * For instance, lang=DE and file=winpt.chm will become
258     * winpt.DE.chm
259     */
260    char*
261    get_locale_name (const char *file)
262    {
263        const char *lang = get_user_langid();
264        char *name, *ext;
265        char *p, buf[MAX_PATH+1];
266        
267        p = strrchr (file, '.');
268        if (p == NULL) {
269            p = new char[strlen(file)+strlen(lang)+2+1];
270            sprintf (p, "%s.%s", file, lang);
271            return p;
272        }
273        name = substr(file, 0, p-file);
274        ext = substr(file, p-file+1, strlen(file));
275        p = get_module_dir (buf, MAX_PATH);
276        if (!p)
277            BUG (NULL);
278        StringBuffer s = p;
279        s = s + name + "." + lang + "." + ext;
280        p = s.getBufferCopy();
281        free_if_alloc (name);
282        free_if_alloc (ext);
283        return p;
284    }
285    
286    
287  /* Deallocate static resources. */  /* Deallocate static resources. */
288  void  void
289  gettext_free_current_domain (void)  gettext_free_current_domain (void)
290  {  {
291      if (!the_domain)      if (the_domain == NULL)
292          return;          return;
293      free (the_domain->data);      free (the_domain->data);
294      free (the_domain->mapped);      free (the_domain->mapped);
295        free (the_domain->file_name);
296      free (the_domain);      free (the_domain);
297      the_domain = NULL;      the_domain = NULL;
298  }  }
299    
300    
301    char* get_reg_entry_mo (void);
302    
303    /* Fallback code which is used when no new NLS file
304     * were found. Then we read the MODir registry key
305     * and check if a file named 'winpt.mo' exists in this
306     * directory.
307     */
308    static gettext_domain_t
309    load_modir_domain (void)
310    {
311        gettext_domain_t domain = NULL;
312        StringBuffer s;
313        char *modir;
314        
315        modir = get_reg_entry_mo ();
316        if (!modir)
317            return NULL;
318        if (dir_exist_check (modir)) {
319            free_if_alloc (modir);
320            return NULL;
321        }
322        s = modir;
323        if (modir[strlen (modir)-1] != '\\')
324            s += "\\";
325        s += "winpt.mo";
326        const char *fname = s.getBuffer();
327        if (!file_exist_check (fname))
328            domain = load_domain (fname);
329        free_if_alloc (modir);
330        return domain;
331    }
332    
333    
334    int
335    gettext_set_user_domain (void)
336    {
337        gettext_domain_t domain = NULL;
338        char *file = get_locale_name ("winpt.mo");
339        if (file && !file_exist_check (file))
340            domain = load_domain (file);
341        else
342            domain = load_modir_domain ();
343        free_if_alloc (file);
344        gettext_free_current_domain ();    
345        the_domain = domain;
346        return 0;
347    }
348    
349    
350    int
351    gettext_domain_needs_refresh (void)
352    {
353        struct stat st;
354        
355        if (the_domain == NULL || stat (the_domain->file_name, &st))
356            return 0;
357        /* '1' means that the MO file were modified in the mean time
358           and the application should reload the domain. */
359        if (st.st_mtime != the_domain->modify_time)
360            return 1;
361        
362        return 0;
363    }
364    
365  /* Set the file used for translations. Pass a NULL to disable translation.  /* Set the file used for translations. Pass a NULL to disable translation.
366     A new filename may be set at anytime. */     A new filename may be set at anytime. */
367  int  int
368  gettext_set_file (const char *filename, const char *nls_dir)  gettext_set_file (const char *filename, const char *nls_dir)
369  {  {
370      struct loaded_domain *domain = NULL;      gettext_domain_t domain = NULL;
371    
372      if (filename && *filename) {      if (filename && *filename) {
373          if (filename[1] == ':' && filename[2] == '\\')          if (filename[1] == ':' && filename[2] == '\\')
# Line 243  gettext_set_file (const char *filename, Line 379  gettext_set_file (const char *filename,
379              if (!dir)              if (!dir)
380                  BUG (0);                  BUG (0);
381              buf= (char *)malloc (strlen (dir) + strlen (filename)+1+3+1);              buf= (char *)malloc (strlen (dir) + strlen (filename)+1+3+1);
             if (!buf)  
                 BUG (0);  
   
382              strcpy (w32_stpcpy (w32_stpcpy (              strcpy (w32_stpcpy (w32_stpcpy (
383                      w32_stpcpy (buf, dir),"\\"), filename),".mo");                      w32_stpcpy (buf, dir), "\\"), filename),".mo");
384              domain = load_domain(buf);              domain = load_domain(buf);
385              free (buf);              free (buf);
386              free (dir);              free (dir);
# Line 256  gettext_set_file (const char *filename, Line 389  gettext_set_file (const char *filename,
389              return -1;              return -1;
390      }      }
391    
392      gettext_free_current_domain ();        gettext_free_current_domain ();
393      the_domain = domain;      the_domain = domain;
394      return 0;      return 0;
395  }  }
396    
397    
398  static const char*  static const char*
399  get_string( struct loaded_domain *domain, DWORD idx )  get_string (gettext_domain_t domain, DWORD idx)
400  {  {
401      char *p = domain->data + SWAPIT(domain->must_swap,      char *p = domain->data + SWAPIT(domain->must_swap,
402                                      domain->trans_tab[idx].offset);                                      domain->trans_tab[idx].offset);
403      if( !domain->mapped[idx] ) {              if (!domain->mapped[idx])
404          domain->mapped[idx] = 1;                          domain->mapped[idx] = 1;
     }  
405      return (const char*)p;      return (const char*)p;
406  }  }
407    
408    
409  const char *  const char *
410  gettext( const char *msgid )  gettext (const char *msgid)
411  {  {
412      struct loaded_domain *domain;      gettext_domain_t domain;
413      size_t act = 0;      size_t act = 0;
414      size_t top, bottom;      size_t top, bottom;
415        
416      if (!(domain = the_domain))      domain = the_domain;
417        if (domain == NULL)
418          goto not_found;          goto not_found;
419    
420      /* Locate the MSGID and its translation.  */      /* Locate the MSGID and its translation.  */
421      if( domain->hash_size > 2 && domain->hash_tab ) {                if (domain->hash_size > 2 && domain->hash_tab) {
422          /* Use the hashing table.  */                    /* Use the hashing table.  */          
423          DWORD len = strlen (msgid);              DWORD len = strlen (msgid);    
424          DWORD hash_val = hash_string (msgid);            DWORD hash_val = hash_string (msgid);  
# Line 293  gettext( const char *msgid ) Line 426  gettext( const char *msgid )
426          DWORD incr = 1 + (hash_val % (domain->hash_size - 2));            DWORD incr = 1 + (hash_val % (domain->hash_size - 2));  
427          DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);          DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
428    
429          if ( !nstr ) /* Hash table entry is empty.  */            if (!nstr) /* Hash table entry is empty.  */    
430              goto not_found;              goto not_found;
431            
432                            if (SWAPIT(domain->must_swap,  
         if( SWAPIT(domain->must_swap,    
433              domain->orig_tab[nstr - 1].length) == len                domain->orig_tab[nstr - 1].length) == len  
434              && !strcmp( msgid,                && !strcmp (msgid,  
435              domain->data + SWAPIT(domain->must_swap,                          domain->data + SWAPIT (domain->must_swap,
436                                      domain->orig_tab[nstr - 1].offset)) )                                                 domain->orig_tab[nstr - 1].offset)))
437                                      return get_string( domain, nstr - 1 );              return get_string (domain, nstr - 1);
438          for(;;) {          for(;;) {
439              if (idx >= domain->hash_size - incr)              if (idx >= domain->hash_size - incr)
440                  idx -= domain->hash_size - incr;                  idx -= domain->hash_size - incr;
441              else              else
442                  idx += incr;                  idx += incr;
443              nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);              nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);
444              if( !nstr )              if (!nstr)  
445                  goto not_found; /* Hash table entry is empty.  */                  goto not_found; /* Hash table entry is empty.  */
446    
447              if ( SWAPIT(domain->must_swap,              if (SWAPIT (domain->must_swap,
448                                  domain->orig_tab[nstr - 1].length) == len                          domain->orig_tab[nstr - 1].length) == len
449                                  && !strcmp (msgid,                  && !strcmp (msgid,
450                                  domain->data + SWAPIT(domain->must_swap,                              domain->data + SWAPIT (domain->must_swap,
451                                             domain->orig_tab[nstr - 1].offset)))                                                     domain->orig_tab[nstr - 1].offset)))
452                                            
453                                             return get_string( domain, nstr-1 );                  return get_string (domain, nstr-1);
454          } /* NOTREACHED */          } /* NOTREACHED */
455      }      }
456    
# Line 326  gettext( const char *msgid ) Line 458  gettext( const char *msgid )
458         array of messages.  */         array of messages.  */
459      bottom = 0;      bottom = 0;
460      top = domain->nstrings;      top = domain->nstrings;
461      while( bottom < top ) {                  while (bottom < top) {
462          int cmp_val;          int cmp_val;
463                    
464          act = (bottom + top) / 2;                act = (bottom + top) / 2;      
465          cmp_val = strcmp(msgid, domain->data + SWAPIT(domain->must_swap,          cmp_val = strcmp (msgid, domain->data + SWAPIT(domain->must_swap,
466                          domain->orig_tab[act].offset));                            domain->orig_tab[act].offset));
467          if (cmp_val < 0)          if (cmp_val < 0)
468              top = act;              top = act;
469          else if (cmp_val > 0)          else if (cmp_val > 0)
470              bottom = act + 1;              bottom = act + 1;
471          else              else
472              return get_string( domain, act );              return get_string (domain, act);
473      }      }
474    
475  not_found:  not_found:
# Line 351  const char* Line 483  const char*
483  gettext_get_langid (void)  gettext_get_langid (void)
484  {  {
485      LANGID lang;      LANGID lang;
     int i;  
486    
487      lang = GetUserDefaultLangID ();      lang = GetUserDefaultLangID ();
488      if (PRIMARYLANGID (lang) == LANG_ENGLISH)      if (PRIMARYLANGID (lang) == LANG_ENGLISH)
489          return NULL;          return NULL;
490    
491      for (i=0; lang_list[i].id; i++) {      for (int i=0; lang_list[i].id; i++) {
492          if (PRIMARYLANGID (lang) == lang_list[i].langid)          if (PRIMARYLANGID (lang) == lang_list[i].langid)
493              return lang_list[i].id;              return lang_list[i].id;
494      }      }
# Line 371  void Line 502  void
502  gettext_localize_dialog (HWND dlg, struct gettext_tab_s *tab,  gettext_localize_dialog (HWND dlg, struct gettext_tab_s *tab,
503                           const char *title)                           const char *title)
504  {  {
505      int i;      for (int i=0; tab[i].trans != NULL; i++)
   
     for (i=0; tab[i].trans != NULL; i++)  
506          SetDlgItemText (dlg, tab[i].ctlid, tab[i].trans);          SetDlgItemText (dlg, tab[i].ctlid, tab[i].trans);
507      if (title)      if (title != NULL)
508          SetWindowText (dlg, title);          SetWindowText (dlg, title);
509  }  }

Legend:
Removed from v.327  
changed lines
  Added in v.328

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26