• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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