Update.
[kopensolaris-gnu/glibc.git] / dlfcn / eval.c
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.
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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <ctype.h>
22 #include <dlfcn.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 static void *funcall (char **stringp) __attribute_noinline__;
31 static void *eval (char **stringp);
32
33
34 long int weak_function
35 __strtol_internal (const char *nptr, char **endptr, int base, int group)
36 {
37   unsigned long int result = 0;
38   long int sign = 1;
39
40   while (*nptr == ' ' || *nptr == '\t')
41     ++nptr;
42
43   if (*nptr == '-')
44     {
45       sign = -1;
46       ++nptr;
47     }
48   else if (*nptr == '+')
49     ++nptr;
50
51   if (*nptr < '0' || *nptr > '9')
52     {
53       if (endptr != NULL)
54         *endptr = (char *) nptr;
55       return 0L;
56     }
57
58   assert (base == 0);
59   base = 10;
60   if (*nptr == '0')
61     {
62       if (nptr[1] == 'x' || nptr[1] == 'X')
63         {
64           base = 16;
65           nptr += 2;
66         }
67       else
68         base = 8;
69     }
70
71   while (*nptr >= '0' && *nptr <= '9')
72     {
73       unsigned long int digval = *nptr - '0';
74       if (result > LONG_MAX / 10
75           || (sign > 0 ? result == LONG_MAX / 10 && digval > LONG_MAX % 10
76               : (result == ((unsigned long int) LONG_MAX + 1) / 10
77                  && digval > ((unsigned long int) LONG_MAX + 1) % 10)))
78         {
79           errno = ERANGE;
80           return sign > 0 ? LONG_MAX : LONG_MIN;
81         }
82       result *= base;
83       result += digval;
84       ++nptr;
85     }
86
87   return (long int) result * sign;
88 }
89
90
91 static void *
92 funcall (char **stringp)
93 {
94   void *args[strlen (*stringp)], **ap = args;
95   void *argcookie = &args[1];
96
97   do
98     {
99       /* Evaluate the next token.  */
100       *ap++ = eval (stringp);
101
102       /* Whitespace is irrelevant.  */
103       while (isspace (**stringp))
104         ++*stringp;
105
106       /* Terminate at closing paren or end of line.  */
107     } while (**stringp != '\0' && **stringp != ')');
108   if (**stringp != '\0')
109     /* Swallow closing paren.  */
110     ++*stringp;
111
112   if (args[0] == NULL)
113     {
114       static const char unknown[] = "Unknown function\n";
115       write (1, unknown, sizeof unknown - 1);
116       return NULL;
117     }
118
119   /* Do it to it.  */
120   __builtin_return (__builtin_apply (args[0],
121                                      &argcookie,
122                                      (char *) ap - (char *) &args[1]));
123 }
124
125 static void *
126 eval (char **stringp)
127 {
128   void *value;
129   char *p = *stringp, c;
130
131   /* Whitespace is irrelevant.  */
132   while (isspace (*p))
133     ++p;
134
135   switch (*p)
136     {
137     case '"':
138       /* String constant.  */
139       value = ++p;
140       do
141         if (*p == '\\')
142           {
143             switch (*strcpy (p, p + 1))
144               {
145               case 't':
146                 *p = '\t';
147                 break;
148               case 'n':
149                 *p = '\n';
150                 break;
151               }
152             ++p;
153           }
154       while (*p != '\0' && *p++ != '"');
155       if (p[-1] == '"')
156         p[-1] = '\0';
157       break;
158
159     case '(':
160       *stringp = ++p;
161       return funcall (stringp);
162
163     default:
164       /* Try to parse it as a number.  */
165       value = (void *) __strtol_internal (p, stringp, 0, 0);
166       if (*stringp != p)
167         return value;
168
169       /* Anything else is a symbol that produces its address.  */
170       value = p;
171       do
172         ++p;
173       while (*p != '\0' && !isspace (*p) && (!ispunct (*p) || *p == '_'));
174       c = *p;
175       *p = '\0';
176       value = dlsym (NULL, value);
177       *p = c;
178       break;
179     }
180
181   *stringp = p;
182   return value;
183 }
184
185
186 extern void _start (void) __attribute__ ((noreturn));
187 void
188 __attribute__ ((noreturn))
189 _start (void)
190 {
191   char *buf = NULL;
192   size_t bufsz = 0;
193
194   while (__getdelim (&buf, &bufsz, '\n', stdin) > 0)
195     {
196       char *p = buf;
197       eval (&p);
198     }
199
200   exit (0);
201 }