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 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 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 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 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 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 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 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 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 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