1 /* This file contains library-wide symbols that are always needed when one
2 * links to the library.
3 */
4 /*
5 Copyright (C) 2004-2017,2018 John E. Davis
6
7 This file is part of the S-Lang Library.
8
9 The S-Lang Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 The S-Lang Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 USA.
23 */
24 #ifndef _GNU_SOURCE
25 # define _GNU_SOURCE
26 #endif
27 #include "slinclud.h"
28
29 #include <errno.h>
30 #include "slang.h"
31 #include "_slang.h"
32
33 #ifdef HAVE_LOCALE_H
34 # include <locale.h>
35 #endif
36
37 #ifdef HAVE_LANGINFO_H
38 # include <langinfo.h>
39 #endif
40
41 #if defined(__WIN32__)
42 # include <windows.h>
43 #endif
44
45 #define SLSYSWRAP_REALLOC realloc
46 #define SLSYSWRAP_MALLOC malloc
47 #ifdef SLSYSWRAP
48 # include <slsyswrap.h>
49 #endif
50
51 int SLang_Version = SLANG_VERSION;
52 SLFUTURE_CONST char *SLang_Version_String = SLANG_VERSION_STRING;
53
54 int _pSLinterp_UTF8_Mode = 0;
55 int _pSLtt_UTF8_Mode = 0;
56 int _pSLutf8_mode = 0;
57
58 #ifndef HAVE_LOCALE_H
59 # define setlocale(x,y) (NULL)
60 # define LC_ALL 0
61 #endif
62
SLutf8_is_utf8_mode(void)63 int SLutf8_is_utf8_mode (void)
64 {
65 return _pSLutf8_mode;
66 }
67
SLinterp_utf8_enable(int mode)68 int SLinterp_utf8_enable (int mode)
69 {
70 if (mode == -1)
71 mode = _pSLutf8_mode;
72
73 return _pSLinterp_UTF8_Mode = mode;
74 }
75
SLinterp_is_utf8_mode(void)76 int SLinterp_is_utf8_mode (void)
77 {
78 return _pSLinterp_UTF8_Mode;
79 }
80
utf8_enable(int mode)81 static int utf8_enable (int mode)
82 {
83 char *locale;
84
85 if (mode != -1)
86 return (mode != 0);
87
88 #if defined(__WIN32__)
89 if (GetConsoleOutputCP () == 65001)
90 return 1;
91 #endif
92
93 (void) setlocale (LC_ALL, "");
94
95 #ifdef HAVE_NL_LANGINFO_CODESET
96 locale = nl_langinfo (CODESET);
97 # ifdef SLSYSWRAP
98 {
99 char *env;
100 if ((NULL != (env = getenv ("SLTEST_NO_LANGINFO")))
101 && (atoi (env) != 0))
102 locale = NULL; /* skip this block of code */
103 }
104 # endif
105 if ((locale != NULL) && (*locale))
106 {
107 if ((0 == strcmp (locale, "UTF-8"))
108 || (0 == strcmp (locale, "utf-8"))
109 || (0 == strcmp (locale, "utf8"))
110 || (0 == strcmp (locale, "UTF8")))
111 return 1;
112
113 return 0;
114 }
115 #endif
116
117 locale = setlocale (LC_ALL, "");
118
119 if (((locale == NULL) || (*locale == 0))
120 && ((NULL == (locale = getenv ("LC_ALL"))) || (*locale == 0))
121 && ((NULL == (locale = getenv ("LC_CTYPE"))) || (*locale == 0))
122 && ((NULL == (locale = getenv ("LANG"))) || (*locale == 0)))
123 return 0;
124
125 /* setlocale man page says the return value is something like:
126 * language[_territory][.codeset][@modifier][+special][,...
127 * Here, we want the codeset, if present.
128 */
129
130 while (*locale && (*locale != '.') && (*locale != '@')
131 && (*locale != '+') && (*locale != ','))
132 locale++;
133
134 if (*locale == '.')
135 {
136 locale++;
137 if (0 == strncmp (locale, "UTF-8", 5))
138 locale += 5;
139 else if (0 == strncmp (locale, "utf8", 4))
140 locale += 4;
141 else
142 return 0;
143
144 if ((*locale == 0) || (*locale == '@')
145 || (*locale == '+') || (*locale == ','))
146 return 1;
147 }
148
149 return 0;
150 }
151
152 /* Returns the value of _pSLutf8_mode */
SLutf8_enable(int mode)153 int SLutf8_enable (int mode)
154 {
155 char *cjk;
156
157 mode = utf8_enable (mode);
158 _pSLutf8_mode = mode;
159 _pSLtt_UTF8_Mode = mode;
160 _pSLinterp_UTF8_Mode = mode;
161 if (mode && (NULL != (cjk = getenv ("WCWIDTH_CJK_LEGACY"))))
162 {
163 if ((*cjk == 0) || (0==strcmp(cjk,"yes")))
164 (void) SLwchar_set_wcwidth_flags (SLWCWIDTH_CJK_LEGACY);
165 }
166 return mode;
167 }
168
169 /* Mallocing 0 bytes leads to undefined behavior. Some C libraries will
170 * return NULL, and others return non-NULL. Here, if 0 bytes is requested,
171 * and the library malloc function returns NULL, then malloc will be retried
172 * using 1 byte.
173 */
SLmalloc(SLstrlen_Type len)174 SLFUTURE_VOID *SLmalloc (SLstrlen_Type len)
175 {
176 SLFUTURE_VOID *p;
177
178 if (NULL != (p = (SLFUTURE_VOID *)SLSYSWRAP_MALLOC(len)))
179 return p;
180
181 if (len || (NULL == (p = (SLFUTURE_VOID *)SLSYSWRAP_MALLOC(1))))
182 SLang_set_error (SL_MALLOC_ERROR);
183
184 return p;
185 }
186
SLfree(SLFUTURE_VOID * p)187 void SLfree (SLFUTURE_VOID *p)
188 {
189 if (p != NULL) free (p);
190 }
191
SLrealloc(SLFUTURE_VOID * p,SLstrlen_Type len)192 SLFUTURE_VOID *SLrealloc (SLFUTURE_VOID *p, SLstrlen_Type len)
193 {
194 if (len == 0)
195 {
196 SLfree (p);
197 return NULL;
198 }
199
200 if (p == NULL) p = SLmalloc (len);
201 else
202 {
203 p = (SLFUTURE_VOID *) SLSYSWRAP_REALLOC(p, len);
204 if (p == NULL)
205 SLang_set_error (SL_MALLOC_ERROR);
206 }
207 return p;
208 }
209
_SLrecalloc(SLFUTURE_VOID * p,SLstrlen_Type nelems,SLstrlen_Type len)210 SLFUTURE_VOID *_SLrecalloc (SLFUTURE_VOID *p, SLstrlen_Type nelems, SLstrlen_Type len)
211 {
212 unsigned int nlen = nelems * len;
213
214 if (nelems && (nlen/nelems != len))
215 {
216 SLang_set_error (SL_Malloc_Error);
217 return NULL;
218 }
219 return SLrealloc (p, nlen);
220 }
221
_SLcalloc(SLstrlen_Type nelems,SLstrlen_Type len)222 SLFUTURE_VOID *_SLcalloc (SLstrlen_Type nelems, SLstrlen_Type len)
223 {
224 SLstrlen_Type nlen = nelems * len;
225
226 if (nelems && (nlen/nelems != len))
227 {
228 SLang_set_error (SL_Malloc_Error);
229 return NULL;
230 }
231 return SLmalloc (nlen);
232 }
233
SLcalloc(SLstrlen_Type nelems,SLstrlen_Type len)234 SLFUTURE_VOID *SLcalloc (SLstrlen_Type nelems, SLstrlen_Type len)
235 {
236 SLFUTURE_VOID *p = _SLcalloc (nelems, len);
237 if (p != NULL) memset (p, 0, len*nelems);
238 return p;
239 }
240
_pSLsecure_issetugid(void)241 int _pSLsecure_issetugid (void)
242 {
243 #ifdef HAVE_ISSETUGID
244 return (1 == issetugid ());
245 #else
246 # if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && defined(HAVE_GETGID) && defined(HAVE_GETEUID)
247 static int enable_secure;
248 if (enable_secure == 0)
249 {
250 if ((getuid () != geteuid ())
251 || (getgid () != getegid ()))
252 enable_secure = 1;
253 else
254 enable_secure = -1;
255 }
256 return (enable_secure == 1);
257 # else
258 return 0;
259 # endif
260 #endif
261 }
262
263 /* Like getenv, except if running as setuid or setgid, returns NULL */
_pSLsecure_getenv(SLCONST char * s)264 char *_pSLsecure_getenv (SLCONST char *s)
265 {
266 if (_pSLsecure_issetugid ())
267 return NULL;
268 return getenv (s);
269 }
270
271 typedef struct Interrupt_Hook_Type
272 {
273 int (*func)(VOID_STAR);
274 VOID_STAR client_data;
275 struct Interrupt_Hook_Type *next;
276 }
277 Interrupt_Hook_Type;
278
279 static Interrupt_Hook_Type *Interrupt_Hooks = NULL;
280
281 static Interrupt_Hook_Type *
find_interrupt_hook(int (* func)(VOID_STAR),VOID_STAR cd,Interrupt_Hook_Type ** prevp)282 find_interrupt_hook (int (*func)(VOID_STAR), VOID_STAR cd,
283 Interrupt_Hook_Type **prevp)
284 {
285 Interrupt_Hook_Type *h = Interrupt_Hooks;
286 Interrupt_Hook_Type *prev = NULL;
287 while (h != NULL)
288 {
289 if ((h->func == func) && (h->client_data == cd))
290 {
291 if (prevp != NULL)
292 *prevp = prev;
293 return h;
294 }
295 prev = h;
296 h = h->next;
297 }
298 return NULL;
299 }
300
SLang_add_interrupt_hook(int (* func)(VOID_STAR),VOID_STAR cd)301 int SLang_add_interrupt_hook (int (*func)(VOID_STAR), VOID_STAR cd)
302 {
303 Interrupt_Hook_Type *h;
304
305 if (NULL != find_interrupt_hook (func, cd, NULL))
306 return 0;
307
308 if (NULL == (h = (Interrupt_Hook_Type *)SLmalloc (sizeof (Interrupt_Hook_Type))))
309 return -1;
310
311 h->func = func;
312 h->client_data = cd;
313 h->next = Interrupt_Hooks;
314 Interrupt_Hooks = h;
315 return 0;
316 }
317
SLang_remove_interrupt_hook(int (* func)(VOID_STAR),VOID_STAR cd)318 void SLang_remove_interrupt_hook (int (*func)(VOID_STAR), VOID_STAR cd)
319 {
320 Interrupt_Hook_Type *h, *hprev;
321
322 if (NULL == (h = find_interrupt_hook (func, cd, &hprev)))
323 return;
324
325 if (hprev == NULL)
326 Interrupt_Hooks = h->next;
327 else
328 hprev->next = h->next;
329
330 SLfree ((char *) h);
331 }
332
SLang_handle_interrupt(void)333 int SLang_handle_interrupt (void)
334 {
335 Interrupt_Hook_Type *h;
336 int status = 0;
337 int e = errno;
338 int se = _pSLerrno_errno;
339
340 h = Interrupt_Hooks;
341 while (h != NULL)
342 {
343 if (-1 == (*h->func)(h->client_data))
344 status = -1;
345
346 h = h->next;
347 }
348 errno = e;
349 _pSLerrno_errno = se;
350 return status;
351 }
352
353 int _pSLerrno_errno;
354
SLerrno_set_errno(int sys_errno)355 int SLerrno_set_errno (int sys_errno)
356 {
357 _pSLerrno_errno = sys_errno;
358 return 0;
359 }
360
361 #if defined(__WIN32__) && defined(SLANG_DLL)
362 # include <windows.h>
363
364 /* where is the prototype for DllMain? */
365 BOOL WINAPI DllMain(HANDLE hInstance,DWORD dwReason,LPVOID lpParam);
366
DllMain(HANDLE hInstance,DWORD dwReason,LPVOID lpParam)367 BOOL WINAPI DllMain(HANDLE hInstance,DWORD dwReason,LPVOID lpParam)
368 {
369 return 1;
370 }
371 #endif
372