1 /*
2 * Copyright 2001-2004 Brandon Long
3 * All Rights Reserved.
4 *
5 * ClearSilver Templating System
6 *
7 * This code is made available under the terms of the ClearSilver License.
8 * http://www.clearsilver.net/license.hdf
9 *
10 */
11
12 #include "cs_config.h"
13
14 #if HAVE_FEATURES_H
15 #include <features.h>
16 #endif
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include "util/neo_misc.h"
22 #include "util/neo_err.h"
23 #include "cgi/cgiwrap.h"
24
25 typedef struct _cgiwrapper
26 {
27 int argc;
28 char **argv;
29 char **envp;
30 int env_count;
31
32 READ_FUNC read_cb;
33 WRITEF_FUNC writef_cb;
34 WRITE_FUNC write_cb;
35 GETENV_FUNC getenv_cb;
36 PUTENV_FUNC putenv_cb;
37 ITERENV_FUNC iterenv_cb;
38
39 void *data;
40 int emu_init;
41 } CGIWRAPPER;
42
43 static CGIWRAPPER GlobalWrapper = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0};
44
cgiwrap_init_std(int argc,char ** argv,char ** envp)45 void cgiwrap_init_std (int argc, char **argv, char **envp)
46 {
47 /* Allow setting of these even after cgiwrap_init_emu is called */
48 GlobalWrapper.argc = argc;
49 GlobalWrapper.argv = argv;
50 GlobalWrapper.envp = envp;
51 GlobalWrapper.env_count = 0;
52 while (envp[GlobalWrapper.env_count] != NULL) GlobalWrapper.env_count++;
53
54 /* so you can compile the same code for embedded without mods.
55 * Note that this setting is global for the lifetime of the program, so
56 * you can never reset these values after calling cgiwrap_init_emu by
57 * calling cgiwrap_init_std, you'll have to call cgiwrap_init_emu with NULL
58 * values to reset */
59 if (GlobalWrapper.emu_init) return;
60
61 GlobalWrapper.read_cb = NULL;
62 GlobalWrapper.writef_cb = NULL;
63 GlobalWrapper.write_cb = NULL;
64 GlobalWrapper.getenv_cb = NULL;
65 GlobalWrapper.putenv_cb = NULL;
66 GlobalWrapper.iterenv_cb = NULL;
67 GlobalWrapper.data = NULL;
68 }
69
cgiwrap_init_emu(void * data,READ_FUNC read_cb,WRITEF_FUNC writef_cb,WRITE_FUNC write_cb,GETENV_FUNC getenv_cb,PUTENV_FUNC putenv_cb,ITERENV_FUNC iterenv_cb)70 void cgiwrap_init_emu (void *data, READ_FUNC read_cb,
71 WRITEF_FUNC writef_cb, WRITE_FUNC write_cb, GETENV_FUNC getenv_cb,
72 PUTENV_FUNC putenv_cb, ITERENV_FUNC iterenv_cb)
73 {
74 /* leave argc, argv, envp, env_count alone since we either don't use them, or
75 * they are used by the default versions if any of these are passed as NULL.
76 * Note that means that if you pass NULL for anything here, you'd better
77 * have called cgiwrap_init_std first! */
78 GlobalWrapper.data = data;
79 GlobalWrapper.read_cb = read_cb;
80 GlobalWrapper.writef_cb = writef_cb;
81 GlobalWrapper.write_cb = write_cb;
82 GlobalWrapper.getenv_cb = getenv_cb;
83 GlobalWrapper.putenv_cb = putenv_cb;
84 GlobalWrapper.iterenv_cb = iterenv_cb;
85 GlobalWrapper.emu_init = 1;
86 }
87
cgiwrap_getenv(const char * k,char ** v)88 NEOERR *cgiwrap_getenv (const char *k, char **v)
89 {
90 if (GlobalWrapper.getenv_cb != NULL)
91 {
92 *v = GlobalWrapper.getenv_cb (GlobalWrapper.data, k);
93 }
94 else
95 {
96 char *s = getenv(k);
97
98 if (s != NULL)
99 {
100 *v = strdup(s);
101 if (*v == NULL)
102 {
103 return nerr_raise (NERR_NOMEM, "Unable to duplicate env var %s=%s",
104 k, s);
105 }
106 }
107 else
108 {
109 *v = NULL;
110 }
111 }
112 return STATUS_OK;
113 }
114
cgiwrap_putenv(const char * k,const char * v)115 NEOERR *cgiwrap_putenv (const char *k, const char *v)
116 {
117 if (GlobalWrapper.putenv_cb != NULL)
118 {
119 if (GlobalWrapper.putenv_cb(GlobalWrapper.data, k, v))
120 return nerr_raise(NERR_NOMEM, "putenv_cb says nomem when %s=%s", k, v);
121 }
122 else
123 {
124 char *buf;
125 int l;
126 l = strlen(k) + strlen(v) + 2;
127 buf = (char *) malloc(sizeof(char) * l);
128 if (buf == NULL)
129 return nerr_raise(NERR_NOMEM, "Unable to allocate memory for putenv %s=%s", k, v);
130 snprintf (buf, l, "%s=%s", k, v);
131 if (putenv (buf))
132 return nerr_raise(NERR_NOMEM, "putenv says nomem when %s", buf);
133 }
134 return STATUS_OK;
135 }
136
cgiwrap_iterenv(int num,char ** k,char ** v)137 NEOERR *cgiwrap_iterenv (int num, char **k, char **v)
138 {
139 *k = NULL;
140 *v = NULL;
141 if (GlobalWrapper.iterenv_cb != NULL)
142 {
143 int r;
144
145 r = GlobalWrapper.iterenv_cb(GlobalWrapper.data, num, k, v);
146 if (r)
147 return nerr_raise(NERR_SYSTEM, "iterenv_cb returned %d", r);
148 }
149 else if (GlobalWrapper.envp != NULL && num < GlobalWrapper.env_count)
150 {
151 char *c, *s = GlobalWrapper.envp[num];
152
153 c = strchr (s, '=');
154 if (c == NULL) return STATUS_OK;
155 *c = '\0';
156 *k = strdup(s);
157 *c = '=';
158 if (*k == NULL)
159 return nerr_raise(NERR_NOMEM, "iterenv says nomem for %s", s);
160 *v = strdup(c+1);
161 if (*v == NULL)
162 {
163 free(*k);
164 *k = NULL;
165 return nerr_raise(NERR_NOMEM, "iterenv says nomem for %s", s);
166 }
167 }
168 return STATUS_OK;
169 }
170
cgiwrap_writef(const char * fmt,...)171 NEOERR *cgiwrap_writef (const char *fmt, ...)
172 {
173 va_list ap;
174
175 va_start (ap, fmt);
176 cgiwrap_writevf (fmt, ap);
177 va_end (ap);
178 return STATUS_OK;
179 }
180
cgiwrap_writevf(const char * fmt,va_list ap)181 NEOERR *cgiwrap_writevf (const char *fmt, va_list ap)
182 {
183 int r;
184
185 if (GlobalWrapper.writef_cb != NULL)
186 {
187 r = GlobalWrapper.writef_cb (GlobalWrapper.data, fmt, ap);
188 if (r)
189 return nerr_raise_errno (NERR_IO, "writef_cb returned %d", r);
190 }
191 else
192 {
193 vprintf (fmt, ap);
194 /* vfprintf(stderr, fmt, ap); */
195 }
196 return STATUS_OK;
197 }
198
cgiwrap_write(const char * buf,int buf_len)199 NEOERR *cgiwrap_write (const char *buf, int buf_len)
200 {
201 int r;
202
203 if (GlobalWrapper.write_cb != NULL)
204 {
205 r = GlobalWrapper.write_cb (GlobalWrapper.data, buf, buf_len);
206 if (r != buf_len)
207 return nerr_raise_errno (NERR_IO, "write_cb returned %d<%d", r, buf_len);
208 }
209 else
210 {
211 /* r = fwrite(buf, sizeof(char), buf_len, stderr); */
212 r = fwrite(buf, sizeof(char), buf_len, stdout);
213 if (r != buf_len)
214 return nerr_raise_errno (NERR_IO, "fwrite returned %d<%d", r, buf_len);
215 }
216 return STATUS_OK;
217 }
218
cgiwrap_read(char * buf,int buf_len,int * read_len)219 void cgiwrap_read (char *buf, int buf_len, int *read_len)
220 {
221 if (GlobalWrapper.read_cb != NULL)
222 {
223 *read_len = GlobalWrapper.read_cb (GlobalWrapper.data, buf, buf_len);
224 }
225 else
226 {
227 #ifdef __UCLIBC__
228 /* According to
229 * http://cvs.uclinux.org/cgi-bin/cvsweb.cgi/uClibc/libc/stdio/stdio.c#rev1.28
230 * Note: there is a difference in behavior between glibc and uClibc here
231 * regarding fread() on a tty stream. glibc's fread() seems to return
232 * after reading all _available_ data even if not at end-of-file, while
233 * uClibc's fread() continues reading until all requested or eof or error.
234 * The latter behavior seems correct w.r.t. the standards.
235 *
236 * So, we use read on uClibc. This may be required on other platforms as
237 * well. Using raw and buffered i/o interchangeably can be problematic,
238 * but everyone should be going through the cgiwrap interfaces which only
239 * provide this one read function.
240 */
241 *read_len = read (fileno(stdin), buf, buf_len);
242 #else
243 *read_len = fread (buf, sizeof(char), buf_len, stdin);
244 #endif
245 }
246 }
247