44 #include <sys/stat.h> |
45 #include <sys/stat.h> |
45 #include <pfmt.h> |
46 #include <pfmt.h> |
46 #include <stdlib.h> |
47 #include <stdlib.h> |
47 #include <unistd.h> |
48 #include <unistd.h> |
48 #include <limits.h> |
49 #include <limits.h> |
|
50 #include <thread.h> |
49 #include "../i18n/_locale.h" |
51 #include "../i18n/_locale.h" |
50 #include "../i18n/_loc_path.h" |
52 #include "../i18n/_loc_path.h" |
51 |
53 |
52 #define MAXDB 10 /* maximum number of data bases per program */ |
|
53 #define MESSAGES "/LC_MESSAGES/" |
54 #define MESSAGES "/LC_MESSAGES/" |
54 #define DB_NAME_LEN 15 |
55 #define DB_NAME_LEN 15 |
55 |
56 |
56 char *handle_return(const char *); |
57 #define handle_return(s) \ |
57 |
58 ((char *)((s) != NULL && *(s) != '\0' ? (s) : not_found)) |
58 /* support multiple versions of a package */ |
59 |
59 |
60 extern char cur_cat[]; |
60 char *Msgdb = (char *)NULL; |
61 extern rwlock_t _rw_cur_cat; |
61 |
62 |
62 static char *saved_locale = NULL; |
63 static mutex_t gettxt_lock = DEFAULTMUTEX; |
63 static const char *not_found = "Message not found!!\n"; |
64 static const char *not_found = "Message not found!!\n"; |
64 |
65 static const char *loc_C = "C"; |
65 static struct db_info { |
66 |
|
67 struct db_list { |
66 char db_name[DB_NAME_LEN]; /* name of the message file */ |
68 char db_name[DB_NAME_LEN]; /* name of the message file */ |
67 uintptr_t addr; /* virtual memory address */ |
69 uintptr_t addr; /* virtual memory address */ |
68 size_t length; |
70 struct db_list *next; |
69 } *db_info; |
71 }; |
70 |
72 |
71 static int db_count; /* number of currently accessible data bases */ |
73 struct db_cache { |
|
74 char *loc; |
|
75 struct db_list *info; |
|
76 struct db_cache *next; |
|
77 }; |
|
78 |
|
79 static struct db_cache *db_cache; |
72 |
80 |
73 char * |
81 char * |
74 gettxt(const char *msg_id, const char *dflt_str) |
82 gettxt(const char *msg_id, const char *dflt_str) |
75 { |
83 { |
76 char msgfile[DB_NAME_LEN]; /* name of static shared library */ |
84 struct db_cache *dbc; |
77 int msgnum; /* message number */ |
85 struct db_list *dbl; |
78 char pathname[PATH_MAX]; /* full pathname to message file */ |
86 char msgfile[DB_NAME_LEN]; /* name of static shared library */ |
79 int i; |
87 int msgnum; /* message number */ |
80 int new_locale = 0; |
88 char pathname[PATH_MAX]; /* full pathname to message file */ |
81 int fd; |
89 int fd; |
82 struct stat64 sb; |
90 struct stat64 sb; |
83 void *addr; |
91 void *addr; |
84 char *tokp; |
92 char *tokp; |
85 size_t name_len; |
93 size_t name_len; |
86 char *curloc; |
94 char *curloc; |
87 |
95 |
88 if ((msg_id == NULL) || (*msg_id == NULL)) { |
96 if ((msg_id == NULL) || (*msg_id == '\0')) { |
89 return (handle_return(dflt_str)); |
97 return (handle_return(dflt_str)); |
90 } |
|
91 |
|
92 /* first time called, allocate space */ |
|
93 if (!db_info) { |
|
94 if ((db_info = (struct db_info *) \ |
|
95 malloc(MAXDB * sizeof (struct db_info))) == NULL) |
|
96 return (handle_return(dflt_str)); |
|
97 } |
98 } |
98 |
99 |
99 /* parse msg_id */ |
100 /* parse msg_id */ |
100 |
|
101 if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0') |
101 if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0') |
102 return (handle_return(dflt_str)); |
102 return (handle_return(dflt_str)); |
103 if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN) |
103 if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN) |
104 return (handle_return(dflt_str)); |
104 return (handle_return(dflt_str)); |
105 if (name_len) { |
105 if (name_len > 0) { |
106 (void) strncpy(msgfile, msg_id, name_len); |
106 (void) strncpy(msgfile, msg_id, name_len); |
107 msgfile[name_len] = '\0'; |
107 msgfile[name_len] = '\0'; |
108 } else { |
108 } else { |
109 if (Msgdb && strlen(Msgdb) < DB_NAME_LEN) |
109 lrw_rdlock(&_rw_cur_cat); |
110 (void) strcpy(msgfile, Msgdb); |
110 if (cur_cat == NULL || *cur_cat == '\0') { |
111 else { |
111 lrw_unlock(&_rw_cur_cat); |
112 char *p; |
112 return (handle_return(dflt_str)); |
113 p = (char *)setcat((const char *)0); |
113 } |
114 if ((p != NULL) && strlen(p) < DB_NAME_LEN) |
114 /* |
115 (void) strcpy(msgfile, p); |
115 * We know the following strcpy is safe. |
116 else |
116 */ |
117 return (handle_return(dflt_str)); |
117 (void) strcpy(msgfile, cur_cat); |
118 } |
118 lrw_unlock(&_rw_cur_cat); |
119 } |
119 } |
120 while (*++tokp) |
120 while (*++tokp) { |
121 if (!isdigit(*tokp)) |
121 if (!isdigit((unsigned char)*tokp)) |
122 return (handle_return(dflt_str)); |
122 return (handle_return(dflt_str)); |
|
123 } |
123 msgnum = atoi(msg_id + name_len + 1); |
124 msgnum = atoi(msg_id + name_len + 1); |
124 |
|
125 /* Has locale been changed? */ |
|
126 |
|
127 curloc = setlocale(LC_MESSAGES, NULL); |
125 curloc = setlocale(LC_MESSAGES, NULL); |
128 if (saved_locale != NULL && strcmp(curloc, saved_locale) == 0) { |
126 |
129 for (i = 0; i < db_count; i++) |
127 lmutex_lock(&gettxt_lock); |
130 if (strcmp(db_info[i].db_name, msgfile) == 0) |
128 |
131 break; |
129 try_C: |
132 } else { /* new locale - clear everything */ |
130 dbc = db_cache; |
133 if (saved_locale) |
131 while (dbc) { |
134 free(saved_locale); |
132 if (strcmp(curloc, dbc->loc) == 0) { |
135 /* |
133 dbl = dbc->info; |
136 * allocate at least 2 bytes, so that we can copy "C" |
134 while (dbl) { |
137 * without re-allocating the saved_locale. |
135 if (strcmp(msgfile, dbl->db_name) == 0) { |
138 */ |
136 /* msgfile found */ |
139 if ((saved_locale = malloc(strlen(curloc)+2)) == NULL) |
137 lmutex_unlock(&gettxt_lock); |
140 return (handle_return(dflt_str)); |
138 goto msgfile_found; |
141 (void) strcpy(saved_locale, curloc); |
139 } |
142 for (i = 0; i < db_count; i++) { |
140 dbl = dbl->next; |
143 (void) munmap((void *)db_info[i].addr, |
|
144 db_info[i].length); |
|
145 (void) strcpy(db_info[i].db_name, ""); |
|
146 new_locale++; |
|
147 } |
|
148 db_count = 0; |
|
149 } |
|
150 if (new_locale || i == db_count) { |
|
151 if (db_count == MAXDB) |
|
152 return (handle_return(dflt_str)); |
|
153 if (snprintf(pathname, sizeof (pathname), |
|
154 _DFLT_LOC_PATH "%s" MESSAGES "%s", |
|
155 saved_locale, msgfile) >= sizeof (pathname)) { |
|
156 return (handle_return(dflt_str)); |
|
157 } |
|
158 if ((fd = open(pathname, O_RDONLY)) == -1 || |
|
159 fstat64(fd, &sb) == -1 || |
|
160 (addr = mmap(0, (size_t)sb.st_size, |
|
161 PROT_READ, MAP_SHARED, |
|
162 fd, 0)) == MAP_FAILED) { |
|
163 if (fd != -1) |
|
164 (void) close(fd); |
|
165 if (strcmp(saved_locale, "C") == 0) |
|
166 return (handle_return(dflt_str)); |
|
167 |
|
168 /* Change locale to C */ |
|
169 |
|
170 if (snprintf(pathname, sizeof (pathname), |
|
171 _DFLT_LOC_PATH "C" MESSAGES "%s", |
|
172 msgfile) >= sizeof (pathname)) { |
|
173 return (handle_return(dflt_str)); |
|
174 } |
141 } |
175 |
142 /* not found */ |
176 for (i = 0; i < db_count; i++) { |
143 break; |
177 (void) munmap((void *)db_info[i].addr, |
144 } |
178 db_info[i].length); |
145 dbc = dbc->next; |
179 (void) strcpy(db_info[i].db_name, ""); |
146 } |
180 } |
147 if (dbc == NULL) { |
181 db_count = 0; |
148 /* new locale */ |
182 if ((fd = open(pathname, O_RDONLY)) != -1 && |
149 if ((dbc = lmalloc(sizeof (struct db_cache))) == NULL) { |
183 fstat64(fd, &sb) != -1 && |
150 lmutex_unlock(&gettxt_lock); |
184 (addr = mmap(0, (size_t)sb.st_size, |
151 return (handle_return(dflt_str)); |
185 PROT_READ, MAP_SHARED, |
152 } |
186 fd, 0)) != MAP_FAILED) { |
153 if ((dbc->loc = lmalloc(strlen(curloc) + 1)) == NULL) { |
187 (void) strcpy(saved_locale, "C"); |
154 lfree(dbc, sizeof (struct db_cache)); |
188 } else { |
155 lmutex_unlock(&gettxt_lock); |
189 if (fd != -1) |
156 return (handle_return(dflt_str)); |
190 (void) close(fd); |
157 } |
191 return (handle_return(dflt_str)); |
158 dbc->info = NULL; |
192 } |
159 (void) strcpy(dbc->loc, curloc); |
193 } |
160 /* connect dbc to the dbc list */ |
|
161 dbc->next = db_cache; |
|
162 db_cache = dbc; |
|
163 } |
|
164 if ((dbl = lmalloc(sizeof (struct db_list))) == NULL) { |
|
165 lmutex_unlock(&gettxt_lock); |
|
166 return (handle_return(dflt_str)); |
|
167 } |
|
168 |
|
169 if (snprintf(pathname, sizeof (pathname), |
|
170 _DFLT_LOC_PATH "%s" MESSAGES "%s", dbc->loc, msgfile) >= |
|
171 sizeof (pathname)) { |
|
172 lfree(dbl, sizeof (struct db_list)); |
|
173 lmutex_unlock(&gettxt_lock); |
|
174 return (handle_return(dflt_str)); |
|
175 } |
|
176 if ((fd = open(pathname, O_RDONLY)) == -1 || |
|
177 fstat64(fd, &sb) == -1 || |
|
178 (addr = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED, |
|
179 fd, 0L)) == MAP_FAILED) { |
194 if (fd != -1) |
180 if (fd != -1) |
195 (void) close(fd); |
181 (void) close(fd); |
196 |
182 lfree(dbl, sizeof (struct db_list)); |
197 /* save file name, memory address, fd and size */ |
183 |
198 |
184 if (strcmp(dbc->loc, "C") == 0) { |
199 (void) strcpy(db_info[db_count].db_name, msgfile); |
185 lmutex_unlock(&gettxt_lock); |
200 db_info[db_count].addr = (uintptr_t)addr; |
186 return (handle_return(dflt_str)); |
201 db_info[db_count].length = (size_t)sb.st_size; |
187 } |
202 i = db_count; |
188 /* Change locale to C */ |
203 db_count++; |
189 curloc = (char *)loc_C; |
204 } |
190 goto try_C; |
|
191 } |
|
192 (void) close(fd); |
|
193 |
|
194 /* save file name, memory address, fd and size */ |
|
195 (void) strcpy(dbl->db_name, msgfile); |
|
196 dbl->addr = (uintptr_t)addr; |
|
197 |
|
198 /* connect dbl to the dbc->info list */ |
|
199 dbl->next = dbc->info; |
|
200 dbc->info = dbl; |
|
201 |
|
202 lmutex_unlock(&gettxt_lock); |
|
203 |
|
204 msgfile_found: |
205 /* check if msgnum out of domain */ |
205 /* check if msgnum out of domain */ |
206 if (msgnum <= 0 || msgnum > *(int *)(db_info[i].addr)) |
206 if (msgnum <= 0 || msgnum > *(int *)dbl->addr) |
207 return (handle_return(dflt_str)); |
207 return (handle_return(dflt_str)); |
208 /* return pointer to message */ |
208 /* return pointer to message */ |
209 return ((char *)(db_info[i].addr + *(int *)(db_info[i].addr |
209 return ((char *)(dbl->addr + |
210 + msgnum * sizeof (int)))); |
210 *(int *)(dbl->addr + msgnum * sizeof (int)))); |
211 } |
211 } |
212 |
|
213 char * |
|
214 handle_return(const char *dflt_str) |
|
215 { |
|
216 return ((char *)(dflt_str && *dflt_str ? dflt_str : not_found)); |
|
217 } |
|