Mon, 16 Jan 2017 14:41:20 +0100
fixes cgi cleanup
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * * THE BSD LICENSE * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * util.c: A hodge podge of utility functions and standard functions which * are unavailable on certain systems * * Rob McCool */ #ifdef XP_UNIX #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <unistd.h> #include <limits.h> #include "prthread.h" #endif /* XP_UNIX */ //include "nspr.h" #include <errno.h> #include "../daemon/netsite.h" #include "../public/nsapi.h" #include <ucx/string.h> #include <ucx/mempool.h> #include "pblock.h" #include "util.h" #include <openssl/bio.h> #include <openssl/buffer.h> #include <openssl/evp.h> /* ------------------------------ _uudecode ------------------------------- */ static const unsigned char pr2six[256] = { 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63, 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27, 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64 }; /** you MUST reserve at least 2 additional bytes for bufout */ size_t util_base64decode(char *bufcoded, size_t codedbytes, char *bufout) { register char *bufin = bufcoded; register int nprbytes; size_t nbytesdecoded; /* Find the length */ nprbytes = (int) codedbytes; while(pr2six[(int)(bufin[nprbytes-1])] >= 64) { nprbytes--; } nbytesdecoded = ((nprbytes+3)/4) * 3; while (nprbytes > 0) { *(bufout++) = (unsigned char) (pr2six[(int)(*bufin)] << 2 | pr2six[(int)bufin[1]] >> 4); *(bufout++) = (unsigned char) (pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2); *(bufout++) = (unsigned char) (pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]); bufin += 4; nprbytes -= 4; } if(nprbytes & 03) { if(pr2six[(int)bufin[-2]] > 63) nbytesdecoded -= 2; else nbytesdecoded -= 1; } return nbytesdecoded; } char* util_base64encode(char *in, size_t len) { BIO *b; BIO *e; BUF_MEM *mem; e = BIO_new(BIO_f_base64()); b = BIO_new(BIO_s_mem()); BIO_set_flags(e, BIO_FLAGS_BASE64_NO_NL); e = BIO_push(e, b); BIO_write(e, in, len); BIO_flush(e); BIO_get_mem_ptr(e, &mem); char *out = malloc(mem->length + 1); memcpy(out, mem->data, mem->length); out[mem->length] = '\0'; BIO_free_all(e); return out; } /* --------------------------- 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; size_t len = strlen(name) + strlen(value) + 2; t = (char *) MALLOC(len); /* 2: '=' and '\0' */ snprintf(t, len, "%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 = '='; } } /* ---------------------------- util_sh_escape ---------------------------- */ NSAPI_PUBLIC char *util_sh_escape(char *s) { char *ns = (char *) MALLOC(strlen(s) * 2 + 1); /* worst case */ register char *t, *u; for(t = s, u = ns; *t; ++t, ++u) { if(strchr("&;`'\"|*?~<>^()[]{}$\\ #!", *t)) *u++ = '\\'; *u = *t; } *u = '\0'; return ns; } /* ---------------------------- 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 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 /* -------------------------- util_uri_unescape --------------------------- */ NSAPI_PUBLIC void util_uri_unescape(char *s) { char *t, *u; for(t = s, u = s; *t; ++t, ++u) { if((*t == '%') && t[1] && t[2]) { *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) + (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0')); t += 2; } else if(u != t) *u = *t; } *u = *t; } /* * Same as util_uri_unescape, but returns success/failure */ NSAPI_PUBLIC int util_uri_unescape_strict(char *s) { char *t, *u, t1, t2; int rv = 1; for(t = s, u = s; *t; ++t, ++u) { if (*t == '%') { t1 = t[1] & 0xdf; /* [a-f] -> [A-F] */ if ((t1 < 'A' || t1 > 'F') && (t[1] < '0' || t[1] > '9')) rv = 0; t2 = t[2] & 0xdf; /* [a-f] -> [A-F] */ if ((t2 < 'A' || t2 > 'F') && (t[2] < '0' || t[2] > '9')) rv = 0; *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) + (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0')); t += 2; } else if (u != t) *u = *t; } *u = *t; return rv; } NSAPI_PUBLIC int util_uri_unescape_plus (const char *src, char *trg, int len) { const char *t = src; char *u = trg == NULL ? (char *)src : trg; int rlen = 0; if (len == -1) len = strlen (src); for( ; len && *t; ++t, ++u, len--, rlen++) { if((*t == '%') && t[1] && t[2]) { *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A') + 10 : (t[1] - '0')) * 16) + (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A') + 10 : (t[2] - '0')); t += 2; len-= 2; } else if (*t == '+') *u = ' '; else *u = *t; } *u = 0; return rlen; } NSAPI_PUBLIC int INTutil_getboolean(const char *v, int def) { if(v[0] == 'T' || v[0] == 't') { return 1; } if(v[0] == 'F' || v[0] == 'f') { return 0; } return def; } int util_getboolean_s(sstr_t s, int def) { if(s.length == 0) { return def; } if(s.ptr[0] == 'T' || s.ptr[0] == 't') { return 1; } if(s.ptr[0] == 'F' || s.ptr[0] == 'f') { return 0; } return def; } NSAPI_PUBLIC int util_strtoint(char *str, int64_t *value) { char *end; errno = 0; int64_t val = strtoll(str, &end, 0); if(errno == 0) { *value = val; return 1; } else { return 0; } } /* ------------------------------ util_itoa ------------------------------- */ /* NSAPI_PUBLIC int util_itoa(int i, char *a) { int len = util_i64toa(i, a); PR_ASSERT(len < UTIL_ITOA_SIZE); return len; } */ NSAPI_PUBLIC int INTutil_itoa(int i, char *a) { return INTutil_i64toa(i, a); } /* ----------------------------- util_i64toa ------------------------------ */ /* * Assumption: Reversing the digits will be faster in the general case * than doing a log10 or some nasty trick to find the # of digits. */ NSAPI_PUBLIC int INTutil_i64toa(int64_t i, char *a) { register int x, y, p; register char c; int negative; negative = 0; if(i < 0) { *a++ = '-'; negative = 1; i = -i; } p = 0; while(i > 9) { a[p++] = (i%10) + '0'; i /= 10; } a[p++] = i + '0'; if(p > 1) { for(x = 0, y = p - 1; x < y; ++x, --y) { c = a[x]; a[x] = a[y]; a[y] = c; } } a[p] = '\0'; //PR_ASSERT(p + negative < UTIL_I64TOA_SIZE); return p + negative; } #ifndef XP_WIN32 NSAPI_PUBLIC struct passwd * util_getpwnam(const char *name, struct passwd *result, char *buffer, int buflen) { struct passwd *rv; errno = getpwnam_r(name, result, buffer, buflen, &rv); if (errno != 0) rv = NULL; return rv; } #endif #ifndef XP_WIN32 NSAPI_PUBLIC struct passwd * util_getpwuid(uid_t uid, struct passwd *result, char *buffer, int buflen) { struct passwd *rv; errno = getpwuid_r(uid, result, buffer, buflen, &rv); if (errno != 0) rv = NULL; return rv; } #endif NSAPI_PUBLIC int util_errno2status(int errno_value) { switch(errno_value) { case 0: { return 200; } case EACCES: { return 403; } case ENOENT: { return 404; break; } } return 500; } NSAPI_PUBLIC sstr_t util_path_append(pool_handle_t *pool, char *path, char *ch) { sstr_t parent = sstr(path); sstr_t child = sstr(ch); sstr_t newstr; UcxAllocator a = util_pool_allocator(pool); if(parent.ptr[parent.length-1] == '/') { newstr = sstrcat_a(&a, 2, parent, child); } else { newstr = sstrcat_a(&a, 3, parent, S("/"), child); } return newstr; } sstr_t util_path_remove_last(sstr_t path) { int i; for(i=path.length-1;i>=0;i--) { char c = path.ptr[i]; if(c == '/') { path.ptr[i] = 0; path.length = i; break; } } if(i < 0) { path.ptr = NULL; path.length = 0; } return path; } void util_add_ppath(sstr_t root, sstr_t path, pblock *vars) { // concat path size_t length = root.length + path.length; char *translated_path = alloca(length); memcpy(translated_path, root.ptr, root.length); memcpy(translated_path + root.length, path.ptr, path.length); // add path to specified pblock pblock_kvinsert( pb_key_ppath, translated_path, length, vars); } UcxAllocator util_pool_allocator(pool_handle_t *pool) { UcxAllocator a; a.malloc = (ucx_allocator_malloc)pool_malloc; a.calloc = (ucx_allocator_calloc)pool_calloc; a.realloc = (ucx_allocator_realloc)pool_realloc; a.free = (ucx_allocator_free)pool_free; a.pool = pool; return a; } // new - code from params.cpp NSAPI_PUBLIC pblock* util_parse_param(pool_handle_t *pool, char *query) { pblock *pb = pblock_create_pool(pool, 32); if(!pb) { return NULL; } if(!query || !(*query)) { return pb; } int loopFlag = 1; int nl = 0; // size of the name substring int vl = 0; // size of the value substring int state = 0; const char *np = query; const char *vp = NULL; while (loopFlag) { char delim = *query++; switch (delim) { case '&': case '\0': { if(!delim) { loopFlag = 0; } state = 0; if(nl > 0) { util_uri_unescape_plus(np, NULL, nl); util_uri_unescape_plus(vp, NULL, vl); pblock_nvlinsert(np, nl, vp, vl, pb); } nl = 0; vl = 0; vp = NULL; np = query; break; } case '=': { state = 1; vp = query; break; } default: { if(state) { vl++; } else { nl++; } } } /* switch */ } /* while */ return pb; } // TODO: remove sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s) { sstr_t newstring; newstring.ptr = (char*)ucx_mempool_malloc(pool, s.length + 1); if (newstring.ptr != NULL) { newstring.length = s.length; newstring.ptr[newstring.length] = 0; memcpy(newstring.ptr, s.ptr, s.length); } return newstring; } /* ---------------------------- util_mstr2num ----------------------------- */ static const int MSTR2NUM_HT_MASK = 0xf; struct mstr2num_ht { unsigned ucmstr; // Uppercase 3 character month string in a machine word int mnum; // 0-based month number for this month string }; struct mstr2num_ht MSTR2NUM_HT[] = { { 'A' << 16 | 'P' << 8 | 'R', 3 }, { 'S' << 16 | 'E' << 8 | 'P', 8 }, { 'M' << 16 | 'A' << 8 | 'Y', 4 }, { 0, -1 }, { 'M' << 16 | 'A' << 8 | 'R', 2 }, { 'F' << 16 | 'E' << 8 | 'B', 1 }, { 0, -1 }, { 'D' << 16 | 'E' << 8 | 'C', 11 }, { 'O' << 16 | 'C' << 8 | 'T', 9 }, { 'J' << 16 | 'U' << 8 | 'N', 5 }, { 0, -1 }, { 'A' << 16 | 'U' << 8 | 'G', 7 }, { 'J' << 16 | 'A' << 8 | 'N', 0 }, { 'J' << 16 | 'U' << 8 | 'L', 6 }, { 0, -1 }, { 'N' << 16 | 'O' << 8 | 'V', 10 } }; static inline int _mstr2num(const char *s) { const unsigned char *mstr = (const unsigned char *) s; /* * We compute ucmstr (an uppercase 3 character month string stored in a * machine word) and hash (a perfect hash based on the last 2 characters * of the 3 character uppercase month string) from the input string s. * Note that each character from the input string is masked by 0xdf; in * ASCII, this has the effect of converting alphabetic characters to * uppercase while 1. not changing any nonalphabetic characters into * alphabetic characters and 2. leaving any nul characters unchanged. * * The hash value is used as an index into the MSTR2NUM_HT[] hash table. * If the ucmstr at that index matches our computed ucmstr, the mnum at * that index is the 0-based month number corresponding to the input * string. * * Note that we never read past the end of the input string and always * return -1 if the input string doesn't begin with a valid 3 character * month string. */ unsigned char ucmstr0 = mstr[0] & 0xdf; unsigned ucmstr = ucmstr0 << 16; if (ucmstr0 != '\0') { unsigned char ucmstr1 = mstr[1] & 0xdf; ucmstr |= ucmstr1 << 8; if (ucmstr1 != '\0') { unsigned char ucmstr2 = mstr[2] & 0xdf; ucmstr |= ucmstr2; unsigned hash = (ucmstr1 >> 2) ^ (ucmstr2 << 1); int i = hash & MSTR2NUM_HT_MASK; if (MSTR2NUM_HT[i].ucmstr == ucmstr) return MSTR2NUM_HT[i].mnum; } } return -1; } NSAPI_PUBLIC int util_mstr2num(const char *s) { return _mstr2num(s); } /* ------------------------- util_str_time_equal -------------------------- */ /* * Function to compare if two time strings are equal * * Acceptable date formats: * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format * * Return 0 if equal, -1 if not equal. */ static inline const char * _parse_day_month(const char *p, int *day, int *month) { *day = 0; if (*p == ',') { // Parse day and month: ", 06 Nov", ", 06-Nov" p++; if (*p == ' ') p++; while (*p >= '0' && *p <= '9') *day = *day * 10 + (*p++ - '0'); if (*p == ' ' || *p == '-') p++; *month = _mstr2num(p); if (*month != -1) p += 3; } else { // Parse month and day: " Nov 6" if (*p == ' ') p++; *month = _mstr2num(p); if (*month != -1) p += 3; while (*p == ' ') p++; while (*p >= '0' && *p <= '9') *day = *day * 10 + (*p++ - '0'); } return p; } static inline void _parse_year_time(const char *p, int *year, const char ** time) { int _year = 0; if (*p == '-') { // Parse year and time: "-94 08:49:37" p++; while (*p >= '0' && *p <= '9') _year = _year * 10 + (*p++ - '0'); if (_year < 70) { _year += 2000; } else { _year += 1900; } if (*p == ' ') p++; *time = p; } else { // Parse year and time or time and year if (*p == ' ') p++; if (p[0] && p[1] && p[2] == ':') { // Parse time and year: "08:49:37 1994" *time = p; p += 3; while (*p && *p != ' ') p++; if (*p == ' ') p++; while (*p >= '0' && *p <= '9') _year = _year * 10 + (*p++ - '0'); } else { // Parse year and time: "1994 08:49:37" while (*p >= '0' && *p <= '9') _year = _year * 10 + (*p++ - '0'); if (*p == ' ') p++; *time = p; } } *year = _year; } NSAPI_PUBLIC int util_str_time_equal(const char *t1, const char *t2) { // Skip leading whitespace and day of week while (isspace(*t1)) t1++; while (isalpha(*t1)) t1++; while (isspace(*t2)) t2++; while (isalpha(*t2)) t2++; // Day and month: ", 06 Nov", ", 06-Nov", or " Nov 6" int day1; int month1; t1 = _parse_day_month(t1, &day1, &month1); int day2; int month2; t2 = _parse_day_month(t2, &day2, &month2); if (day1 != day2) return -1; if (month1 != month2) return -1; // Year and time: " 1994 08:49:37", "-94 08:49:37", or " 08:49:37 1994" int year1; const char *time1; _parse_year_time(t1, &year1, &time1); int year2; const char *time2; _parse_year_time(t2, &year2, &time2); if (year1 != year2) return -1; while (*time1 && *time1 != ' ' && *time1 == *time2) { time1++; time2++; } if (*time2 && *time2 != ' ') return -1; return 0; } /* --------------------------- util_later_than ---------------------------- */ static int _time_compare(const struct tm *lms, const char *ims) { while (isspace(*ims)) ims++; while (isalpha(*ims)) ims++; int day; int month; ims = _parse_day_month(ims, &day, &month); if (month == -1) return 1; int year; const char *time; _parse_year_time(ims, &year, &time); int rv; rv = (lms->tm_year + 1900) - year; if (rv) return rv; rv = lms->tm_mon - month; if (rv) return rv; rv = lms->tm_mday - day; if (rv) return rv; const char *p = time; int hour = 0; while (*p >= '0' && *p <= '9') hour = hour * 10 + (*p++ - '0'); if (*p == ':') p++; rv = lms->tm_hour - hour; if (rv) return rv; int minutes = 0; while (*p >= '0' && *p <= '9') minutes = minutes * 10 + (*p++ - '0'); if (*p == ':') p++; rv = lms->tm_min - minutes; if (rv) return rv; int seconds = 0; while (*p >= '0' && *p <= '9') seconds = seconds * 10 + (*p++ - '0'); if (*p == ':') p++; rv = lms->tm_sec - seconds; if (rv) return rv; return 0; } NSAPI_PUBLIC int util_later_than(const struct tm *lms, const char *ims) { /* * Returns 0 if lms later than ims * 0 if ims is malformed * 1 if ims later than lms * 1 if equal */ return _time_compare(lms, ims) <= 0; } NSAPI_PUBLIC int util_time_equal(const struct tm *lms, const char *ims) { return _time_compare(lms, ims) == 0; } NSAPI_PUBLIC struct tm * util_gmtime(const time_t *clock, struct tm *res) { return gmtime_r(clock, res); } int util_isdate(char *str) { sstr_t datestr = sstr(str); sstr_t example = S("Sun, 06 Nov 1994 08:49:37 GMT"); if(datestr.length != example.length) { return 0; } for(int i=0;i<datestr.length;i++) { char e = example.ptr[i]; if(isdigit(e)) { if(!isdigit(datestr.ptr[i])) { return 0; } } else if(e == ' ') { if(datestr.ptr[i] != ' ') { return 0; } } else if(e == ',') { if(datestr.ptr[i] != ',') { return 0; } } else if(e == ':') { if(datestr.ptr[i] != ':') { return 0; } } } if(!sstrsuffix(datestr, S("GMT"))) { return 0; } return 1; } /* ------------------------- util_mime_separator -------------------------- */ NSAPI_PUBLIC int util_mime_separator(char *sep) { int size = 35; // documented in nsapi.h int pos = 0; sep[pos++] = CR; sep[pos++] = LF; sep[pos++] = '-'; sep[pos++] = '-'; int r[6]; for(int i=0;i<6;i++) { r[i] = rand() % 10000; } pos += snprintf( sep+4, size-4, "X%04x%04x%04x%04x%04x%04xE", r[0], r[1], r[2], r[3], r[4], r[5]); return pos; }