some fixes

Tue, 25 Jun 2013 15:45:13 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 25 Jun 2013 15:45:13 +0200
changeset 77
f1cff81e425a
parent 76
5f7660fe1562
child 78
3578977d29a3

some fixes

src/server/daemon/auth.c file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/configmanager.c file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/log.c file | annotate | diff | comparison | revisions
src/server/daemon/log.h file | annotate | diff | comparison | revisions
src/server/daemon/protocol.c file | annotate | diff | comparison | revisions
src/server/daemon/threadpools.c file | annotate | diff | comparison | revisions
src/server/safs/addlog.c file | annotate | diff | comparison | revisions
src/server/safs/auth.c file | annotate | diff | comparison | revisions
src/server/safs/init.c file | annotate | diff | comparison | revisions
src/server/safs/nametrans.c file | annotate | diff | comparison | revisions
src/server/safs/objecttype.c file | annotate | diff | comparison | revisions
src/server/safs/pathcheck.c file | annotate | diff | comparison | revisions
src/server/safs/service.c file | annotate | diff | comparison | revisions
src/server/util/pblock.cpp file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
--- a/src/server/daemon/auth.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/auth.c	Tue Jun 25 15:45:13 2013 +0200
@@ -41,8 +41,8 @@
     printf("auth_cache_init\n");
     // TODO: config parameters
     //pthread_mutex_init(&auth_cache_mutex, NULL);
-    cache.map = calloc(64, sizeof(UserCacheElm));
-    cache.size = 96;
+    cache.map = calloc(80, sizeof(UserCacheElm));
+    cache.size = 80;
     cache.count = 0;
     cache.max_users = 64;
     cache.head = NULL;
--- a/src/server/daemon/config.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/config.c	Tue Jun 25 15:45:13 2013 +0200
@@ -434,12 +434,23 @@
         return 0;
     }
     sstr_t format;
-    format.ptr = NULL; 
+    format.ptr = NULL;
+    format.length = 0;
     
-    AccessLog *log = get_access_log(file, format);
-    if(log) {
-        // access logs are only stored in the server config to free them
-        cfg->logfiles = ucx_list_append(cfg->logfiles, log);
+    //AccessLog *log = get_access_log(file, format);
+    LogFile *log_file = get_access_log_file(file);
+    if(!log_file) {
+        // TODO: error/warning
+        return 0;
+    }
+    AccessLog *log = pool_malloc(cfg->pool, sizeof(AccessLog));
+    log->file = sstrdup_pool(cfg->pool, file);
+    log->format = format;
+    log->log = log_file;
+    cfg->logfiles = ucx_list_append(cfg->logfiles, log);
+    
+    if(!cfg->default_log) {
+        cfg->default_log = log;
     }
     
     return 0;
@@ -632,7 +643,7 @@
     
     // set the access log for the virtual server
     // TODO: don't use always the default
-    vs->log = get_default_access_log();
+    vs->log = cfg->default_log;
 
     ucx_map_sstr_put(cfg->host_vs, vs->host, vs);
     
--- a/src/server/daemon/config.h	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/config.h	Tue Jun 25 15:45:13 2013 +0200
@@ -42,6 +42,7 @@
 
 #include "acldata.h"
 #include "keyfile_auth.h"
+#include "log.h"
 
 #include "../ucx/list.h"
 #include "../ucx/dlist.h"
@@ -60,6 +61,7 @@
     UcxMap          *host_vs;   // map of all vservers. key is the host name
     UcxList         *listeners; // list of all listeners
     UcxList         *logfiles;
+    AccessLog       *default_log;
     UcxMap          *authdbs;
     MimeMap         *mimetypes;
     sstr_t          tmp;
--- a/src/server/daemon/configmanager.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/configmanager.c	Tue Jun 25 15:45:13 2013 +0200
@@ -63,37 +63,6 @@
     return ucx_map_sstr_get(config_files, name);
 }
 
-// copy functions
-static void* copy_listener(HttpListener *ls, ServerConfiguration *cfg) {
-    /*
-     * we reuse the old listener, but change the
-     * ServerConfiguration and VirtualServer
-     */
-    http_listener_ref(ls);
-    
-    // TODO: this is non atomar
-    sstr_t vsname = ls->default_vs.vs->name;
-    ls->default_vs.vs = ucx_map_sstr_get(cfg->host_vs, vsname);
-    ls->cfg = cfg;
-    
-    return ls;
-}
-
-static void* copy_vs(void *vserver, void *pool) {
-    VirtualServer *vs = vs_copy(vserver, pool);
-    
-    /*
-     * this function is executed on configuration reload, so some
-     * VS configs may be changed
-     * 
-     * vs
-     *    objects
-     */
-    ConfigFile *objectfile = cfgmgr_get_file(vs->objectfile);
-    vs->objects = objectfile->data;
-    return vs;
-}
-
 int cfgmgr_reload_file(ConfigFile *f, ServerConfiguration *conf, int *reload) {
     struct stat s;
     if(stat(f->file.ptr, &s) != 0) {
@@ -152,41 +121,6 @@
         }
         
         sc_last_modified = s.st_mtime;
-    } else if(0) {
-        /* copy configuration */
-        printf("cfgmgr copy server.conf\n");
-        
-        /* TODO: copy */
-        /*
-        config = load_server_conf(
-            current_config,
-            "config/server.conf");
-        */
-        config = malloc(sizeof(ServerConfiguration));
-        config->ref = 1;
-        config->pool = pool_create();
-        config->user = sstrdup_pool(config->pool, current_config->user);
-        config->tmp = sstrdup_pool(config->pool, current_config->tmp);
-        
-        // copy configuration
-        config->host_vs = ucx_map_clone(
-                current_config->host_vs,
-                copy_vs,
-                config->pool);
-        
-        config->listeners = ucx_list_clone(
-                current_config->listeners,
-                (copy_func)copy_listener,
-                config);
-        
-        // TODO: we need to get the mime map from the configfile data
-        config->mimetypes = current_config->mimetypes;
-        
-        if(config == NULL) {
-            fprintf(stderr, "Cannot load server.conf\n");
-            return -1;
-        }
-
     } else {
         printf("no reconfig required!\n");
         config = current_config;
--- a/src/server/daemon/httprequest.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/httprequest.c	Tue Jun 25 15:45:13 2013 +0200
@@ -500,7 +500,6 @@
         }
         /* if there is a trailing '/', remove it */
         if(docroot.ptr[docroot.length - 1] == '/') {
-            //docroot.ptr[docroot.length - 1] = 0; // TODO: can I do this? No!!
             docroot.length--;
         }
 
--- a/src/server/daemon/log.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/log.c	Tue Jun 25 15:45:13 2013 +0200
@@ -41,6 +41,7 @@
 #include "../util/strbuf.h"
 #include "../util/io.h"
 #include "../ucx/map.h"
+#include "../util/atomic.h"
 
 static int is_initialized = 0;
 
@@ -53,10 +54,9 @@
 static sbuf_t *ui_buffer = NULL;
 
 /*
- * access logfile map
+ * access log file map
  */
-static UcxMap    *access_log_files; // map of AccessLog*
-static AccessLog *default_access_log;
+static UcxMap *access_log_files; // map of LogFile*
 
 
 static char *log_date_month[] = {
@@ -248,7 +248,7 @@
  * This source file only manages access log files. IO is performed directly
  * by AddLog safs. 
  */
-AccessLog* get_access_log(sstr_t file, sstr_t format) {
+LogFile* get_access_log_file(sstr_t file) {
     if(!access_log_files) {
         access_log_files = ucx_map_new(4);
     }
@@ -257,41 +257,27 @@
         return NULL;
     }
     
-    AccessLog *log = ucx_map_sstr_get(access_log_files, file);
+    LogFile *log = ucx_map_sstr_get(access_log_files, file);
     if(log != NULL) {
-        // TODO: ref
+        ws_atomic_inc32(&log->ref);
         return log;
     }
     
     // the log file is not opened
     // check first if we can open it
-    sstr_t path = sstrdup(file);
-    FILE *out = fopen(path.ptr, "a");
+    FILE *out = fopen(file.ptr, "a");
     if(out == NULL) {
-        free(path.ptr);
         return NULL;
     }
     
-    // create access log object
-    log = calloc(1, sizeof(AccessLog));
-    log->file = path;
-    if(format.ptr != NULL) {
-        log->format = sstrdup(format);
-    }
-    log->log = out;
-    // TODO: log->ref = 1;
+    // create LogFile object
+    log = calloc(1, sizeof(LogFile));
+    log->file = out;
+    log->ref = 1;
     
     // add access log to the map
     ucx_map_sstr_put(access_log_files, file, log);
     
-    if(!default_access_log) {
-        default_access_log = log;
-    }
-    
     return log;
 }
 
-AccessLog* get_default_access_log() {
-    // TODO: ref
-    return default_access_log;
-}
--- a/src/server/daemon/log.h	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/log.h	Tue Jun 25 15:45:13 2013 +0200
@@ -46,10 +46,14 @@
 } LogConfig;
 
 typedef struct {
+    FILE     *file;
+    uint32_t ref;
+} LogFile;
+
+typedef struct {
     sstr_t   file;
     sstr_t   format; // unused
-    FILE     *log;
-    uint32_t ref;
+    LogFile  *log;
 } AccessLog;
 
 // server logging
@@ -64,10 +68,7 @@
 int log_ereport(int degree, const char *format, ...);
 
 // access logging
-AccessLog* get_access_log(sstr_t file, sstr_t format);
-AccessLog* get_default_access_log();
-
-// TODO: ref/unref
+LogFile* get_access_log_file(sstr_t file);
 
 #ifdef	__cplusplus
 }
--- a/src/server/daemon/protocol.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/protocol.c	Tue Jun 25 15:45:13 2013 +0200
@@ -261,13 +261,22 @@
             char *name  = p->param->name;
             char *value = p->param->value;
 
-            /* make first char of name uppercase */
-            // TODO: don't modify the headers
+            // make first char of name uppercase
+            size_t name_len = strlen(name);
             if(name[0] > 90) {
-                name[0] -= 32;
+                /*
+                 * make first char uppercase and write the remaining chars
+                 * unmodified to the buffer
+                 */
+                sbuf_put(out, name[0]-32);
+                if(name_len > 1) {
+                    sbuf_write(out, name+1, name_len-1);
+                }
+            } else {
+                // first char is already uppercase so just write the name
+                sbuf_write(out, name, name_len);
             }
 
-            sbuf_write(out, name, strlen(name));
             sbuf_write(out, ": ", 2);
             sbuf_write(out, value, strlen(value));
             sbuf_write(out, "\r\n", 2);
--- a/src/server/daemon/threadpools.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/daemon/threadpools.c	Tue Jun 25 15:45:13 2013 +0200
@@ -41,16 +41,20 @@
 
 threadpool_t *last_thrpool_c = NULL;
 
-int create_threadpool(sstr_t name, ThreadPoolConfig *cfg) {
-    // TODO: use ThreadPoolConfig
-    
+int create_threadpool(sstr_t name, ThreadPoolConfig *cfg) { 
     if(thread_pool_map == NULL) {
         thread_pool_map = ucx_map_new(16);
     }
     
     threadpool_t *pool = ucx_map_sstr_get(thread_pool_map, name);
     if(pool) {
-        /* TODO: reconfig thread pool */
+        if(pool->min_threads > cfg->max_threads) {
+            pool->min_threads = cfg->min_threads;
+            pool->max_threads = cfg->max_threads;
+        } else {
+            pool->max_threads = cfg->max_threads;
+            pool->min_threads = cfg->min_threads;
+        }
         return 0;
     } else {
         threadpool_t *tp = threadpool_new(cfg->min_threads, cfg->max_threads);
--- a/src/server/safs/addlog.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/addlog.c	Tue Jun 25 15:45:13 2013 +0200
@@ -72,7 +72,7 @@
     tmstr = sstrdup_pool(sn->pool, tmstr);
     
     fprintf(
-            log->log,
+            log->log->file,
             "%s - %s [%s] \"%s\" %d %s\n",
             ip,
             user,
@@ -80,7 +80,7 @@
             req,
             rq->status_num,
             len);
-    fflush(log->log);
+    fflush(log->log->file);
     
     
     return REQ_PROCEED;
--- a/src/server/safs/auth.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/auth.c	Tue Jun 25 15:45:13 2013 +0200
@@ -175,9 +175,7 @@
     grpfn = pblock_findval("groupfn", param);
 
     if((!type) || (!pwfile) || (!pwfn) || (grpfile && !grpfn)) {
-        // TODO: log error
-        //log_error(LOG_MISCONFIG, "basic-auth", sn, rq,
-        //          XP_GetAdminStr(DBT_authError1));
+        log_ereport(LOG_MISCONFIG, "basic-auth: missing parameter");
         protocol_status(sn, rq, PROTOCOL_SERVER_ERROR, NULL);
         return REQ_ABORTED;
     }
@@ -233,8 +231,7 @@
 
     if(!db) {
         // TODO: log error
-        //log_error(LOG_MISCONFIG, "basic-auth", sn, rq,
-        //          XP_GetAdminStr(DBT_authError1));
+        log_ereport(LOG_MISCONFIG, "basic-auth: missing db parameter");
         protocol_status(sn, rq, PROTOCOL_SERVER_ERROR, NULL);
         return REQ_ABORTED;
     }
--- a/src/server/safs/init.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/init.c	Tue Jun 25 15:45:13 2013 +0200
@@ -43,8 +43,7 @@
     char *funcs = pblock_findval("funcs", pb);
 
     if(shlib == NULL || funcs == NULL) {
-        fprintf(stderr, "load-modules: missing parameter\n");
-        //log_ereport(LOG_MISCONFIG, "load-modules: missing parameters");
+        log_ereport(LOG_MISCONFIG, "load-modules: missing parameters");
         if(!shlib && funcs) {
             log_ereport(
                     LOG_MISCONFIG,
@@ -60,7 +59,7 @@
         }
     }
 
-    /* load lib */
+    // load lib
     void *lib = dlopen(shlib, RTLD_GLOBAL | RTLD_NOW);
     if(lib == NULL) {
         char *dlerr = dlerror();
@@ -71,7 +70,7 @@
         return REQ_ABORTED;
     }
 
-    /* load function symbols */
+    // load function symbols
     int b = 0;
     for(int i=0;;i++) {
         if(funcs[i] == ','  || funcs[i] == 0) {
@@ -81,7 +80,7 @@
 
             funcs[i] = 0;
 
-            /* we have a function name */
+            // we have a function name
             void *sym = dlsym(lib, funcs);
             if(sym == NULL) {
                 fprintf(stderr, "Cannot load symbol %s\n", funcs);
--- a/src/server/safs/nametrans.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/nametrans.c	Tue Jun 25 15:45:13 2013 +0200
@@ -28,6 +28,7 @@
 
 #include "nametrans.h"
 
+#include "../daemon/log.h"
 #include "../util/pblock.h"
 
 int test_nametrans(pblock *pb, Session *sn, Request *rq) {
@@ -57,7 +58,7 @@
     char *from = pblock_findkeyval(pb_key_from, pb);
 
     if(!name) {
-        /* TODO: add log */
+        log_ereport(LOG_MISCONFIG, "assign-name: missing name parameter");
         protocol_status(sn, rq, 500, NULL);
         return REQ_ABORTED;
     }
@@ -74,7 +75,7 @@
         }
     }
 
-    /* add object to rq->vars */
+    // add object to rq->vars
     pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars);
 
     return REQ_NOACTION;
--- a/src/server/safs/objecttype.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/objecttype.c	Tue Jun 25 15:45:13 2013 +0200
@@ -36,12 +36,11 @@
 
 int object_type_by_extension(pblock *pb, Session *sn, Request *rq) {
     sstr_t ppath = sstr(pblock_findkeyval(pb_key_ppath, rq->vars));
-
     //printf("\nobject_type_by_extension: {%s}[%d]\n\n", ppath);
 
     sstr_t ct;
     if(ppath.ptr[ppath.length - 1] == '/') {
-        /* directory */
+        // directory
         ct = sstrn("internal/directory", 18);
     } else {
         sstr_t ext;
@@ -54,11 +53,11 @@
         }
 
         if(ext.length == 0) {
-            /* no extension, no type */
+            // no extension, no type
             return REQ_NOACTION;
         }
 
-        /* get the mime type for the ext from the server configuration */
+        // get the mime type for the ext from the server configuration
         ServerConfiguration *config = session_get_config(sn);
         char *type = ucx_map_sstr_get(config->mimetypes->map, ext);
         
--- a/src/server/safs/pathcheck.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/pathcheck.c	Tue Jun 25 15:45:13 2013 +0200
@@ -57,8 +57,8 @@
 int require_access(pblock *pb, Session *sn, Request *rq) {
     char *mask_str = pblock_findval("mask", rq->vars);
     if(!mask_str) {
-        // misconfig
-        // TODO: log
+        log_ereport(LOG_MISCONFIG, "require-access: missing mask parameter");
+        protocol_status(sn, rq, 500, NULL);
         return REQ_ABORTED;
     }
     
@@ -80,8 +80,10 @@
     if(aclname) {
         ACLList *acl = acl_get(vs->acls, aclname);
         if(!acl) {
-            // TODO: error
-            fprintf(stderr, "acl %s not found\n", aclname);
+            log_ereport(
+                    LOG_MISCONFIG,
+                    "append-acl: acl %s not found", aclname);
+            protocol_status(sn, rq, 500, NULL);
             return REQ_ABORTED;
         }
         
--- a/src/server/safs/service.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/safs/service.c	Tue Jun 25 15:45:13 2013 +0200
@@ -52,7 +52,7 @@
 SYS_FILE prepare_service_file(Session *sn, Request *rq, struct stat *s) {
     char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
 
-    /* open the file */
+    // open the file
     VFSContext *vfs = vfs_request_context(sn, rq);
     SYS_FILE fd = vfs_open(vfs, ppath, O_RDONLY);
     if(!fd) {
@@ -60,7 +60,7 @@
         return NULL;
     }
 
-    /* get stat */
+    // get stat
     if(vfs_fstat(vfs, fd, s) != 0) {
         //perror("prepare_service_file: stat");
         protocol_status(sn, rq, 500, NULL);
@@ -84,13 +84,13 @@
         return fd;
     }
 
-    /* add content-length header*/
+    // add content-length header
     char contentLength[32];
     int len = snprintf(contentLength, 32, "%lld", s->st_size);
 
     pblock_kvinsert(pb_key_content_length, contentLength, len, rq->srvhdrs);
 
-    /* start response */
+    // start response
     protocol_status(sn, rq, 200, NULL);
     http_start_response(sn, rq);
 
@@ -140,23 +140,23 @@
 
     sstr_t r_uri = sstr(uri);
 
-    /* open the file */
+    // open the file
     VFSContext *vfs = vfs_request_context(sn, rq);
     VFS_DIR dir = vfs_opendir(vfs, ppath);
     if(!dir) {
         return REQ_ABORTED;
     }
 
-    sbuf_t *out = sbuf_new(1024); /* output buffer */
+    sbuf_t *out = sbuf_new(1024); // output buffer
 
-    /* write html header  */
+    // write html header
     sbuf_puts(out, "<html>\n<head>\n<title>Index of ");
     sbuf_puts(out, uri);
     sbuf_puts(out, "</title>\n</head><body>\n<h1>Index of ");
     sbuf_puts(out, uri);
     sbuf_puts(out, "</h1><hr>\n\n");
 
-    //struct dirent *f;
+    // list directory
     VFS_ENTRY f;
     while(vfs_readdir(dir, &f)) {
         sstr_t filename = sstr(f.name);
@@ -171,7 +171,7 @@
 
     sbuf_puts(out, "\n</body>\n</html>\n");
 
-    /* send stuff to client */
+    // send stuff to client
     pblock_removekey(pb_key_content_type, rq->srvhdrs);
     pblock_kvinsert(pb_key_content_type, "text/html", 9, rq->srvhdrs);
     pblock_nninsert("content-length", out->length, rq->srvhdrs);
@@ -180,7 +180,7 @@
 
     net_write(sn->csd, out->ptr, out->length);
 
-    /* close */
+    // close
     vfs_closedir(dir);
     sbuf_free(out);
 
--- a/src/server/util/pblock.cpp	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/util/pblock.cpp	Tue Jun 25 15:45:13 2013 +0200
@@ -1145,8 +1145,6 @@
         if (ppval[i]) ++nval;
     }
     
-    // TODO: implement util_env_create and util_env_str
-    /*
     env = util_env_create(env, nval, &pos);
 
     for (i = 0; i < pl->pl_initpi; ++i) {
@@ -1156,7 +1154,6 @@
         }
     }
     env[pos] = NULL;
-    */
 
     return env;
 }
--- a/src/server/util/util.c	Mon Jun 24 14:41:32 2013 +0200
+++ b/src/server/util/util.c	Tue Jun 25 15:45:13 2013 +0200
@@ -108,17 +108,152 @@
     return nbytesdecoded;
 }
 
-/*
-NSAPI_PUBLIC int util_getboolean(const char *v, int def) {
-    if(v[0] == 'T' || v[0] == 't') {
-        return 1;
+
+/* --------------------------- util_env_create ---------------------------- */
+
+
+NSAPI_PUBLIC char **util_env_create(char **env, int n, int *pos)
+{
+    int x;
+
+    if(!env) {
+        *pos = 0;
+        return (char **) MALLOC((n + 1)*sizeof(char *));
+    }
+    else {
+        for(x = 0; (env[x]); x++);
+        env = (char **) REALLOC(env, (n + x + 1)*(sizeof(char *)));
+        *pos = x;
+        return env;
+    }
+}
+
+
+/* ---------------------------- util_env_free ----------------------------- */
+
+
+NSAPI_PUBLIC void util_env_free(char **env)
+{
+    register char **ep = env;
+
+    for(ep = env; *ep; ep++)
+        FREE(*ep);
+    FREE(env);
+}
+
+/* ----------------------------- util_env_str ----------------------------- */
+
+
+NSAPI_PUBLIC char *util_env_str(const char *name, const char *value) {
+    char *t;
+
+    t = (char *) MALLOC(strlen(name)+strlen(value)+2); /* 2: '=' and '\0' */
+
+    sprintf(t, "%s=%s", name, value);
+
+    return t;
+}
+
+
+/* --------------------------- util_env_replace --------------------------- */
+
+
+NSAPI_PUBLIC void util_env_replace(char **env, const char *name, const char *value)
+{
+    int x, y, z;
+    char *i;
+
+    for(x = 0; env[x]; x++) {
+        i = strchr(env[x], '=');
+        *i = '\0';
+        if(!strcmp(env[x], name)) {
+            y = strlen(env[x]);
+            z = strlen(value);
+
+            env[x] = (char *) REALLOC(env[x], y + z + 2);
+            util_sprintf(&env[x][y], "=%s", value);
+            return;
+        }
+        *i = '=';
     }
-    if(v[0] == 'F' || v[0] == 'f') {
-        return 0;
+}
+
+
+/* ---------------------------- util_env_find ----------------------------- */
+
+
+NSAPI_PUBLIC char *util_env_find(char **env, const char *name)
+{
+    char *i;
+    int x, r;
+
+    for(x = 0; env[x]; x++) {
+        i = strchr(env[x], '=');
+        *i = '\0';
+        r = !strcmp(env[x], name);
+        *i = '=';
+        if(r)
+            return i + 1;
     }
-    return def;
+    return NULL;
+}
+
+
+/* ---------------------------- util_env_copy ----------------------------- */
+
+
+NSAPI_PUBLIC char **util_env_copy(char **src, char **dst)
+{
+    char **src_ptr;
+    int src_cnt;
+    int index;
+
+    if (!src)
+        return NULL;
+
+    for (src_cnt = 0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++);
+
+    if (!src_cnt)
+        return NULL;
+
+    dst = util_env_create(dst, src_cnt, &index);
+
+    for (src_ptr = src; *src_ptr; index++, src_ptr++)
+        dst[index] = STRDUP(*src_ptr);
+    dst[index] = NULL;
+    
+    return dst;
 }
-*/
+
+/* ----------------------------- util_sprintf ----------------------------- */
+
+NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register const char *fmt, 
+                                va_list args)
+{
+    return vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_snprintf(char *s, int n, const char *fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    return vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_vsprintf(char *s, register const char *fmt, va_list args)
+{
+    return vsprintf(s, fmt, args);
+}
+
+NSAPI_PUBLIC int util_sprintf(char *s, const char *fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    return vsprintf(s, fmt, args);
+}
+
+// TODO: asprintf
+
 
 NSAPI_PUBLIC int INTutil_getboolean(const char *v, int def) {
     if(v[0] == 'T' || v[0] == 't') {

mercurial