Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / dlfcn / eval.c
1 /* You don't really want to know what this hack is for.
2    Copyright (C) 1996-2013 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
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.
9
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.
14
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/>.  */
18
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>
28
29 static void *funcall (char **stringp) __attribute_noinline__;
30 static void *eval (char **stringp);
31
32
33 long int weak_function
34 __strtol_internal (const char *nptr, char **endptr, int base, int group)
35 {
36   unsigned long int result = 0;
37   long int sign = 1;
38
39   while (*nptr == ' ' || *nptr == '\t')
40     ++nptr;
41
42   if (*nptr == '-')
43     {
44       sign = -1;
45       ++nptr;
46     }
47   else if (*nptr == '+')
48     ++nptr;
49
50   if (*nptr < '0' || *nptr > '9')
51     {
52       if (endptr != NULL)
53         *endptr = (char *) nptr;
54       return 0L;
55     }
56
57   assert (base == 0);
58   base = 10;
59   if (*nptr == '0')
60     {
61       if (nptr[1] == 'x' || nptr[1] == 'X')
62         {
63           base = 16;
64           nptr += 2;
65         }
66       else
67         base = 8;
68     }
69
70   while (*nptr >= '0' && *nptr <= '9')
71     {
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)))
77         {
78           errno = ERANGE;
79           return sign > 0 ? LONG_MAX : LONG_MIN;
80         }
81       result *= base;
82       result += digval;
83       ++nptr;
84     }
85
86   return (long int) result * sign;
87 }
88
89
90 static void *
91 funcall (char **stringp)
92 {
93   void *args[strlen (*stringp)], **ap = args;
94   void *argcookie = &args[1];
95
96   do
97     {
98       /* Evaluate the next token.  */
99       *ap++ = eval (stringp);
100
101       /* Whitespace is irrelevant.  */
102       while (isspace (**stringp))
103         ++*stringp;
104
105       /* Terminate at closing paren or end of line.  */
106     } while (**stringp != '\0' && **stringp != ')');
107   if (**stringp != '\0')
108     /* Swallow closing paren.  */
109     ++*stringp;
110
111   if (args[0] == NULL)
112     {
113       static const char unknown[] = "Unknown function\n";
114       write (1, unknown, sizeof unknown - 1);
115       return NULL;
116     }
117
118   /* Do it to it.  */
119   __builtin_return (__builtin_apply (args[0],
120                                      &argcookie,
121                                      (char *) ap - (char *) &args[1]));
122 }
123
124 static void *
125 eval (char **stringp)
126 {
127   void *value;
128   char *p = *stringp, c;
129
130   /* Whitespace is irrelevant.  */
131   while (isspace (*p))
132     ++p;
133
134   switch (*p)
135     {
136     case '"':
137       /* String constant.  */
138       value = ++p;
139       do
140         if (*p == '\\')
141           {
142             switch (*strcpy (p, p + 1))
143               {
144               case 't':
145                 *p = '\t';
146                 break;
147               case 'n':
148                 *p = '\n';
149                 break;
150               }
151             ++p;
152           }
153       while (*p != '\0' && *p++ != '"');
154       if (p[-1] == '"')
155         p[-1] = '\0';
156       break;
157
158     case '(':
159       *stringp = ++p;
160       return funcall (stringp);
161
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;
167
168       /* Anything else is a symbol that produces its address.  */
169       value = p;
170       do
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;
178     }
179
180   *stringp = p;
181   return value;
182 }
183
184
185 extern void _start (void) __attribute__ ((noreturn));
186 void
187 __attribute__ ((noreturn))
188 _start (void)
189 {
190   char *buf = NULL;
191   size_t bufsz = 0;
192
193   while (__getdelim (&buf, &bufsz, '\n', stdin) > 0)
194     {
195       char *p = buf;
196       eval (&p);
197     }
198
199   exit (0);
200 }