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