cgi_util.c

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /* cgi_util.c © Copyright 1998-2005 by Raosoft Inc. All Rights Reserved.      */
00003 /*                                                                            */
00004 /* You may use and modify this file for your own use, but may not distribute  */
00005 /* it or derivative works without the prior written consent of Raosoft, Inc.  */
00006 /*                                                                            */
00007 /* If you choose to share your modifications with Raosoft, Inc. the company   */
00008 /* will attempt to incorporate them into future versions of this file.        */
00009 /*                                                                            */
00010 /* This software is provided "as is," and Raosoft makes no warranty, express  */
00011 /* or implied, of fitness for a particular application. Every measure has been*/
00012 /* taken to anticipate risks inherent to computer networks, but we cannot     */
00013 /* guarantee safety or reliability of this program in every situation.        */
00014 /*                                                                            */
00015 /******************************************************************************/
00016 
00017 /* The functions fmakeword(), x2c(), unescape_url(), swapchars(), rind()  */
00018 /* are either intuitively obvious or are in the public domain, so you may */
00019 /* use that source code in other programs                                 */
00020 
00021 #include "cgi.h"
00022 #include <stdarg.h>
00023 #include <math.h>
00024 /* Utility functions */
00025 
00026 #define EATCOLIN(x) while (*x && (strchr(":",*x) != NULL)) x++
00027 #define EATWHITE(x) while (*x && (strchr(" \t\r\n",*x) != NULL)) x++
00028 #define EATTEXT(x) while (*x && (strchr(" \t\r\n",*x) == NULL)) x++
00029 
00030 size_t int16ToUTF8(unsigned int in, char* out)
00031 {
00032   if (in < 0x80)
00033   {
00034       out[0]=(char)in;
00035       return 1;
00036   }
00037   else if (in < 0x800)
00038   {
00039       out[1] = (char)((in & 0x3f) | 0x80);
00040       out[0] = (char)((in >> 6)   | 0xc0);
00041       return 2;
00042   }
00043   else
00044   {
00045       out[2] = (char)((in & 0x3f) | 0x80);
00046       out[1] = (char)(((in >> 6) & 0x3f) | 0x80);
00047       out[0] = (char)((in >> 12)  | 0xe0);
00048       return 3;
00049   }
00050 }
00051 
00052 static char basis_64[] =
00053  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00054 
00058 int B64encode(char* in, char* out)
00059 {
00060   unsigned char c1=in[0], c2=0, c3=0;
00061   if (c1) c2 = in[1];
00062   if (c2) c3 = in[2];
00063   out[0] = basis_64[c1>>2];
00064   out[1] = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
00065 
00066   if (c2)
00067   {
00068    out[2] = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
00069    out[3] = basis_64[c3 & 0x3F];
00070    return c3;
00071   }
00072   else if (c2)
00073    out[2] = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
00074   else
00075    out[2] = '=';
00076 
00077   out[3] = '=';
00078   return 0;
00079 }
00080 int unB64(int c)
00081 {
00082     if (c >= 'A' && c <= 'Z') return c-'A';
00083     if (c >= 'a' && c <= 'z') return c-'a'+26;
00084     if (c >= '0' && c <= '9') return c-'0'+52;
00085     if (c == '=') return 62;
00086     if (c == '/') return 63;
00087     return -1;
00088 }
00089 
00090 
00105 int ContainsANSIChars(char* s)
00106 {
00107 /*
00108  ansi
00109  128 10000000
00110  159 10011111
00111  160 10100000
00112  utf-8
00113  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
00114  1110xxxx 10xxxxxx 10xxxxxx
00115  110xxxxx 10xxxxxx
00116  non-ansi characters: 127, 129, 141, 143, 144, 157,
00117  01111111 10000001 10001101 10001111 10010000 10011101
00118  are also all non-unicode values
00119 */
00120  unsigned c = *s++ & 0x00ff;
00121  unsigned d;
00122 
00123  while (c)
00124  {
00125   if (c & 0x80)
00126   {
00127    if ((c & 0x60) == 0) return 1; /*ANSI remap range -- no unicode characters*/
00128    d = *s; /*look at the next character */
00129    if ((d & 0xc0) != 0x80) return 1;
00130    /* require c & 0x60 == 0x40 || c & 0x70 == 0x60 || c & 0xf8 == 0xf0 */
00131    /*eos | not a utf-8 start sequnce | not a utf-8 sequence */
00132 
00133    /* a valid UTF-8 sequence is unlikely inside an ANSI sequence, but not impossible. */
00134    if ((c & 0x60) == 0x40) /* 110xxxxx 10xxxxxx */
00135    {
00136     s++;
00137     goto next;
00138    }
00139 
00140    d = s[1];
00141    if ((d & 0xc0) != 0x80) return 1;
00142 
00143    if ((c & 0xf0) == 0xe0) /* 1110xxxx 10xxxxxx 10xxxxxx */
00144    {
00145      s += 2;
00146      goto next;
00147    }
00148 
00149    d = s[2];
00150    if ((d & 0xc0) != 0x80) return 1;
00151 
00152    if ((c & 0xf8) == 0xf0) /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
00153    {
00154     s += 3;
00155     goto next;
00156    }
00157 
00158    return 1; /* isolated high-bit character */
00159   }
00160  next:
00161   c = *s++ & 0x00ff;
00162  }
00163 
00164  return 0;
00165 }
00166 
00167 /* ANSI Unicode HTML*/
00168 unsigned ANSIchars []=
00169 {
00170 8364,   /* &euro;   euro sign   Currency Symbols*/
00171 '?',
00172 8218,   /* &sbquo;  single low-9 quotation mark General Punctuation*/
00173 402,    /* &fnof;   Latin small letter f with hook  Latin Extended-B*/
00174 8222,   /* &bdquo;  double low-9 quotation mark General Punctuation*/
00175 8230,   /* &hellip; horizontal ellipsis General Punctuation*/
00176 8224,   /* &dagger; dagger  General Punctuation*/
00177 8225,   /* &Dagger; double dagger   General Punctuation*/
00178 710,    /* &circ;   modifier letter circumflex accent   Spacing Modifier Letters*/
00179 8240,   /* &permil; per mille sign  General Punctuation*/
00180 352,    /* &Scaron; Latin capital letter S with caron   Latin Extended-A*/
00181 8249,   /* &lsaquo; single left-pointing angle quotation mark   General Punctuation*/
00182 338,    /* &OElig;  Latin capital ligature OE   Latin Extended-A*/
00183 '?',
00184 381,            /* Latin capital letter Z with caron    Latin Extended-A*/
00185 '?',
00186 '?',
00187 8216,   /* &lsquo;  left single quotation mark  General Punctuation*/
00188 8217,   /* &rsquo;  right single quotation mark General Punctuation*/
00189 8220,   /* &ldquo;  left double quotation mark  General Punctuation*/
00190 8221,   /* &rdquo;  right double quotation mark General Punctuation*/
00191 8226,   /* &bull;   bullet  General Punctuation*/
00192 8211,   /* &ndash;  en dash General Punctuation*/
00193 8212,   /* &mdash;  em dash General Punctuation*/
00194 732,    /* &tilde;  small tilde Spacing Modifier Letters*/
00195 8482,   /* &trade;  trade mark sign Letterlike Symbols*/
00196 353,    /* &scaron; Latin small letter s with caron Latin Extended-A*/
00197 8250,   /* &rsaquo; single right-pointing angle quotation mark  General Punctuation*/
00198 339,    /* &oelig;  Latin small ligature oe Latin Extended-A*/
00199 '?',
00200 382,            /* Latin small letter z with caron  Latin Extended-A*/
00201 376,    /* &Yuml;   Latin capital letter Y with diaeresis   Latin Extended-A */
00202 };
00203 
00204 char* ANSItoUTF8(char* s)
00205 {
00206   char* r = malloc(strlen(s)*4+1); /* worst case */
00207   char* c = r;
00208   for (; *s; s++)
00209   {
00210    unsigned x = (*s) & 0x00ff;
00211    if ((x & 0x80) == 0)
00212    {
00213     *c++ = x;
00214     continue;
00215    }
00216 
00217    if ((x & 0x60) == 0) //between 128 and 159, remap from the table
00218     x = ANSIchars[x - 128];
00219 
00220    c += int16ToUTF8(x, c);
00221   }
00222   *c=0;
00223   return r;
00224 }
00225 
00226 /*
00227 void qpdecode(char*in)
00228 {
00229   char* out = in;
00230   char c;
00231   char hex[3];
00232   hex[2]=0;
00233 
00234   while (c=*in++)
00235   {
00236    if (c == '=')
00237     {
00238      hex[0] = *in++;
00239      if (!hex[0]) break;
00240 
00241      if (hex[0] == '\r')
00242        {
00243         hex[0] = *in++;
00244         if (!hex[0]) break;
00245        }
00246      else if (hex[0] == '\n') continue;
00247 
00248      hex[1] = *in++;
00249 
00250      if (!hex[1]) break;
00251      c = strtol(hex,0,16);
00252     }
00253    *out++ = (char)c;
00254   }
00255 }
00256 */
00257 void B64decode(char* write)
00258 {
00259   char* read = write;
00260   int x, step=0, i[2];
00261   while (*read && *read != '=')
00262     {
00263     x = unB64(*read);
00264     if (x == -1) break;
00265     i[step % 2]=x;
00266 
00267     if (step % 4)
00268      *write++ = (char)((i[(step+1)%2] << ((step%4) * 2)) | (i[step%2] >> (6 - ((step%4) * 2)))) & 0x00ff;
00269 
00270      read++;
00271     step = (step + 1) % 8;
00272    }
00273   *write = 0;
00274 }
00275 
00276 /* returns the number of characters processed and whether to continue. - terminates a scan.
00277    UTF-8 is always shorter. Direct conversion is possible. B64 maps 3 bytes to 4.
00278    +AAA-
00279 */
00280 void UTF7toUTF8(char* write)
00281 {
00282     char* read = write;
00283 
00284     while (*read)
00285     {
00286         if (*read == '+')
00287          {
00288           int x, step, out, i[2], ch[2];
00289              if (read[1] == '-')
00290              {
00291                  *write++ = *read++;
00292                  read++;
00293                  continue;
00294              }
00295              read++;
00296              step = 0;
00297              out = 0;
00298 
00299              while (*read && *read != '-')
00300              {
00301              x = unB64(*read);
00302              if (x == -1) break;
00303              i[step % 2]=x;
00304 
00305              if (step % 4)
00306                ch[out++%2] = ((i[(step+1)%2] << ((step%4) * 2)) | (i[step%2] >> (6 - ((step%4) * 2)))) & 0x00ff;
00307 
00308              if (step == 2 || step == 5 || step == 7)
00309                write += int16ToUTF8((ch[0] << 8) | ch[1],write);
00310                  read++;
00311              step = (step + 1) % 8;
00312              }
00313           if (*read == '-') read++; /* eat the - */
00314           else if (*read) *write++ = *read++;
00315          }
00316         else
00317        {
00318          *write++ = *read++;
00319        }
00320     }
00321     *write = 0;
00322 }
00323 
00324 char x2c(char *what) {
00325     register char digit;
00326 
00327     digit =
00328       (char)(what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
00329     digit *=
00330       (char)16;
00331     digit +=
00332       (char)(what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
00333     return(digit);
00334 }
00335 
00336 int ExpandUrl(char *url) {
00337     register int x,y;
00338 
00339     for(x=0,y=0;url[y];++x,++y) {
00340         if((url[x] = url[y]) == '%') {
00341             url[x] = x2c(&url[y+1]);
00342             y+=2;
00343         }
00344     }
00345     url[x] = '\0';
00346     return x; /* return the finished string length */
00347 }
00348 
00349 int IsNumber(char *c,size_t length)
00350 { /* -.3e5 */
00351 /* int i=0;
00352  if (c[0] == '+' || c[0]=='-') i++;
00353  if (c[i] == '.') i++;
00354  if (c[i] >= '0' && c[i] <= '9') return 1;*/
00355  char *x;
00356  size_t i;
00357  if (!c) return 0;
00358  if (!*c) return 0;
00359  strtod(c,&x);
00360  i = x - c;
00361  return ((length == 0 && *x == 0) || (length != 0 && length == i));
00362 }
00363 
00364 TextBuffer * NewBuffer(int length)
00365 {
00366  TextBuffer* t = CGIMALLOC(sizeof(TextBuffer));
00367  t->data = CGIMALLOC(length+1);
00368  t->data[length] = 0;
00369  t->size = length;
00370  t->used = 0;
00371  t->Next = NULL;
00372  t->Last = t;
00373  return t;
00374 }
00375 
00376 void DeleteBuffer(TextBuffer* t)
00377 {
00378  while (t)
00379   {
00380    TextBuffer* n = t->Next;
00381    CGIFREE(t->data);
00382    CGIFREE(t);
00383    t = n;
00384   }
00385 }
00386 
00387 size_t BufferWrite(TextBuffer* start,char* text)
00388 {
00389  if (text) return BufferWriteL(start,text,strlen(text));
00390  return 0;
00391 }
00392 
00393 size_t BufferWriteL(TextBuffer* start,char* text,size_t length)
00394 {
00395  size_t current, next;
00396  TextBuffer* t = (TextBuffer*)start->Last;
00397 
00398  if (length == 0) return 0;
00399 
00400  if (length >= (t->size - t->used))
00401    {
00402     current = (t->size - t->used);
00403     next = length - current;
00404    }
00405  else
00406    {
00407     current = length;
00408     next = 0;
00409    }
00410 
00411  memcpy(t->data + t->used,text,current);
00412  t->used += current;
00413 
00414  if (next)
00415  {
00416   size_t i = 1024u; /* allocate a new block for anything this big */
00417   TextBuffer* tn;
00418 
00419   if (i < next) i = next;
00420   start->Last = NewBuffer(i);
00421   t->Next = start->Last;
00422   tn = (TextBuffer*)t->Next;
00423   memcpy(tn->data, text + current, next);
00424   tn->used = next;
00425  }
00426 
00427  return length;
00428 }
00429 
00430 size_t BufferSize(TextBuffer* t)
00431 {
00432  size_t length = 0;
00433  while (t)
00434   {
00435    TextBuffer* n = t->Next;
00436    length += t->used;
00437    t = n;
00438   }
00439  return length;
00440 }
00441 
00442 char* CopyBuffer(TextBuffer* t)
00443 {
00444  size_t l = BufferSize(t);
00445  char * x = CGIMALLOC(l+4);
00446  BufferRead(t,x,l+4);
00447  memset(x+l,0,4);
00448  return x;
00449 }
00450 #define MIN(a,b) (a<b?a:b)
00451 
00452 size_t BufferRead(TextBuffer* start, char* out,size_t length)
00453 {
00454  size_t read=0;
00455 
00456  while( read < length)
00457   {
00458    size_t x = MIN((length - read), start->used);
00459    memcpy(out + read, start->data, x);
00460    read += x;
00461    if (!start->Next) break;
00462    start = (TextBuffer*)start->Next;
00463   }
00464  return read;
00465 }
00466 
00467 
00468 int ReadUntilWord2(FILE * in, char * out,size_t max,char*check1,char*check2)
00469 {
00470  size_t len = strlen(check1);
00471  size_t pos = 0;
00472  char* buf = 0;
00473  int quit = 0;
00474 
00475  if (len == 0) {return 0;}
00476 
00477  buf = CGIMALLOC(len+1);
00478  buf[len]=0;
00479 
00480  if (fread(buf,len,1,in) != 1) {CGIFREE(buf); return 0;}
00481 
00482  len --;
00483 
00484  while (stricmp(buf,check1) && (check1 == check2 ? 1 : stricmp(buf,check2)))
00485   {
00486    if (out)
00487     if (pos < max)
00488      {
00489       out[pos] = buf[0];
00490       pos ++;
00491       if (pos < max) out[pos]=0;
00492      }
00493 
00494     if(quit) {CGIFREE(buf); return 0;}
00495 
00496    memmove((char*)buf,(char*)buf+1,len);
00497 
00498    if (fread((char*)buf + len,1,1,in) != 1) {quit=1;}
00499   }
00500 
00501  if (!stricmp(buf,check1)) len = 1;
00502  else len = 2;
00503  CGIFREE(buf);
00504  return len;
00505 }
00506 
00507 int ReadUntilWord(FILE * in, char * out,size_t max,char*check)
00508 {
00509  return ReadUntilWord2(in,out,max,check,check);
00510 }
00511 
00512 int ReadUntilWordS2(FILE * in,STREAM out, char * check1, char* check2)
00513 {
00514  size_t len = strlen(check1);
00515  size_t l2;
00516  char* buf;
00517 
00518  if (len == 0) return 0;
00519  buf = CGIMALLOC(len+1);
00520  buf[len]=0;
00521  l2 = len - 1;
00522 
00523  if (fread(buf,len,1,in) != 1)
00524   {
00525       CGIFREE(buf); return 0;
00526 }
00527 
00528  while (stricmp(buf,check1) && (check1 == check2 ? 1 : stricmp(buf,check2)))
00529   {
00530    if (out)
00531    {
00532     char c[2];
00533     c[0]=buf[0];
00534     c[1]=0;
00535     HTMLWrite(out,c);
00536    }
00537    memmove((char*)buf,(char*)buf+1,len);
00538    if (fread((char*)buf + l2,1,1,in) != 1)  {CGIFREE(buf); return 0;}
00539   }
00540 
00541  if (!stricmp(buf,check1)) len = 1;
00542  else len = 2;
00543  CGIFREE(buf);
00544  return len;
00545 }
00546 
00547 int ReadUntilWordS(FILE * in,STREAM out, char * check)
00548 {
00549  return ReadUntilWordS2(in,out,check,check);
00550 }
00551 
00552 void HTMLSend(STREAM htmlout, TextBuffer* start)
00553 {
00554  if (!htmlout) return;
00555  while (start)
00556   {
00557    HTMLWriteL(htmlout,start->data,start->used);
00558    start = (TextBuffer*)start->Next;
00559   }
00560 }
00561 
00562 FILE* FileOpen(char* argv0, char* file,char* extension)
00563 {
00564  char filename[MAXPATH];
00565  if (!file) return 0;
00566  if (!*file) return 0;
00567  ExpandLocalPath(argv0,filename,file,extension);
00568  return CGIFOPEN(filename,"rb");
00569 }
00570 
00571 int ReadUntilChar(FILE * in, char * out, size_t max, char * stop, int skip)
00572 {
00573  char c;
00574  if (out) *out = 0;
00575  if (max) max--;
00576  if (feof(in)) return -1;
00577  while (fread(&c,1,1,in)>0)
00578  {
00579   if (skip && skip == c)
00580     continue;
00581 
00582   if (strchr(stop,c))
00583    {
00584     if (out && max) *out = 0;
00585     return c;
00586    }
00587   else
00588    {
00589     if (out && max)
00590      {
00591       *out = c;
00592       out++;
00593       *out = 0;
00594       max--;
00595      }
00596    }
00597  }
00598  return -1;
00599 }
00600 
00601 CGINameValue* ReadHTMLAttributes(FILE * source,size_t max)
00602 {
00603  CGINameValue * v = NewNVP(max > 0 ? max : 16);
00604  int i = 0; /* max 20 options per tag, 1k per option*/
00605  char temp[4096];
00606 
00607  while (i < 20)
00608   {
00609    int e = ReadUntilChar(source,temp,sizeof(temp)-1,"=> \t\r\n",0);
00610    char *s = temp;
00611    while (*s && strchr(" \t\r\n",*s)!=NULL) s++;
00612 
00613    if (*s)
00614    {
00615     v[i].name = strdup(s);
00616 
00617     if (e == '=')
00618     {
00619      fread(temp,1,1,source);
00620      if (temp[0] == '\"')
00621        e = ReadUntilChar(source,temp,sizeof(temp),"\"",0);
00622      else
00623        e = ReadUntilChar(source,temp+1,sizeof(temp)-1,"> \t\r\n",0);
00624 
00625      v[i].value = strdup(temp);
00626     }
00627     i++;
00628    }
00629    if (e == '>' || e == -1) return v;
00630   }
00631   ReadUntilChar(source,0,0,">",0); /* chomp all the remaining tags */
00632   return v;
00633 }
00634 
00635 #ifdef __WINCE__
00636 extern char serverRootA[MAXPATH];
00637 #endif
00638 
00639 void ExpandLocalPath(char * argv0, char * fn,char* finish,char* a)
00640 {
00641  char * c;
00642 #ifdef XP_WIN
00643  int i;
00644 #endif
00645 #ifdef __WINCE__ /* fully qualified path already? */
00646  if (finish[0] == '\\')
00647 #elif defined XP_WIN
00648  if ((finish[0] == '\\' && finish[1] == '\\') || (finish[0] != 0 && finish[1] == ':'))
00649 #else /* unix */
00650  if (finish[0] == '/')
00651 #endif
00652  {
00653      strcpy(fn,finish);
00654      if (a != NULL) strcat(fn,a);
00655      return;
00656  }
00657 
00658  strcpy(fn,argv0);
00659 #ifdef XP_WIN
00660  c = strrchr(fn,'\\');
00661 #else
00662  c = strrchr(fn,'/');
00663 #endif
00664  if (c)
00665  {
00666   c++;
00667  }
00668  else
00669  {
00670 #ifdef __WINCE__
00671    strcpy(fn,serverRootA);
00672 #else
00673    getcwd(fn, MAXPATH);
00674 #ifdef XP_WIN
00675    strcat(fn, "\\");
00676 #else
00677    strcat(fn, "/");
00678 #endif
00679 #endif
00680    c = fn + strlen(fn);
00681 
00682  }
00683  strcpy(c,finish);
00684  if (a != NULL) strcat(c,a);
00685 #ifdef XP_WIN
00686  for (i=0; c[i]; i++)
00687     if (c[i] == '/') c[i] = '\\';
00688 #endif
00689 }
00690 
00691 /*
00692 CGINameValue* LoadSettings(char* argv0, char* dbname, char* section)
00693 {
00694  char fn[MAXPATH];
00695  CGINameValue * n;
00696  ExpandLocalPath(argv0,fn,dbname,".ini");
00697  n = ReadINIFileSection(fn, section,0);
00698 
00699  if (n == NULL) return NULL;
00700  return n;
00701 }
00702 */
00703  /* Loads configuration information. dbname=cgi to get global settings.  */
00704 
00705 char * GetSetting(CGINameValue*section,char * key, char* def)
00706 {
00707  CGINameValue * n;
00708  n = GetField(section, key);
00709  if (n == NULL) return def;
00710  if (n->value == NULL) return def;
00711  if (n->value[0] == 0) return def;
00712  return n->value;
00713 }
00714  /* Returns the appropriate settings or the default value */
00715 
00716 #ifdef WINCGI
00717 char module[256];
00718 int SplitArgs (char *str, char *argv[],int max)
00719 {
00720     int argc;
00721     char *c;
00722 
00723    GetModuleFileName(0,module,256);
00724 
00725    argv[0]=module;
00726     argc = 1;
00727     c = str;
00728     while (*c && argc < max)
00729     {
00730         while(*c && isspace(*c)) c++;
00731         if (*c) argv[argc] = c;
00732         while(*c && !isspace(*c)) c++;
00733       if (*c) { *c = 0; c++; }
00734       argc++;
00735     }
00736    argv[argc]=0;
00737     return argc;
00738 }
00739 #endif
00740 
00741 void swapchars(char * str, char find, char repl)
00742 {
00743     int x;
00744     for(x=0;str[x];x++) if(str[x] == find) str[x] = repl;
00745 }
00746 
00747 #ifndef stricmp
00748 int stricmp(const char * a,const  char * b)
00749 {
00750  int i;
00751  while (*a && *b)
00752  {
00753   i = toupper(*a) - toupper(*b);
00754   if (i != 0) return i;
00755   a++;
00756   b++;
00757  }
00758  return *a - *b;
00759 }
00760 
00761 int strnicmp(const char * a,const  char * b, size_t length)
00762 {
00763  int i;
00764  while (*a && *b && length)
00765  {
00766   i = toupper(*a) - toupper(*b);
00767   if (i != 0) return i;
00768   ++a;
00769   ++b;
00770   --length;
00771  }
00772  return length ? toupper(*a) - toupper(*b) : 0;
00773 }
00774 #endif
00775 
00776 #ifndef strdup
00777 char *strdup(const char *s)
00778 {
00779  size_t length ;
00780  length = s ? strlen(s) : 0;
00781  return strndup((char*)s,length);
00782 }
00783 #endif
00784 
00785 char* strdup3(char* a,char* b,char*c)
00786 {
00787  size_t l = strlen(a) + strlen(b)+strlen(c);
00788  char* x = CGIMALLOC(l+1);
00789  x[0]=0;
00790  if (x) strcpy(x,a);
00791  if (b) strcat(x,b);
00792  if (c) strcat(x,c);
00793  return x;
00794 }
00795 
00796 char *strndup(char *s,size_t length)
00797 {
00798  char * c;
00799  c = CGIMALLOC(length+3);
00800  if (s && length) strncpy(c,s,length);
00801  c[length]=0;
00802  return c;
00803 }
00804 
00809 char * PopList2(char* list,int end)
00810 {
00811  char* r;
00812  size_t l,m;
00813  char* x = list;
00814  l=0;
00815 
00816  if (end)
00817   while (x[l] && x[l] != end) l++;
00818  else
00819   while (x[l] && x[l] != ',' && x[l] != ' ') l++;
00820 
00821  if (!x[l]) return NULL; /* not found */
00822  x = list + l + 1;
00823  m = strlen(x);
00824  r = CGIMALLOC(l+1);
00825 
00826  memcpy(r,list,l);
00827  r[l]=0;
00828 
00829  memmove(list,x,m);
00830  list[m]=0;
00831 
00832  x = list + m + 1; /* tail of the new list */
00833  memcpy(x,r,l);
00834  x[l]=0;
00835 
00836  CGIFREE(r);
00837  return x;
00838 }
00839 
00840 char * PopList(CGINameValue*list,char* key,int end)
00841 {
00842  char* x = GetFieldValue(list,key);
00843  char* p;
00844  size_t i = 0;
00845 
00846  /* remove leading delimiters */
00847  while (x[i] == ',' || x[i] == ' ') i++;
00848  if (i)
00849    memmove(x,x+i,strlen(x+i) + 1);
00850 
00851  p = PopList2(x,end);
00852 
00853  /* remove trailing delimiters */
00854  i = strlen(x);
00855  while (i && (x[i-1]  == ',' || x[i-1] == ' ')) i--;
00856  x[i]=0;
00857 
00858  if (p != NULL) return p;
00859  else
00860  {
00861   size_t l = strlen(x);
00862   memmove(x+1,x,strlen(x));
00863   x[l+1] = 0;
00864   x[0]=0;
00865   return x+1;
00866  }
00867 }
00868 
00869 int strmatch(char * c1,char * c2, size_t length,char* end,int cs)
00870 {
00871   if (length) do
00872   {
00873    if (cs)
00874    {
00875     if (*c1 != *c2) return 0;
00876    }
00877    else if (toupper(*c1) != toupper(*c2)) return 0;
00878 
00879   c1++;
00880   c2++;
00881   length--;
00882   /* if (end of token AND end of comparison) */
00883   if ((*c2==0) && (!length||*c1==0||strchr(end,*c1))) return 1;
00884   } while (length);
00885   return 0;
00886 }
00887 
00888 int HasTokenX(char * c, char * code,int*loc,int cs)
00889 {
00890  size_t length = strlen(c);
00891  size_t i = 0;
00892  if (loc) *loc = 1;
00893 
00894   while (i < length && (c[i]==',' || c[i]==' ')) {i++; }
00895 
00896   while (i < length)
00897   {
00898    if (c[i] == ','|| c[i]==' ') { i++; if (loc) (*loc)++;}
00899    else
00900    {
00901     if (strmatch(c+i,code,length,", ",cs)) return 1;
00902     while (i<length && c[i] != ',' && c[i] != ' ') {i++; }
00903    }
00904   }
00905   return 0;
00906 }
00907 
00908 int HasToken(char * c, char * code,int*loc)
00909 {return HasTokenX(c,code,loc,1);}
00910 
00911 int HasTokenI(char * c, char * code,int*loc)
00912 {return HasTokenX(c,code,loc,0);}
00913 
00914 void ClearToken(char * c,char * code)
00915 { /* removes an element from a , delimited list */
00916   size_t length=strlen(c);
00917   while (length)
00918   {
00919    if (*c == ',' || *c == ' ') { c++; length--; }
00920    else
00921    {
00922     if (strmatch(c,code,length,", ",1))
00923      {
00924       size_t cl = strlen(code);
00925       while (c[cl] == ',' || c[cl] == ' ') cl++;
00926        /* don't bother to check the length here.  */
00927       if (length >= cl)
00928        {
00929         length -= cl;
00930         memmove(c,c+cl,length);
00931         memset(c+length,0,cl); /* pad the end with nulls */
00932        }
00933       return;
00934      }
00935     while (length && *c != ',' && *c != ' ') {c++; length--;}
00936    }
00937   }
00938 } /* wasn't that clever? */
00939 
00940 /*
00941 #ifdef WINCGI
00942 extern STREAM htmlin;
00943 extern STERAM htmlout;
00944 #else
00945 #define htmlin stdin
00946 #define htmlout stdout
00947 #endif
00948 */
00949 
00952 STREAM NewStream(int size)
00953 {
00954 #if defined(FASTCGI)
00955  STREAM str = (STREAM)CGIMALLOC(sizeof(FCGISTREAM));
00956  str->strp=0;
00957 #else
00958  STREAM str = (STREAM)CGIMALLOC(sizeof(EZSSTREAM));
00959  str->f=0;
00960 #endif
00961 #ifdef __WINCE__
00962  str->s = 0;
00963 #endif
00964 #ifdef ISAPICGI
00965  str->ecb = 0;
00966  str->pos = 0;
00967 #endif
00968  str->t = NewBuffer(size);
00969  return str;
00970 }
00971 
00972 void DeleteStream(STREAM str)
00973 {
00974  if (!str) return;
00975  if (str->t) DeleteBuffer(str->t);
00976  CGIFREE(str);
00977 }
00978 
00980 char * CopyStream(STREAM str)
00981 {
00982  return CopyBuffer(str->t);
00983 }
00984 
00985 /* output routines */
00986 
00987 void HTMLPrintf(STREAM htmlout,char * formatting, ...)
00988 {
00989  if (htmlout)
00990  {
00991   va_list argptr;
00992   va_start(argptr, formatting);
00993 #ifdef FASTCGI
00994   if (htmlout->strp)
00995   {
00996    FCGX_VFPrintF(htmlout->strp,formatting,argptr);
00997   }
00998   else
00999 #endif
01000  if (htmlout->f)
01001     vfprintf(htmlout->f,formatting, argptr);
01002  else
01003     {
01004      char temp[MAXBUF];
01005      vsprintf(temp,formatting,argptr);
01006      HTMLWrite(htmlout,temp);
01007     }
01008 
01009    va_end(argptr);
01010  }
01011 }
01012 
01013 size_t UTF8ToUCS2C(char* in,int *c)
01014 {
01015  if ((in[0] & 0x80) == 0) {*c=in[0]; return 1;} /* 1 character OK */
01016 
01017  /* 110xxxxx 10xxxxxx      */
01018  if (((in[0] & 0xe0) == 0xc0) && ((in[1] & 0xc0) == 0x80))
01019   { *c = (int)( ((in[0] & 0x1f) << 6) | (in[1] & 0x3f)); return 2;}
01020 
01021  /* 1110xxxx 10xxxxxx 10xxxxxx  */
01022  if (((in[0] & 0xf0) == 0xe0) && ((in[1] & 0xc0) == 0x80) && ((in[2] & 0xc0 )== 0x80))
01023   { *c = (int)(((in[0] & 0x0f) << 12) | ((in[1] & 0x3f) << 6)| (in[2] & 0x3f)); return 3;}
01024 
01025  /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  */
01026  if (((in[0] & 0xf8) == 0xf0) && ((in[1] & 0xc0) == 0x80) && ((in[2] & 0xc0 )== 0x80)&& ((in[3] & 0xc0) == 0x80))
01027   { *c = (int)(((in[0] & 0x0f) << 18) | ((in[1] & 0x3f) << 12)| ((in[2] & 0x3f) <<6)| ((in[3] & 0x3f))); return 4;}
01028 
01029  return 0; /*error */
01030 }
01031 
01032 void HTMLEscape(STREAM htmlout, char* out)
01033 {
01034  size_t k;
01035  int c=0;
01036 
01037  if (!htmlout) return;
01038 
01039  while (out && out[0])
01040  {
01041   k = UTF8ToUCS2C(out,&c);
01042   if (k > 1)
01043   {
01044    char x[32];
01045    sprintf(x,"&#%d;",c);
01046    HTMLWriteL(htmlout,x,strlen(x));
01047    out += k;
01048    continue;
01049   }
01050 
01051   switch (out[0])
01052   {
01053    case '<': HTMLWriteL(htmlout,"&lt;",4); out++; break;
01054    case '>': HTMLWriteL(htmlout,"&gt;",4); out++; break;
01055    case '&': HTMLWriteL(htmlout,"&amp;",5); out++; break;
01056    case '\"': HTMLWriteL(htmlout,"&quot;",6); out++; break;
01057    default: HTMLWriteL(htmlout,out,1); out++;
01058   }
01059  }
01060 }
01061 
01062 /*#ifdef DEBUG
01063 void debug_HTMLWrite(STREAM htmlout, char* file, int line,char* data)
01064 {
01065  FILE * h;
01066  if (!htmlout) return;
01067  if (!data) return;
01068   HTMLWriteL(htmlout,data,strlen(data));
01069 
01070   h = CGIFOPEN("debug.txt","at");
01071   if (h)
01072   {
01073    fprintf(h,"%s[%d]: %s\n",file,line,data);
01074    CGIFCLOSE(h);
01075   }
01076 }
01077 #else*/
01078 
01079 void HTMLWrite(STREAM htmlout,char* data)
01080 {
01081  if (!data) return;
01082  if (!htmlout) return;
01083  HTMLWriteL(htmlout,data,strlen(data));
01084 }
01085 /*#endif*/
01086 
01087 #ifndef VPWSCGI
01088 void HTMLWriteL(STREAM htmlout,char* data,size_t length)
01089  {
01090   if (length==0||data==NULL||htmlout==NULL) return;
01091 
01092 #if defined(FASTCGI)
01093     if (htmlout->strp)
01094       FCGX_PutStr(data,length,htmlout->strp);
01095     else
01096 #endif
01097 #ifdef ISAPICGI
01098     if (htmlout->ecb !=NULL)
01099     {
01100      int c = length + htmlout->pos;
01101      if (c < MAXPATH)
01102      {
01103          memcpy(htmlout->buffer + htmlout->pos,data,length);
01104          htmlout->pos = c;
01105          return;
01106      }
01107 
01108      c = MAXPATH - htmlout->pos;
01109 
01110        if (c) memcpy(htmlout->buffer + htmlout->pos, data, c);
01111      htmlout->pos = MAXPATH;
01112        htmlout->ecb->WriteClient(htmlout->ecb->ConnID, (PVOID)htmlout->buffer,&htmlout->pos,0);
01113      htmlout->pos = length - c;
01114 
01115      /*cache or send? */
01116      if (htmlout->pos >= MAXPATH)
01117      {
01118          htmlout->ecb->WriteClient(htmlout->ecb->ConnID, (PVOID) (data + c), &htmlout->pos,0);
01119          htmlout->pos = 0;
01120          return;
01121      }
01122      memcpy(htmlout->buffer,data+c,htmlout->pos);
01123     }
01124     else
01125 #endif
01126     if (htmlout->f !=NULL)
01127       fwrite(data,1,length,htmlout->f);
01128     else if (htmlout->t !=NULL)
01129       BufferWriteL(htmlout->t,data,length);
01130  }
01131 #endif
01132 
01133 void HTMLWriteFileF(STREAM htmlout,FILE* handle)
01134 {
01135  char temp[MAXPATH];
01136  size_t length;
01137  if (!htmlout) return;
01138  length = fread(temp,1,sizeof(temp),handle);
01139  while(length>0)
01140   {
01141     HTMLWriteL(htmlout,temp,length);
01142     length = fread(temp,1,sizeof(temp),handle);
01143   }
01144 }
01145 
01146 int HTMLWriteFile(STREAM htmlout,char * filename)
01147 {
01148  FILE * handle;
01149  if (!htmlout) return 0;
01150  handle = CGIFOPEN(filename,"rb");
01151  if (!handle) return 0;
01152 
01153  HTMLWriteFileF(htmlout,handle);
01154  CGIFCLOSE(handle);
01155 
01156  return 1;
01157 }
01158 
01159 void DebugShowNVP(STREAM htmlout,CGINameValue* v)
01160 {
01161  if (!htmlout) return;
01162  while (v->name)
01163  {
01164   if (*v->name)
01165   {
01166   HTMLWrite(htmlout,v->name);
01167   if (v->value)
01168   {
01169    HTMLWrite(htmlout,"=");
01170    HTMLWrite(htmlout,v->value);
01171   }
01172   HTMLWrite(htmlout,"\n");
01173   }
01174   v++;
01175  }
01176 }
01177 
01178 void GetTime(char * Date,char * Time,int type)
01179 {
01180 #ifdef __WINCE__
01181    SYSTEMTIME tb;
01182 
01183    /* gets time of day */
01184    GetLocalTime(&tb);
01185 
01186  switch (type)
01187   {
01188 case 2:
01189    if (Date) sprintf(Date,"%2.2d/%2.2d/%4.4d",
01190            tb.wMonth,tb.wDay,tb.wYear);
01191    if (Time) sprintf(Time,"%2.2d:%2.2d:%2.2d",
01192           tb.wHour,tb.wMinute,tb.wSecond); break;
01193 case 1:
01194    if (Date) sprintf(Date,"%2.2d/%2.2d/%4.4d",
01195            tb.wDay,tb.wMonth,tb.wYear);
01196    if (Time) sprintf(Time,"%2.2d:%2.2d:%2.2d",
01197           tb.wHour,tb.wMinute,tb.wSecond); break;
01198 
01199 default:
01200    if (Date) sprintf(Date,"%4.4d%2.2d%2.2d",
01201           tb.wYear,tb.wMonth,tb.wDay);
01202    if (Time) sprintf(Time,"%2.2d%2.2d%2.2d",
01203           tb.wHour,tb.wMinute,tb.wSecond);
01204   }
01205 
01206 #else
01207    time_t timer;
01208    struct tm *tb;
01209 
01210    /* gets time of day */
01211    time(&timer);
01212 
01213    /* converts date/time to a structure */
01214    tb = localtime(&timer);
01215  switch (type)
01216   {
01217 case 2:
01218    if (Date) sprintf(Date,"%2.2d/%2.2d/%4.4d",
01219            tb->tm_mday,tb->tm_mon+1,tb->tm_year+1900);
01220    if (Time) sprintf(Time,"%2.2d:%2.2d:%2.2d",
01221           tb->tm_hour,tb->tm_min,tb->tm_sec); break;
01222 case 1:
01223    if (Date) sprintf(Date,"%2.2d/%2.2d/%4.4d",
01224            tb->tm_mon+1,tb->tm_mday,tb->tm_year+1900);
01225    if (Time) sprintf(Time,"%2.2d:%2.2d:%2.2d",
01226           tb->tm_hour,tb->tm_min,tb->tm_sec); break;
01227 
01228 default:
01229    if (Date) sprintf(Date,"%4.4d%2.2d%2.2d",
01230           tb->tm_year+1900,tb->tm_mon+1,tb->tm_mday);
01231    if (Time) sprintf(Time,"%2.2d%2.2d%2.2d",
01232           tb->tm_hour,tb->tm_min,tb->tm_sec);
01233   }
01234 #endif
01235 }
01236 
01237 double Div(double a, double b)
01238 {
01239  if (b == 0.0) return 0.0;
01240  return a / b;
01241 }
01242 
01243 #if 0 /* turn this to 1 to use the built-in pow() */
01244       /* our Power() function has error checking */
01245 #define Power(x,y) pow(x,y)
01246 #else
01247 double Power(double x, double y) /* exponentials are tricky */
01248  {
01249    int neg = 0;
01250    if (x < 0)
01251     {
01252      if (fmod(y,1.0) != 0.0) return 0.0;
01253       /* we don't do complex numbers */
01254      if (fmod(y,2.0) != 0.0) neg = 1;
01255      x = -x;
01256     }
01257 
01258 #ifdef XP_WIN
01259    x = exp(log(x) * y);
01260 #else
01261    return pow(x,y);
01262 #endif
01263    return neg ? -x : x;
01264 /*  double result=1;
01265   int pow = y;
01266   while (pow)
01267   {
01268    result *= x;
01269    pow --;
01270   }
01271   return result;  */
01272  }
01273 #endif
01274 
01275 int StringLength(char* text)
01276 {
01277  int i = 1;
01278  int end = text[0];
01279  while (text[i])
01280  {
01281    if (text[i] == '\\') i++;
01282    else if (text[i] == end) break;
01283    i++;
01284  }
01285  return i;
01286 }
01287 
01288 int FindEndChar(char * text,char start,char finish,int skipquote)
01289 {
01290  int pcount = 0;
01291  int i = 0;
01292  while (text[i])
01293  {
01294        if (text[i] == start ) pcount ++;
01295   else if (text[i] == finish ) pcount --;
01296   else if (skipquote)
01297   {
01298      if (text[i] == '\"' || text[i] == '\'')
01299        i += StringLength(text);
01300   }
01301   if (pcount == 0) return i;
01302   i++;
01303  }
01304  return -1;
01305 }
01306 
01307 char * EvaluateExpressionL(CGINameValue*v, CGINameValue*v2, char* equation,size_t length)
01308 {
01309  char * c;
01310  char * x = CGIMALLOC(length+1);
01311  strncpy(x,equation,length);
01312  x[length]=0;
01313  c = EvaluateExpression(v,v2,x);
01314  CGIFREE(x);
01315  return c;
01316 }
01317 
01318 double EvaluateAlgebraL(CGINameValue*v, CGINameValue*v2,char* equation,size_t length)
01319 {
01320  double c;
01321  char * x = CGIMALLOC(length+1);
01322  strncpy(x,equation,length);
01323  x[length]=0;
01324  c = EvaluateAlgebra(v,v2,x);
01325  CGIFREE(x);
01326  return c;
01327 }
01328 
01329 char* GetField2(CGINameValue*v, CGINameValue*v2,  char* x)
01330 {
01331  if (x[0] == '$')
01332  {
01333   if (v2)
01334    v = v2;
01335   x++;
01336  }
01337 
01338  return GetFieldValue(v,x);
01339 }
01340 
01341 char * EvaluateExpression(CGINameValue*v, CGINameValue*v2,  char* equation)
01342 {
01343  char *c = strrchr(equation,' '); /* strip trailing blanks */
01344  if (c) *c = 0;
01345  EATWHITE(equation);
01346  /* an equation or a number*/
01347  if (strcspn(equation,"(+-*/^%") != strlen(equation))
01348  {
01349   double d = EvaluateAlgebra(v,v2,equation);
01350   int i = (int)d;
01351   char*t = CGIMALLOC(64);
01352   if (i == d)
01353    sprintf(t,"%d",i);
01354   else
01355    sprintf(t,"%f",d);
01356   return t;
01357  }
01358  else if (IsNumber(equation,0))
01359   return strdup(equation);
01360  else
01361   return strdup(GetField2(v,v2,equation));
01362 }
01363 
01369 double EvaluateAlgebra(CGINameValue * v, CGINameValue*v2, char * equation)
01370 {
01371  char * c, *left, *right;
01372  double lastmath;
01373  size_t length;
01374 
01375  if (equation == NULL) return 0.0;
01376 
01377  EATWHITE(equation);
01378  if (*equation == '=') equation++;
01379 
01380  c = strrchr(equation,' '); /* strip trailing blanks */
01381  if (c) *c = 0;
01382 
01383  /* the number of characters in the first part of the expression */
01384  length = strcspn(equation,"(+-*/^%");
01385 
01386  /* if that's all there is, return the replacement value of the field */
01387  if ((length) == strlen(equation))
01388   return strtod(GetField2(v,v2,equation),0);
01389 
01390  /* copy out the mathematical section of the expression */
01391  right = strdup(equation + length);   /* fmath=operator + rvalue */
01392 
01393  /* copy out the leading fieldname of the expression */
01394  left = strndup(equation,length); /* fname=lvalue */
01395 
01396  /* if it's non-blank, get the replacement value */
01397  if (*left && !IsNumber(left,0))
01398   c = GetField2(v,v2,left);
01399  else
01400   c = 0; /* else, ignore the first statement  */
01401 
01402  if (c && *c)
01403   lastmath = strtod(c,0); /* lastmath is the accumulated return value */
01404  else
01405   lastmath = strtod(left,0); /* the thing on the left was probably a number */
01406 
01407  c = right; /* start working on the next part */
01408 
01409  while (c && *c) /* iterate through that section */
01410  {
01411   double math;
01412   char * d, * argument ; /* variables we'll need */
01413   EATWHITE(c); /* duh */
01414   if (*c == '(') /* is it parenthesized? */
01415     argument = c;
01416   else
01417     argument = c + 1;
01418   EATWHITE(argument);
01419   if (isdigit(*argument)) /* it's just a number */
01420      math = strtod(argument,&d);
01421   else if (*argument != '(') /* evaluate the next variable name */
01422     {
01423      length = strcspn(argument,"(+-*/^% \t\r\n");
01424      d = argument+length;
01425      math = EvaluateAlgebraL(v,v2,argument,length);
01426     }
01427   else /* recurse through parentheses */
01428     {
01429      int l = FindEndChar(argument,'(',')',0); /* where does the parenthesis end? */
01430      d = argument + l + 1;
01431      if (l < 2) break; /* whoops! someone screwed up. Can't have empty parens.*/
01432      math = EvaluateAlgebraL(v,v2,argument+1,l-2);
01433     }
01434 
01435   switch (*c) {
01436    case '(': lastmath = math; break; /* only happens when the expression begins with a paren */
01437    case '+': lastmath += math; break;
01438    case '-': lastmath -= math; break;
01439    case '*': lastmath *= math; break;
01440    case '^': lastmath = Power(lastmath,math); break;
01441    case '/': lastmath = Div(lastmath,math); break;
01442    case '%': lastmath = ((int)(math)) ?((int)lastmath)%(int)(math):0; break;
01443    default: break; /* leave while loop */}
01444   c = d;
01445  } /* of while */
01446 
01447  CGIFREE(left);
01448  CGIFREE(right);
01449  return lastmath;
01450 }
01451 
01452 char * strn2istr(char *s1, char *s2,size_t l2)
01453 {
01454  while (*s1)
01455  {
01456   if (strnicmp(s1,s2,l2) == 0) return s1;
01457   s1++;
01458  }
01459  return 0;
01460 }
01461 
01462 char * stristr(char *s1, char *s2)
01463 {
01464  return strn2istr(s1,s2,strlen(s2));
01465 }
01466 
01467 int DoEvaluateLogic(char* current,CGINameValue* Variables,CGINameValue* Var2,char** lastc,int eval);
01468 int DoEvaluateComparison(char* Comparison ,CGINameValue* v,CGINameValue* Var2,char** lastc,int eval);
01469 int LogicSub(char* Comparison ,CGINameValue* v,CGINameValue* Var2,char** lastc,int eval)
01470 {
01471  int bnot = 0;
01472  int ret;
01473  if (Comparison[0] == '!')
01474   {
01475    Comparison++;
01476    EATWHITE(Comparison);
01477    bnot = 1;
01478   }
01479  if (Comparison[0] == '(')
01480    ret = DoEvaluateLogic(Comparison+1,v,Var2,lastc,eval);
01481  else
01482    ret = DoEvaluateComparison(Comparison,v,Var2,lastc,eval);
01483 
01484  if (ret < 0) return ret;
01485  return ret ^ bnot;
01486 }
01487 
01489 int DoEvaluateLogic(char* current,CGINameValue* Variables,CGINameValue* Var2,char** lastc,int eval)
01490 {/* ( condition | condition & condition ) */
01491  int left, right;
01492  if (!eval && !lastc)
01493     return 0;
01494 
01495  EATWHITE(current);
01496 
01497  if (!*current) return 1; /* empty logic is true */
01498 
01499  left = LogicSub(current,Variables,Var2,&current,eval);
01500  if (left < 0) return -1;
01501 
01502  EATWHITE(current);
01503 
01504  while (*current)
01505  {
01506   int op = *current;
01507   int neg = 0;
01508 
01509   if (op == ')') /* quit on end paren ) */
01510    { current ++; break;}
01511 
01512   if (op == '|' || op == '&' || op == '^')
01513     while (*current == op) current++;
01514   else break;
01515 
01516   EATWHITE(current);
01517   if (!*current) return -1;
01518   right = LogicSub(current,Variables,Var2,&current,eval);
01519   if (right < 0) return -1;
01520   if (neg) right = !right;
01521 
01522   switch (op)
01523   {
01524    case '|': left = left || right; break;
01525    case '&': left = left && right; break;
01526    case '^': left = left ^ right; break;
01527    default: return -1;
01528   }
01529   EATWHITE(current);
01530  }
01531  if (lastc) *lastc = current;
01532  return left;
01533 }
01534 
01535 int EvaluateLogic(char* line,CGINameValue* Variables,CGINameValue* Var2)
01536 {
01537  return DoEvaluateLogic(line,Variables,Var2,0,1);
01538 }
01539 
01540 int ComparisonEvaluation(char*field,char*comp,size_t rlength,int op,int isundef)
01541 {
01542      int result = 0;
01543       if (isundef && !field)
01544       {
01545           field = comp = "undefined";
01546           if (op == 9) op = 1;
01547           rlength = 9;
01548       }
01549       else if (!field) return -1; /* field not found */
01550 
01551       {
01552       char * rval = strndup(comp,rlength);
01553 
01554       switch(op)
01555        {/* non-null and non-zero */
01556         case 0: if (strlen(field)) if (*field != '0') result = 1;
01557                 break;
01558 
01559         case 1: if (strlen(field) == rlength)
01560                  if (!strnicmp(field,comp,rlength))
01561                   result = 1;
01562                 break;
01563 
01564         case 2: if (strtod(field,NULL) > strtod(rval,NULL)) result = 1; break;
01565         case 3: if (strtod(field,NULL) < strtod(rval,NULL)) result = 1; break;
01566         case 4: if (strn2istr(field,rval,rlength) != NULL) result = 1; break;
01567         case 5: if (strtod(field,NULL) >= strtod(rval,NULL)) result = 1; break;
01568         case 6: if (strtod(field,NULL) <= strtod(rval,NULL)) result = 1; break;
01569         case 7: if (strlen(field) != rlength || strnicmp(field,rval,rlength)) result = 1; break;
01570         case 8: if (strn2istr(field,rval,rlength) == NULL) result = 1; break;
01571         case 9: if (strtod(field,NULL) == strtod(rval,NULL)) result = 1; break;
01572         case 10: if (HasToken(field,rval,NULL)) result = 1;
01573 
01574        }
01575       CGIFREE(rval);
01576       }
01577       return result;
01578  }
01579 
01584 int DoEvaluateComparison(char* Comparison ,CGINameValue* v,CGINameValue* Var2,char** lastc,int eval)
01585 {
01586       char *comp, *freeme=0;
01587       int op = 0;
01588       int result;
01589       int ORsearch = 0;
01590       size_t x,length;
01591       int bnot = 0;
01592        int isundef = 0;
01593       size_t rlength = 0;
01594 
01595       if (!v) return 0;
01596       if (!eval && !lastc)
01597           return 0;
01598 
01599       if (lastc) *lastc = Comparison;
01600       if (Comparison[0] == 0) return -1;
01601 
01602       if (Comparison[0] == '!')
01603        {
01604         bnot = 1;
01605         Comparison++;
01606         EATWHITE(Comparison);
01607        }
01608 
01609       if (Comparison[0] == '/')
01610        {
01611         Comparison++;
01612         ORsearch = 1;
01613        }
01614       /* the first token is always assumed to be a field name */
01615 
01616       /* read the LHS until a valid operator is found */
01617       comp = Comparison;
01618 
01619       while (op == 0 && comp[0])
01620       {
01621            if (!strnicmp(comp,"gte ",4)){op = 5; rlength = 4;}
01622       else if (!strnicmp(comp,"has ",4)){op = 10; rlength = 4; ORsearch = 1;}
01623       else if (!strnicmp(comp,">=",2))  {op = 5; rlength = 2;}
01624       else if (!strnicmp(comp,"<=",2))  {op = 6; rlength = 2;}
01625       else if (!strnicmp(comp,"lte ",4)){op = 6; rlength = 3;}
01626       else if (!strnicmp(comp,">",1))   {op = 2; rlength = 1;}
01627       else if (!strnicmp(comp,"gt ",3)) {op = 2; rlength = 3;}
01628       else if (!strnicmp(comp,"<",1))   {op = 3; rlength = 1;}
01629       else if (!strnicmp(comp,"lt ",3)) {op = 3; rlength = 3;}
01630       else if (!strnicmp(comp,"=~",2))  {op = 4; rlength = 2;}/* substring */
01631       else if (!strnicmp(comp,"!~",2))  {op = 8; rlength = 2;}/* not substring */
01632       else if (!strnicmp(comp,"s ",2))  {op = 4; rlength = 2;}/* substring */
01633       else if (!strnicmp(comp,"eq ",3)) {op = 1; rlength = 2;}
01634       else if (!strnicmp(comp,"===",3)) {op = 9; rlength = 3;}/* numeric equals */
01635       else if (!strnicmp(comp,"==",2))  {op = 9; rlength = 2;}/* numeric equals */
01636       else if (!strnicmp(comp,"=",1))   {op = 1; rlength = 1;}/* = */
01637       else if (!strnicmp(comp,"!=",2))  {op = 7; rlength = 2;}
01638       else if (!strnicmp(comp,"ne ",3)) {op = 7; rlength = 2;}
01639       else if (strchr("?:",comp[0])) break;
01640       else if (strchr(" \t\r\n",comp[0])) EATWHITE(comp);
01641       else if (strchr("~=<>!",comp[0])) return -1;
01642       else {
01643       while (comp[0] && strchr("~=<>! ",comp[0]) == NULL)   comp++;
01644       EATWHITE(comp); }
01645       }
01646 
01647       if (!*comp) /* reached the end without an operator or action */
01648        return -1;
01649 
01650       length = comp - Comparison;
01651       if (!length)
01652        return -1; /* oops - no lvalue */
01653 
01654       /* trim trailing whitespace */
01655       while (length && strchr(" \r\t\n",Comparison[length-1])) length --;
01656 
01657       comp += rlength; /* skip the operator */
01658       EATWHITE(comp); /* skip WS */
01659 
01660       rlength = 0;
01661 
01662       /* read the rvalue, and reuse rlength */
01663       if (*comp == '\'' || *comp == '\"') /* read a string literal */
01664        {
01665         rlength = StringLength(comp); /* StringLength returns 2 or more */
01666         if (!comp[rlength]) /* unterminated string */
01667           return -1;
01668 
01669         if (lastc) *lastc = comp + rlength +1;
01670         if (!eval) return 0;
01671         comp ++;
01672         rlength --;
01673         if (rlength == 0)
01674             isundef = 1;
01675        }
01676       else /* if (*comp == '=' || *comp == '$' || !IsNumber(comp))*/
01677        {/* treat the rhs as a field or arithmetic expression */
01678         /* if it's a numeric constant, t//HERE shouln't be any problem */
01679         /* if (comp[0] == '=' || comp[0] == '$')
01680           comp++; {field==value} or {field = $value}
01681           if an exposed ), stop the scan and return. */
01682         while (comp[rlength] && !strchr("?:!&|) \r\t\n",comp[rlength]))
01683          {
01684           rlength++;
01685          }
01686         if (lastc) *lastc = comp + rlength;
01687 
01688          if (!eval) return 0;
01689 
01690         if (!strnicmp(comp,"undefined",rlength))
01691             isundef = 1;
01692         else if (!IsNumber(comp,rlength))
01693         {
01694          comp = freeme = EvaluateExpressionL(v,Var2,comp,rlength);
01695          if (comp) rlength = strlen(comp);
01696          else rlength = 0;
01697         }
01698        }
01699 
01700       if (comp == NULL) comp = "";
01701 
01702       if (ORsearch && length && Comparison[length-1]=='/') length --;
01703       /* remove trailing slash */
01704 
01705       if (Comparison[0] == '\'' || Comparison[0] == '\"')
01706       {
01707        char* field = strndup(Comparison + 1,length-1);
01708        result = ComparisonEvaluation(field,comp,rlength,op,isundef);
01709        CGIFREE(field);
01710       }
01711       else
01712       {
01713         char * x = EvaluateExpressionL(v,Var2,Comparison,length);
01714         result = ComparisonEvaluation(x,comp,rlength,op,isundef);
01715         CGIFREE(x);
01716       }
01717 
01718       if (result) return bnot ^ 1;
01719       if (ORsearch)
01720       {
01721        CGINameValue* list = v;
01722        while (list)
01723        {
01724         size_t y=0;
01725         for (x=0; list[x].name; x++)
01726         {
01727          y=x;
01728 
01729          if (strlen(list[x].name) < length)
01730           continue;
01731 
01732          if (strnicmp(Comparison,list[x].name,length))
01733           continue;
01734 
01735          /* Q1_value */
01736          if (list[x].name[length] && list[x].name[length] != '_')
01737           continue;
01738 
01739           result = ComparisonEvaluation(list[x].value,comp,rlength,op,isundef);
01740          if (result) return bnot ^ 1;
01741         }
01742         while (!list[y].last) y++;
01743         list = (CGINameValue*)list[y].value;
01744        }
01745       }
01746 
01747   CGIFREE(freeme);
01748   return bnot; /* not ^ 0 */
01749 }
01750 
01751 int EvaluateComparison(char* Comparison ,CGINameValue* v,CGINameValue* Var2,char** lastc)
01752 {
01753  return DoEvaluateComparison(Comparison ,v,Var2,lastc,1);
01754 }
01755 
01756 int RenameField(CGINameValue*d, char* oldname, char* newname)
01757 {
01758  d = GetField(d,oldname);
01759  if (d == NULL) return 0;
01760  SetName(d,newname);
01761  return 1;
01762 }
01763 
01774 void SetName(CGINameValue*d, char* name)
01775 {
01776  if (name == NULL)
01777   {
01778     if (d->name) d->name[0]=0;
01779     if (d->value) d->value[0]=0;
01780   }
01781  else
01782   {
01783    char *n = name;
01784    char *o = d->name;
01785    while (*n && *o) *o++ = *n++;
01786    if (*n == 0 && *o != 0) *o = 0;
01787    else  if (*o == 0 && *n != 0)
01788    {
01789     CGIFREE(d->name);
01790     d->name = strdup(name);
01791    }
01792   }
01793 }
01794 
01795 void SetValue(CGINameValue*d, char* value)
01796 {
01797  if (value == NULL)
01798   {
01799     if (d->value) d->value[0]=0;
01800   }
01801  else if (d->value == NULL)
01802   {
01803    goto set;
01804   }
01805  else
01806   {
01807    char *n = value;
01808    char *o = d->value;
01809    while (*n && *o) *o++ = *n++;
01810    if (*n == 0 && *o != 0) *o = 0;
01811    else  if (*o == 0 && *n != 0)
01812    {
01813     CGIFREE(d->value);
01814     set:
01815     d->value = strdup(value);
01816    }
01817   }
01818 }
01819 
01820 int SetFieldValue(CGINameValue *f,char * fieldname,char* value)
01821 {
01822  CGINameValue *d = GetField(f,fieldname);
01823  if (d == NULL)
01824   {
01825    d = GetField(f,"");
01826    if (d == NULL) return 0;
01827    SetName(d,fieldname);
01828   }
01829 
01830  if (d == NULL) return 0;
01831 
01832  SetValue(d,value);
01833  return 1;
01834 }
01835 
01837 int GetFieldInt(CGINameValue *data,char * fieldname)
01838 {char * endptr;
01839  return strtol(GetFieldValue(data,fieldname),&endptr,10);
01840 }
01841 
01842 double GetFieldFloat(CGINameValue*data,char * fieldname)
01843 {char * endptr;
01844  return strtod(GetFieldValue(data,fieldname),&endptr);
01845 }
01846 
01850 CGINameValue* NewNVP(size_t count)
01851 {
01852  CGINameValue * v;
01853  size_t i;
01854  v = (CGINameValue*) CGIMALLOC((count + 1) * sizeof(CGINameValue));
01855  for (i = 0; i <= count; i++)
01856   {
01857    v[i].name = 0;
01858    v[i].value = 0;
01859    v[i].last = 0;
01860   }
01861  v[count].last = 1;
01862  return v;
01863 }
01864 
01865 void DeleteNVP(CGINameValue* v)
01866 {
01867  int i,l;
01868  if (v == NULL) return;
01869  for (i=0; v[i].last == 0 ; i++)
01870   {
01871    if (v[i].name) CGIFREE(v[i].name);
01872    if (v[i].value) CGIFREE(v[i].value);
01873    l=i;
01874   }
01875  l++;
01876  if (v[l].last && v[l].value)
01877   {
01878    DeleteNVP((CGINameValue*)(void*)v[l].value);
01879   }
01880  CGIFREE(v);
01881 }
01882 
01883 void ExtendNVP(CGINameValue * v, size_t count)
01884 {
01885  size_t i,l;
01886  if (v == NULL) return;
01887  for (i=0; v[i].last == 0 ; i++)
01888   {
01889    l=i;
01890   }
01891  l++;
01892  if (v[l].last)
01893   {
01894    if (v[l].value)
01895      ExtendNVP((CGINameValue*)(void*)v[l].value,count);
01896    else
01897    {
01898      CGINameValue* n = NewNVP(count);
01899      v[l].value = (char*)(void*)n;
01900      for (i=0; i<count; i++)
01901       {
01902        n[i].name = strdup(NULLSTR);
01903       }
01904    }
01905   }
01906 }
01907 
01908 CGINameValue * GetField(CGINameValue * data, char * fieldname)
01909 {
01910  int x,i=0;
01911  if (data == NULL)
01912    return NULL;
01913 
01914  for(x=0; data[x].last == 0; x++)
01915    {
01916      i = x;
01917      if (!data[x].name)
01918        continue;
01919 
01920      if (!data[x].name[0] && !fieldname[0])
01921        return &data[x];
01922 
01923      if (stricmp(fieldname,data[x].name)==0)
01924        return &data[x];
01925    }
01926 
01927   i++;
01928 
01929   if (data[i].last && data[i].value)
01930    return GetField((CGINameValue*)(void*)data[i].value,fieldname);
01931 
01932 return NULL;
01933 }
01934 
01935 
01936 CGINameValue* CopyListJoin(CGINameValue* a,CGINameValue* b,size_t extra)
01937 {
01938  CGINameValue * v;
01939  size_t x=0;
01940  size_t y=0;
01941  if (b == NULL) return CopyList(a,extra);
01942 
01943  while (a[x].name != NULL) x++;
01944 
01945  while (b[y].name != NULL)
01946   {
01947    if (GetField(a,b[y].name)== NULL) x++;
01948    y++;
01949   }
01950 
01951  v = NewNVP(x+extra);
01952 
01953  for (x=0; x<extra; x++)
01954  {
01955   v[x].name = strdup("");
01956  }
01957  x=0;
01958  while (a[x].name != NULL)
01959  { v[x+extra].name = strdup(a[x].name);
01960    if (a[x].value)
01961      v[x+extra].value = strdup(a[x].value);
01962   x++;
01963  }
01964  y=0;
01965  while (b[y].name != NULL)
01966  {
01967   if (GetField(a,b[y].name)== NULL)
01968   {
01969    v[x+extra].name = strdup(b[y].name);
01970    if (b[y].value)
01971      v[x+extra].value = strdup(b[y].value);
01972    x++;
01973   }
01974   y++;
01975  }
01976  return v;
01977 }
01978 
01979 CGINameValue* CopyListDeep(CGINameValue* header,size_t extra)
01980 {
01981  CGINameValue * v, *c=header;
01982 
01983  size_t x=0;
01984  while (c)
01985  {
01986   size_t i=0;
01987   while (c[i].name != NULL) {if (c[i].name[0]) x++;i++; }
01988   if (!c[i].last) break;
01989   c = (CGINameValue*) c[i].value;
01990  }
01991 
01992  v = NewNVP(x+extra);
01993  c = header;
01994  x=0;
01995  while (c)
01996  {
01997   size_t i=0;
01998   while (c[i].name)
01999   {
02000    if (!c[i].name[0]) {i++; continue;}
02001    v[x+extra].name = strdup(c[i].name);
02002    if (c[i].value)
02003      v[x+extra].value = strdup(c[i].value);
02004    i++;
02005    x++;
02006   }
02007   if (!c[i].last) break;
02008   c = (CGINameValue*) c[i].value;
02009  }
02010 
02011  for (x=0;x<extra;x++)
02012   {
02013   v[x].name = strdup(NULLSTR);
02014   v[x].value = strdup(NULLSTR);
02015   }
02016  return v;
02017 }
02018 
02019 size_t ListLength(CGINameValue*header)
02020 {
02021  size_t x = 0;
02022  if (header)
02023  while (header->name != NULL)
02024  {
02025   if (header->name[0])
02026     x++;
02027   header++;
02028  }
02029  return x;
02030 }
02031 
02032 CGINameValue* CopyList(CGINameValue* header,size_t extra)
02033 {
02034  CGINameValue * v;
02035 
02036  size_t x = ListLength(header);
02037  size_t y = 0;
02038  v = NewNVP(x+extra);
02039 
02040  if (header)
02041  for (x=0;header[x].name != NULL;x++)
02042   {
02043    if (header[x].name[0])
02044    {
02045     v[y+extra].name = strdup(header[x].name);
02046     if (header[y].value)
02047       v[y+extra].value = strdup(header[x].value);
02048     y++;
02049    }
02050   }
02051 
02052  for (x=0;x<extra;x++)
02053   {
02054   v[x].name = strdup(NULLSTR);
02055   v[x].value = strdup(NULLSTR);
02056   }
02057  return v;
02058 }
02059 
02061 CGINameValue* CopyListN(CGINameValue* header,size_t extra,...)
02062 {
02063    va_list ap;
02064    CGINameValue * n;
02065    size_t x;
02066 
02067    n = CopyList(header,extra);
02068    va_start(ap, extra);
02069 
02070    for (x=0; extra > 0 && n[x].name != NULL; x++)
02071      {char *c;
02072       if (n[x].name[0]) continue;
02073 
02074       c = va_arg(ap, char*);
02075      CGIFREE(n[x].name);
02076      n[x].name = strdup(c);
02077      extra--;
02078     }
02079 
02080    va_end(ap);
02081    return n;
02082 }
02083 
02084 #ifdef __WINCE__
02085 int FileSize(char * fname)
02086 {
02087     HANDLE h;
02088     int l;
02089     wchar_t fn[MAXPATH];
02090     fn[MultiByteToWideChar(CP_UTF8,0,fname,strlen(fname),fn,MAXPATH)] = 0;
02091     h = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
02092     if (h == INVALID_HANDLE_VALUE ) return 0;
02093     l = GetFileSize(h,NULL);
02094     CloseHandle(h);
02095     return l;
02096 }
02097 #else
02098 int FileSize(char * fname)
02099    {
02100     struct stat StatBuf;
02101      if (!fname) return 0;
02102      if (!*fname) return 0;
02103      if (stat(fname, & StatBuf) != 0) return 0;
02104      return StatBuf.st_size;
02105    }
02106 #endif
02107 
02108 #if 0
02109 /*  defined(XP_WIN) &&!defined(__WINCE__) */
02110 
02112 CGINameValue* ReadINIFileSection(char * file, char * section,int reserve)
02113 {
02114  CGINameValue* v;
02115  char * c, *d;
02116  int maxsize = FileSize(file);
02117  char * str;
02118  int i,length;
02119  if (maxsize <= 0) return NULL;
02120  str = CGIMALLOC(maxsize+1);
02121  if (!str) return NULL;
02122  str[maxsize]=0;
02123 
02124 #ifdef UNICODE
02125  GetPrivateProfileSectionA(section,str,maxsize,file);
02126 #else
02127  GetPrivateProfileSection(section,str,maxsize,file);
02128 #endif
02129 
02130  length = reserve;
02131  c = str;
02132  while (*c)
02133  {
02134   while (*c) c++;
02135   c++;
02136   length++;
02137  }
02138 
02139  c = str;
02140  if (length == 0) {CGIFREE(str); return NULL;}
02141 
02142  v = NewNVP(length);
02143 
02144  for (i=0; i<reserve; i++)
02145   {
02146    v[i].name = strdup(NULLSTR);
02147    v[i].value = strdup(NULLSTR);
02148   }
02149 
02150  if (length == reserve) {CGIFREE(str); return v;}
02151 
02152  i = reserve;
02153  while (*c)
02154  {
02155   d = c;
02156   length=0;
02157   while (*c && *c != '=') {c++;length++;}
02158   c++;
02159   v[i].name=strndup(d,length);
02160 
02161   d = c;
02162   length = 0;
02163   while (*c) {c++;length++;}
02164   c++;
02165   v[i].value=strndup(d,length);
02166   i++;
02167  }
02168  CGIFREE(str);
02169  return v;
02170 }
02171 #else
02172 
02173 void killchar(char*c, char kill)
02174 {
02175  int i=0,j=0;/*i is the new str, j is the current str.*/
02176  while (c[j])
02177  {
02178      if (c[j] != kill)
02179          c[i++] = c[j++];
02180      else
02181          j++;
02182  }
02183  c[i]=0;
02184 }
02185 
02186 CGINameValue* ReadINIFileSection(char * filename, char * section,int reserve)
02187 {
02188  CGINameValue* ret = NULL;
02189  int d;
02190  int maxsize = FileSize(filename);
02191  char * str;
02192  FILE * file= NULL;
02193  if (maxsize <= 0) return NULL;
02194  str = CGIMALLOC(maxsize+1);
02195  if (str == NULL) return NULL;
02196  str[maxsize]=0;
02197 
02198  file = CGIFOPEN(filename,"rt");
02199  if (file != NULL)
02200  while (1)
02201  {
02202   d = ReadUntilChar(file,0,0,"[",'\r');
02203   if (d < 0) break;
02204   d = ReadUntilChar(file,str,maxsize,"]\n",'\r');
02205   if (d == ']')
02206    {
02207     if (stricmp(str,section)==0)
02208     {
02209      ReadUntilWord(file,str,maxsize,"\n[");
02210      killchar(str,'\r');
02211      ret = ReadPairedString(str,'\n',reserve);
02212      break;
02213     }
02214    }
02215  }
02216  CGIFCLOSE(file);
02217  CGIFREE(str);
02218  return ret;
02219 }
02220 #endif
02221 
02222 CGINameValue* ReadPairedValues(int argc, char ** argv,int reserve)
02223 {
02224  CGINameValue* v;
02225  char * c;
02226  int i,length,max;
02227  max = argc + reserve;
02228  if (max <= 0) return NULL;
02229 
02230  v = NewNVP(max);
02231 
02232  for (i=0; i<reserve; i++)
02233   {
02234    v[i].name = strdup(NULLSTR);
02235    v[i].value = strdup(NULLSTR);
02236   }
02237 
02238  for (i = 0 ; i < argc ; i++ )
02239  {
02240   c = argv[i];
02241   length=0;
02242   while (*c && *c != '=') {c++;length++;}
02243   if (*c) c++;
02244   v[i+reserve].name=strndup(argv[i],length);
02245   v[i+reserve].value=strdup(c);
02246  }
02247  return v;
02248 }
02249 
02251 CGINameValue* ReadPairedString(char * str,char delim,int reserve)
02252 {
02253   CGINameValue *v;
02254   char *c;
02255   int i,j,count,done;
02256   if (!str) return NULL;
02257   count = reserve;
02258   if (str[0]) count++;
02259 
02260   for (i=1; str[i]; i++)
02261   {
02262     if (str[i] == delim) count++;
02263   }
02264 
02265   if (count == 0 && reserve == 0)
02266   {
02267    if (str[0])
02268      count = 1;
02269    else
02270      return NULL;
02271   }
02272 
02273   v = NewNVP(count);
02274 
02275   c = str;
02276   done =0;
02277   for (i=0; i<reserve; i++)
02278   {
02279    v[i].name = strdup(NULLSTR);
02280    v[i].value = strdup(NULLSTR);
02281   }
02282 
02283   if (count == reserve) return v;
02284 
02285   i = reserve;
02286   while(!done && *c)
02287   {
02288     int x=1;
02289     /* eat empties */
02290     while (*c == delim) c++;
02291     if (isalnum(*c) || *c == '_') /* legal start characters for a field value */
02292     {
02293       for (j=1; c[j] != '=' && c[j] != delim && c[j]; j++){x++;}/* name length*/
02294       v[i].name = strndup(c, x);
02295       if (c[x] == '=')
02296       {
02297         c = c + x + 1;
02298         x=0;
02299         for (j=0; c[j] != delim && c[j]; j++) {x++;}
02300         v[i].value = strndup(c, x);
02301       }
02302       else
02303       {
02304         v[i].value = strdup("");
02305       }
02306       if (*c)
02307         c = c + x + 1;
02308       i++;
02309     }
02310     else if (*c == '=') /* "=blah" is deleted */
02311      while (*c && *c != delim) c++;
02312     else c++; /* whitespace */
02313     if (i >= count) done = 1;
02314   }
02315 
02316   return v;
02317 }
02318 


Raosoft, Inc.
Raosoft EZReport, EZSurvey, InterForm, RapidReport, Raosoft, and SurveyWin are registered trademarks of Raosoft, Inc. Page contents © 1996-2007 by Raosoft, Inc. You may use and modify this file for your own use, but may not distribute it or derivative works without the prior written consent of Raosoft, Inc. This software is provided "as is," and Raosoft makes no warranty, express or implied, of fitness for a particular application. Every measure has been taken to anticipate risks inherent to computer networks, but we cannot guarantee safety or reliability of this program in every situation.
Tel: 206-525-4025 (US) Email: raosoft@raosoft.com
http://www.raosoft.com/