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

Diff of /trunk/Src/wptNLS.c

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

revision 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 176 by twoaday, Mon Feb 13 09:38:03 2006 UTC
# Line 1  Line 1 
1  /* wptNLS.cpp - W32 Native Language Support  /* wptNLS.cpp - W32 Native Language Support
2   *      Copyright (C) 2001, 2002, 2003 Timo Schulz   *      Copyright (C) 2001, 2002, 2003, 2006 Timo Schulz
3   *      Copyright (C) 1995-1999 Free Software Foundation, Inc.   *      Copyright (C) 1995-1999 Free Software Foundation, Inc.
4   *   *
5   * This code based on the simple-gettext.c code from the GnuPG   * This code based on the simple-gettext.c code from the GnuPG
6   * by Ulrich Drepper.   * by Ulrich Drepper.
7   *   *
8   * WinPT is free software; you can redistribute it and/or   * WinPT is free software; you can redistribute it and/or
9   * modify it under the terms of the GNU General Public License   * modify it under the terms of the GNU General Public License
10   * as published by the Free Software Foundation; either version 2   * as published by the Free Software Foundation; either version 2
11   * of the License, or (at your option) any later version.   * of the License, or (at your option) any later version.
12   *     *  
13   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * General Public License for more details.   * General Public License for more details.
17   *   *
18   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
19   * along with WinPT; if not, write to the Free Software Foundation,   * along with WinPT; if not, write to the Free Software Foundation,
20   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21   */   */
22  /* x-todo-status: OK */  
23    #ifdef HAVE_CONFIG_H
24  #include <stdio.h>  #include <config.h>
25  #include <string.h>  #endif
26  #include <ctype.h>  
27  #include <errno.h>  #include <stdio.h>
28  #include <sys/types.h>  #include <string.h>
29  #include <sys/stat.h>  #include <ctype.h>
30  #include <windows.h>  #include <errno.h>
31    #include <sys/types.h>
32  #include "wptTypes.h"  #include <sys/stat.h>
33  #include "wptNLS.h"  #include <windows.h>
34    
35    #include "wptTypes.h"
36  /* Missing W32 functions. */  #include "wptNLS.h"
37  static char *  
38  stpcpy( char *a,const char *b )  
39  {  /* Missing W32 functions. */
40      while( *b )  static char *
41          *a++ = *b++;  w32_stpcpy (char *a,const char *b)
42      *a = 0;  {
43      return (char*)a;      while( *b )
44  }          *a++ = *b++;
45        *a = 0;
46  /* The magic number of the GNU message catalog format.  */      return (char*)a;
47  #define MAGIC         0x950412de  }
48  #define MAGIC_SWAPPED 0xde120495  
49    /* The magic number of the GNU message catalog format.  */
50  /* Revision number of the currently used .mo (binary) file format.  */  #define MAGIC         0x950412de
51  #define MO_REVISION_NUMBER 0  #define MAGIC_SWAPPED 0xde120495
52    
53    /* Revision number of the currently used .mo (binary) file format.  */
54  /* Header for binary .mo file format.  */  #define MO_REVISION_NUMBER 0
55  struct mo_file_header {  
56    u32 magic; /* The magic number.       */    
57    u32 revision; /* The revision number of the file format.  */  /* Header for binary .mo file format.  */
58    u32 nstrings; /* The number of strings pairs.  */    struct mo_file_header {
59    u32 orig_tab_offset; /* Offset of table with start offsets of original    u32 magic; /* The magic number.       */  
60                            strings.  */    u32 revision; /* The revision number of the file format.  */
61    u32 trans_tab_offset; /* Offset of table with start offsets of translation    u32 nstrings; /* The number of strings pairs.  */  
62                             strings.  */      u32 orig_tab_offset; /* Offset of table with start offsets of original
63    u32 hash_tab_size; /* Size of hashing table.  */                              strings.  */
64    u32 hash_tab_offset; /* Offset of first hashing entry.  */    u32 trans_tab_offset; /* Offset of table with start offsets of translation
65  };                             strings.  */  
66      u32 hash_tab_size; /* Size of hashing table.  */  
67  struct string_desc {    u32 hash_tab_offset; /* Offset of first hashing entry.  */
68    u32 length; /* Length of addressed string.  */    };
69    u32 offset; /* Offset of string in file.      */  
70  };  struct string_desc {
71      u32 length; /* Length of addressed string.  */  
72  struct loaded_domain {    u32 offset; /* Offset of string in file.      */
73    char *data;  };
74    int must_swap;  
75    u32 nstrings;  struct loaded_domain {
76    char *mapped;    char *data;
77    struct string_desc *orig_tab;    int must_swap;
78    struct string_desc *trans_tab;    u32 nstrings;
79    u32 hash_size;    char *mapped;
80    u32 *hash_tab;    struct string_desc *orig_tab;
81  };    struct string_desc *trans_tab;
82      u32 hash_size;
83  static struct loaded_domain *the_domain;    u32 *hash_tab;
84    };
85  static u32  
86  do_swap_u32( u32 i )  static struct loaded_domain *the_domain;
87  {  
88    return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);  static u32
89  }  do_swap_u32( u32 i )
90    {
91  #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )    return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
92    }
93    
94  /* We assume to have `unsigned long int' value with at least 32 bits.  */  #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )
95  #define HASHWORDBITS 32  
96    
97  /* The so called `hashpjw' function by P.J. Weinberger  /* We assume to have `unsigned long int' value with at least 32 bits.  */
98     [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,  #define HASHWORDBITS 32
99     1986, 1987 Bell Telephone Laboratories, Inc.]  */  
100    /* The so called `hashpjw' function by P.J. Weinberger
101  static u32     [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
102  hash_string( const char *str_param )     1986, 1987 Bell Telephone Laboratories, Inc.]  */
103  {  
104      unsigned long int hval, g;  static u32
105      const char *str = str_param;  hash_string( const char *str_param )
106    {
107      hval = 0;      unsigned long int hval, g;
108      while (*str != '\0') {      const char *str = str_param;
109          hval <<= 4;  
110          hval += (unsigned long int) *str++;          hval = 0;
111          g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));      while (*str != '\0') {
112          if (g != 0) {          hval <<= 4;
113              hval ^= g >> (HASHWORDBITS - 8);          hval += (unsigned long int) *str++;    
114              hval ^= g;            g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
115          }          if (g != 0) {
116      }              hval ^= g >> (HASHWORDBITS - 8);
117      return hval;              hval ^= g;  
118  } /* hash_string */          }
119        }
120        return hval;
121  static struct loaded_domain *  } /* hash_string */
122  load_domain( const char *filename )  
123  {  
124      FILE *fp;  static struct loaded_domain *
125      size_t size;  load_domain( const char *filename )
126      struct stat st;  {
127      struct mo_file_header *data = NULL;      FILE *fp;
128      struct loaded_domain *domain = NULL;      size_t size;
129      size_t to_read;      struct stat st;
130      char *read_ptr;      struct mo_file_header *data = NULL;
131        struct loaded_domain *domain = NULL;
132      fp = fopen( filename, "rb" );      size_t to_read;
133      if( !fp )      char *read_ptr;
134         return NULL; /* can't open the file */  
135      /* we must know about the size of the file */      fp = fopen( filename, "rb" );
136      if( fstat( fileno(fp ), &st )      if( !fp )
137          || (size = (size_t)st.st_size) != st.st_size         return NULL; /* can't open the file */
138          || size < sizeof (struct mo_file_header) ) {      /* we must know about the size of the file */
139          fclose( fp );        if( fstat( fileno(fp ), &st )
140          return NULL;          || (size = (size_t)st.st_size) != st.st_size
141      }          || size < sizeof (struct mo_file_header) ) {
142            fclose( fp );  
143      data = (struct mo_file_header *) malloc( size );          return NULL;
144      if( !data ) {      }
145          fclose( fp );  
146          return NULL; /* out of memory */      data = (struct mo_file_header *) malloc( size );
147      }      if( !data ) {
148            fclose( fp );
149      to_read = size;          return NULL; /* out of memory */
150      read_ptr = (char *) data;      }
151      do {  
152          long int nb = fread( read_ptr, 1, to_read, fp );      to_read = size;
153          if( nb < to_read ) {      read_ptr = (char *) data;
154              fclose (fp);      do {
155              free(data);          long int nb = fread( read_ptr, 1, to_read, fp );
156              return NULL; /* read error */          if( nb < to_read ) {
157                                fclose (fp);
158          }              free(data);
159          read_ptr += nb;              return NULL; /* read error */
160          to_read -= nb;                  
161      } while( to_read > 0 );          }
162      fclose (fp);          read_ptr += nb;
163            to_read -= nb;
164      /* Using the magic number we can test whether it really is a message      } while( to_read > 0 );
165       * catalog file.  */      fclose (fp);
166      if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {  
167          /* The magic number is wrong: not a message catalog file.  */      /* Using the magic number we can test whether it really is a message
168          free( data );       * catalog file.  */
169          return NULL;      if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {
170      }          /* The magic number is wrong: not a message catalog file.  */
171            free( data );
172      domain = (struct loaded_domain *)calloc( 1, sizeof *domain );          return NULL;
173      if( !domain )  {      }
174          free( data );    
175          return NULL;      domain = (struct loaded_domain *)calloc( 1, sizeof *domain );
176      }      if( !domain )  {
177      domain->data = (char *) data;          free( data );  
178      domain->must_swap = data->magic != MAGIC;          return NULL;
179        }
180      /* Fill in the information about the available tables.  */      domain->data = (char *) data;
181      switch( SWAPIT(domain->must_swap, data->revision) ) {      domain->must_swap = data->magic != MAGIC;
182        case 0:  
183            domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);      /* Fill in the information about the available tables.  */
184            domain->orig_tab = (struct string_desc *)      switch( SWAPIT(domain->must_swap, data->revision) ) {
185                ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));        case 0:
186            domain->trans_tab = (struct string_desc *)            domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);
187                ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));            domain->orig_tab = (struct string_desc *)
188            domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);                  ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));
189            domain->hash_tab = (u32 *)                domain->trans_tab = (struct string_desc *)
190                ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));                      ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));
191            break;            domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);  
192              domain->hash_tab = (u32 *)    
193        default: /* This is an invalid revision.  */                ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));      
194            free( data );            break;
195            free( domain );  
196            return NULL;        default: /* This is an invalid revision.  */
197      }            free( data );
198              free( domain );
199      /* allocate an array to keep track of code page mappings */            return NULL;
200      domain->mapped = (char *)calloc( 1, domain->nstrings );      }
201      if( !domain->mapped ) {  
202          free( data );      /* allocate an array to keep track of code page mappings */
203          free( domain );      domain->mapped = (char *)calloc( 1, domain->nstrings );
204          return NULL;      if( !domain->mapped ) {
205      }          free( data );
206            free( domain );
207      return domain;          return NULL;
208  } /* load_domain */      }
209    
210        return domain;
211  /****************  } /* load_domain */
212   * Set the file used for translations.  Pass a NULL to disable  
213   * translation.  A new filename may be set at anytime.  
214   * WARNING: After changing the filename you shoudl not access any data  /****************
215   *          retrieved by gettext().   * Set the file used for translations.  Pass a NULL to disable
216   */   * translation.  A new filename may be set at anytime.
217  int   * WARNING: After changing the filename you shoudl not access any data
218  set_gettext_file( const char *filename, const char *nls_dir )   *          retrieved by gettext().
219  {   */
220      struct loaded_domain *domain = NULL;  int
221    set_gettext_file( const char *filename, const char *nls_dir )
222      if( filename && *filename ) {  {
223          if( filename[0] == '/'          struct loaded_domain *domain = NULL;
224              || ( isalpha(filename[0])              
225              && filename[1] == ':'            if( filename && *filename ) {
226              && (filename[2] == '/' || filename[2] == '\\') )          if( filename[0] == '/'    
227             ) {              || ( isalpha(filename[0])            
228              /* absolute path - use it as is */                    && filename[1] == ':'      
229              domain = load_domain( filename );              && (filename[2] == '/' || filename[2] == '\\') )
230          }             ) {
231          else { /* relative path - append ".mo" and get dir from the environment */              /* absolute path - use it as is */      
232              char *buf = NULL;              domain = load_domain( filename );
233              char *dir;          }
234                            else { /* relative path - append ".mo" and get dir from the environment */
235              dir = strdup( nls_dir );              char *buf = NULL;
236              if( dir && (buf= (char *)malloc(strlen(dir)+strlen(filename)+1+3+1)) ) {              char *dir;
237                  strcpy(stpcpy(stpcpy(stpcpy( buf, dir),"/"), filename),".mo");                  
238                  domain = load_domain( buf );                                  dir = strdup( nls_dir );
239                  free(buf);              if( dir && (buf= (char *)malloc(strlen(dir)+strlen(filename)+1+3+1)) ) {
240              }                  strcpy(w32_stpcpy(w32_stpcpy(w32_stpcpy( buf, dir),"/"), filename),".mo");
241              free(dir);                  domain = load_domain( buf );                    
242          }                  free(buf);
243          if( !domain )              }
244              return -1;              free(dir);
245      }          }
246            if( !domain )
247      if( the_domain ) {              return -1;
248          free( the_domain->data );      }
249          free( the_domain->mapped );  
250          free( the_domain );          if( the_domain ) {
251          the_domain = NULL;          free( the_domain->data );
252      }          free( the_domain->mapped );
253      the_domain = domain;          free( the_domain );    
254      return 0;          the_domain = NULL;
255  } /* set_gettext_file */      }
256        the_domain = domain;
257        return 0;
258  static const char*  } /* set_gettext_file */
259  get_string( struct loaded_domain *domain, u32 idx )  
260  {  
261      char *p = domain->data + SWAPIT(domain->must_swap,  static const char*
262                                      domain->trans_tab[idx].offset);  get_string( struct loaded_domain *domain, u32 idx )
263      if( !domain->mapped[idx] ) {          {
264          domain->mapped[idx] = 1;                      char *p = domain->data + SWAPIT(domain->must_swap,
265      }                                      domain->trans_tab[idx].offset);
266      return (const char*)p;      if( !domain->mapped[idx] ) {        
267  } /* get_string */          domain->mapped[idx] = 1;                
268        }
269  const char *      return (const char*)p;
270  gettext( const char *msgid )  } /* get_string */
271  {  
272      struct loaded_domain *domain;  const char *
273      size_t act = 0;  gettext( const char *msgid )
274      size_t top, bottom;  {
275        struct loaded_domain *domain;
276      if( !(domain = the_domain) )              size_t act = 0;
277          goto not_found;      size_t top, bottom;
278    
279      /* Locate the MSGID and its translation.  */      if( !(domain = the_domain) )        
280      if( domain->hash_size > 2 && domain->hash_tab ) {                    goto not_found;
281          /* Use the hashing table.  */            
282          u32 len = strlen (msgid);            /* Locate the MSGID and its translation.  */
283          u32 hash_val = hash_string (msgid);          if( domain->hash_size > 2 && domain->hash_tab ) {          
284          u32 idx = hash_val % domain->hash_size;          /* Use the hashing table.  */          
285          u32 incr = 1 + (hash_val % (domain->hash_size - 2));              u32 len = strlen (msgid);      
286          u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);          u32 hash_val = hash_string (msgid);    
287            u32 idx = hash_val % domain->hash_size;
288          if ( !nstr ) /* Hash table entry is empty.  */            u32 incr = 1 + (hash_val % (domain->hash_size - 2));    
289              goto not_found;          u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
290    
291                            if ( !nstr ) /* Hash table entry is empty.  */  
292          if( SWAPIT(domain->must_swap,                goto not_found;
293              domain->orig_tab[nstr - 1].length) == len    
294              && !strcmp( msgid,                    
295              domain->data + SWAPIT(domain->must_swap,          if( SWAPIT(domain->must_swap,  
296                                      domain->orig_tab[nstr - 1].offset)) )              domain->orig_tab[nstr - 1].length) == len  
297                                      return get_string( domain, nstr - 1 );              && !strcmp( msgid,  
298          for(;;) {              domain->data + SWAPIT(domain->must_swap,
299              if (idx >= domain->hash_size - incr)                                      domain->orig_tab[nstr - 1].offset)) )
300                  idx -= domain->hash_size - incr;                                      return get_string( domain, nstr - 1 );
301              else          for(;;) {
302                  idx += incr;              if (idx >= domain->hash_size - incr)
303              nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);                  idx -= domain->hash_size - incr;
304              if( !nstr )              else
305                  goto not_found; /* Hash table entry is empty.  */                  idx += incr;
306                nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);
307              if ( SWAPIT(domain->must_swap,              if( !nstr )
308                                  domain->orig_tab[nstr - 1].length) == len                  goto not_found; /* Hash table entry is empty.  */
309                                  && !strcmp (msgid,  
310                                  domain->data + SWAPIT(domain->must_swap,              if ( SWAPIT(domain->must_swap,
311                                             domain->orig_tab[nstr - 1].offset)))                                  domain->orig_tab[nstr - 1].length) == len
312                                                            && !strcmp (msgid,
313                                             return get_string( domain, nstr-1 );                                  domain->data + SWAPIT(domain->must_swap,
314          } /* NOTREACHED */                                             domain->orig_tab[nstr - 1].offset)))
315      }                          
316                                               return get_string( domain, nstr-1 );
317      /* Now we try the default method:  binary search in the sorted          } /* NOTREACHED */
318         array of messages.  */      }
319      bottom = 0;  
320      top = domain->nstrings;      /* Now we try the default method:  binary search in the sorted
321      while( bottom < top ) {                     array of messages.  */
322          int cmp_val;      bottom = 0;
323                top = domain->nstrings;
324          act = (bottom + top) / 2;            while( bottom < top ) {            
325          cmp_val = strcmp(msgid, domain->data + SWAPIT(domain->must_swap,          int cmp_val;
326                          domain->orig_tab[act].offset));          
327          if (cmp_val < 0)          act = (bottom + top) / 2;      
328              top = act;          cmp_val = strcmp(msgid, domain->data + SWAPIT(domain->must_swap,
329          else if (cmp_val > 0)                          domain->orig_tab[act].offset));
330              bottom = act + 1;          if (cmp_val < 0)
331          else                  top = act;
332              return get_string( domain, act );          else if (cmp_val > 0)
333      }              bottom = act + 1;
334            else    
335  not_found:              return get_string( domain, act );
336      return msgid;      }
337  } /* gettext */  
338    not_found:
339        return msgid;
340    } /* gettext */
341    
342    
343    /* Map the user specific language ID to a
344       gettext conform language string.
345       Example: LANG_GERMAN -> "de" */
346    const char*
347    get_gettext_langid (void)
348    {
349        struct {
350            const char *id;
351            int langid;
352        } lang_table[] = {
353            {"de", LANG_GERMAN},
354            {NULL, 0},
355        };
356        LANGID lang;
357        int i;
358    
359        lang = GetUserDefaultLangID ();
360    
361        for (i=0; lang_table[i].id; i++) {
362            if (PRIMARYLANGID (lang) == lang_table[i].langid)
363                return lang_table[i].id;
364        }
365        return NULL;
366    }
367    
368    
369    /* Take a table with control item IDs and their translation
370       and set each text to the translated value. */
371    void
372    gettext_localize_dialog (HWND dlg, struct gettext_tab_s *tab,
373                             const char *title)
374    {
375        int i;
376    
377        for (i=0; tab[i].trans != NULL; i++)
378            SetDlgItemText (dlg, tab[i].ctlid, tab[i].trans);
379        if (title)
380            SetWindowText (dlg, title);
381    }
382    
383    
384    /* XXX: this has to be placed in a .c file but not here */
385    #include <shlobj.h>
386    
387    void _SHFree (void *p)
388    {
389        IMalloc *pm;
390        SHGetMalloc(&pm);
391        if (pm) {
392            pm->lpVtbl->Free(pm,p);
393            pm->lpVtbl->Release(pm);
394        }
395    }

Legend:
Removed from v.2  
changed lines
  Added in v.176

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26