Avoid overflows from long double functions using __kernel_standard.
[glibc.git] / dlfcn / eval.c
blobf40f5eab21e5b103ec9483fc71cdbbb81150cd3e
1 /* You don't really want to know what this hack is for.
2 Copyright (C) 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <dlfcn.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
29 static void *funcall (char **stringp) __attribute_noinline__;
30 static void *eval (char **stringp);
33 long int weak_function
34 __strtol_internal (const char *nptr, char **endptr, int base, int group)
36 unsigned long int result = 0;
37 long int sign = 1;
39 while (*nptr == ' ' || *nptr == '\t')
40 ++nptr;
42 if (*nptr == '-')
44 sign = -1;
45 ++nptr;
47 else if (*nptr == '+')
48 ++nptr;
50 if (*nptr < '0' || *nptr > '9')
52 if (endptr != NULL)
53 *endptr = (char *) nptr;
54 return 0L;
57 assert (base == 0);
58 base = 10;
59 if (*nptr == '0')
61 if (nptr[1] == 'x' || nptr[1] == 'X')
63 base = 16;
64 nptr += 2;
66 else
67 base = 8;
70 while (*nptr >= '0' && *nptr <= '9')
72 unsigned long int digval = *nptr - '0';
73 if (result > LONG_MAX / 10
74 || (sign > 0 ? result == LONG_MAX / 10 && digval > LONG_MAX % 10
75 : (result == ((unsigned long int) LONG_MAX + 1) / 10
76 && digval > ((unsigned long int) LONG_MAX + 1) % 10)))
78 errno = ERANGE;
79 return sign > 0 ? LONG_MAX : LONG_MIN;
81 result *= base;
82 result += digval;
83 ++nptr;
86 return (long int) result * sign;
90 static void *
91 funcall (char **stringp)
93 void *args[strlen (*stringp)], **ap = args;
94 void *argcookie = &args[1];
98 /* Evaluate the next token. */
99 *ap++ = eval (stringp);
101 /* Whitespace is irrelevant. */
102 while (isspace (**stringp))
103 ++*stringp;
105 /* Terminate at closing paren or end of line. */
106 } while (**stringp != '\0' && **stringp != ')');
107 if (**stringp != '\0')
108 /* Swallow closing paren. */
109 ++*stringp;
111 if (args[0] == NULL)
113 static const char unknown[] = "Unknown function\n";
114 write (1, unknown, sizeof unknown - 1);
115 return NULL;
118 /* Do it to it. */
119 __builtin_return (__builtin_apply (args[0],
120 &argcookie,
121 (char *) ap - (char *) &args[1]));
124 static void *
125 eval (char **stringp)
127 void *value;
128 char *p = *stringp, c;
130 /* Whitespace is irrelevant. */
131 while (isspace (*p))
132 ++p;
134 switch (*p)
136 case '"':
137 /* String constant. */
138 value = ++p;
140 if (*p == '\\')
142 switch (*strcpy (p, p + 1))
144 case 't':
145 *p = '\t';
146 break;
147 case 'n':
148 *p = '\n';
149 break;
151 ++p;
153 while (*p != '\0' && *p++ != '"');
154 if (p[-1] == '"')
155 p[-1] = '\0';
156 break;
158 case '(':
159 *stringp = ++p;
160 return funcall (stringp);
162 default:
163 /* Try to parse it as a number. */
164 value = (void *) __strtol_internal (p, stringp, 0, 0);
165 if (*stringp != p)
166 return value;
168 /* Anything else is a symbol that produces its address. */
169 value = p;
171 ++p;
172 while (*p != '\0' && !isspace (*p) && (!ispunct (*p) || *p == '_'));
173 c = *p;
174 *p = '\0';
175 value = dlsym (NULL, value);
176 *p = c;
177 break;
180 *stringp = p;
181 return value;
185 extern void _start (void) __attribute__ ((noreturn));
186 void
187 __attribute__ ((noreturn))
188 _start (void)
190 char *buf = NULL;
191 size_t bufsz = 0;
193 while (__getdelim (&buf, &bufsz, '\n', stdin) > 0)
195 char *p = buf;
196 eval (&p);
199 exit (0);