Back to index

opendkim  2.6.6
ut.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2011, The OpenDKIM Project.  All rights reserved.
00003 */
00004 
00005 #ifndef lint
00006 static char ut_c_id[] = "$Id$";
00007 #endif /* ! lint */
00008 
00009 /* system includes */
00010 #include <sys/param.h>
00011 #include <sys/types.h>
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include <ctype.h>
00016 #include <assert.h>
00017 
00018 /* libut includes */
00019 #include "ut.h"
00020 
00021 /* types */
00022 struct ut_keyvalue
00023 {
00024        int                  ukv_type;
00025        const char *         ukv_key;
00026        void *               ukv_value;
00027        struct ut_keyvalue * ukv_next;
00028 };
00029 
00030 struct uri_template
00031 {
00032        struct ut_keyvalue * ut_params;
00033        struct ut_keyvalue * ut_paramstail;
00034 };
00035 
00036 #define       UT_GEN_DELIM(x)             ((x) == ':' || \
00037                              (x) == '/' || \
00038                              (x) == '?' || \
00039                              (x) == '#' || \
00040                              (x) == '[' || \
00041                              (x) == ']' || \
00042                              (x) == '@')
00043 
00044 #define       UT_SUB_DELIM(x)             ((x) == '!' || \
00045                              (x) == '$' || \
00046                              (x) == '&' || \
00047                              (x) == '\'' || \
00048                              (x) == '(' || \
00049                              (x) == ')' || \
00050                              (x) == '*' || \
00051                              (x) == '+' || \
00052                              (x) == ',' || \
00053                              (x) == ';' || \
00054                              (x) == ';' || \
00055                              (x) == '=')
00056 
00057 #define UT_UNRESERVED(x)    (isalpha(x) || isdigit(x) || \
00058                              (x) == '-' || \
00059                              (x) == '.' || \
00060                              (x) == '_' || \
00061                              (x) == '~')
00062 
00063 #define       UT_RESERVED(x)              (UT_GEN_DELIM(x) || UT_SUB_DELIM(x))
00064 
00065 #define UT_OP_RESERVE(x)    ((x) == '=' || \
00066                              (x) == ',' || \
00067                              (x) == '!' || \
00068                              (x) == '@' || \
00069                              (x) == '|')
00070 
00071 #define UT_OPERATOR(x)             ((x) == '+' || \
00072                              (x) == '#' || \
00073                              (x) == '.' || \
00074                              (x) == '/' || \
00075                              (x) == ';' || \
00076                              (x) == '?' || \
00077                              (x) == '&' || \
00078                              UT_OP_RESERVE(x))
00079 
00080 #define       UT_VARCHAR(x)        (isalpha(*x) || \
00081                              isdigit(*x) || \
00082                              (*x) == '_' || \
00083                              ut_pct_encoded(x))
00084 
00085 #define UT_ALLOW_U          1
00086 #define UT_ALLOW_UR         2
00087 
00088 /*
00089 **  UT_HEXDIGIT -- hexadecimal digit conversion
00090 **
00091 **  Parameters:
00092 **     c -- character to convert
00093 **
00094 **  Return value:
00095 **     Decimal equivalent, or 0 on error.
00096 */
00097 
00098 static int
00099 ut_hexdigit(int c)
00100 {
00101        if (c >= '0' && c <= '9')
00102               return c - '0';
00103        else if (c >= 'A' && c <= 'F')
00104               return c - 'A' + 10;
00105        else if (c >= 'a' && c <= 'f')
00106               return c - 'a' + 10;
00107        else
00108               return 0;
00109 }
00110 
00111 /*
00112 **  UT_PCT_ENCODED -- determine whether or not a pct-encoded byte has
00113 **                    been encoutered
00114 **
00115 **  Parameters:
00116 **     p -- string to scan
00117 ** 
00118 **  Return value:
00119 **     1 iff "p" points to something "pct-encoded"
00120 */
00121 
00122 static int
00123 ut_pct_encoded(const char *p)
00124 {
00125        assert(p != NULL);
00126 
00127        return (*p == '%' && isxdigit(*(p + 1)) && isxdigit(*(p + 2)));
00128 }
00129 
00130 /*
00131 **  UT_VALID_VARNAME -- confirm a valid varname
00132 **
00133 **  Parameters:
00134 **     s -- string to check
00135 **
00136 **  Return value:
00137 **     1 iff "s" points to a valid varname
00138 */
00139 
00140 static int
00141 ut_valid_varname(const char *s)
00142 {
00143        char *p;
00144 
00145        assert(s != NULL);
00146 
00147        if (!UT_VARCHAR(&s[0]))
00148               return 0;
00149 
00150        for (p = (char *) &s[1]; *p != '\0'; p++)
00151        {
00152               if (*p != '.' && !UT_VARCHAR(p))
00153                      return 0;
00154        }
00155 
00156        return 1;
00157 }
00158 
00159 /*
00160 **  UT_FREE -- free a key-value node and its descendents
00161 **
00162 **  Parameters:
00163 **     kv -- a key-value node
00164 **
00165 **  Return value:
00166 **     None.
00167 */
00168 
00169 static void
00170 ut_free(struct ut_keyvalue *kv)
00171 {
00172        assert(kv != NULL);
00173 
00174        if (kv->ukv_type == UT_KEYTYPE_STRING)
00175        {
00176               free((void *) kv->ukv_key);
00177               if (kv->ukv_value != NULL)
00178                      free(kv->ukv_value);
00179 
00180        }
00181        else if (kv->ukv_type == UT_KEYTYPE_LIST ||
00182                 kv->ukv_type == UT_KEYTYPE_KEYVALUE)
00183        {
00184               struct ut_keyvalue *next;
00185               struct ut_keyvalue *tmp;
00186 
00187               tmp = kv->ukv_value;
00188               while (tmp != NULL)
00189               {
00190                      free((void *) tmp->ukv_key);
00191                      if (tmp->ukv_value != NULL)
00192                             free(tmp->ukv_value);
00193 
00194                      next = tmp->ukv_next;
00195                      free(tmp);
00196                      tmp = next;
00197               }
00198        }
00199 
00200        free(kv);
00201 }
00202 
00203 /*
00204 **  UT_FINDKEY -- locate a key in a URI template handle
00205 **
00206 **  Parameters:
00207 **     ut -- URITEMP handle
00208 **     key -- key to find
00209 **
00210 **  Return value:
00211 **     Pointer to a (struct ut_keyvalue) node, or NULL if not found.
00212 */
00213 
00214 static struct ut_keyvalue *
00215 ut_findkey(URITEMP ut, const char *key)
00216 {
00217        struct ut_keyvalue *find;
00218 
00219        for (find = ut->ut_params; find != NULL; find = find->ukv_next)
00220        {
00221               if (strcasecmp(find->ukv_key, key) == 0)
00222                      return find;
00223        }
00224 
00225        return NULL;
00226 }
00227 
00228 /*
00229 **  UT_APPEND -- append a string, encoding as needed
00230 **
00231 **  Parameters:
00232 **     ap -- append point
00233 **     rem -- bytes available at "ap"
00234 **     allow -- allowed characters
00235 **     in -- input string
00236 **     maxlen -- max length (-1 for unbounded)
00237 **
00238 **  Return value:
00239 **     Count of bytes appended; may exceed "rem" if truncation occurred
00240 */
00241 
00242 static size_t
00243 ut_append(char *ap, size_t rem, int allow, const char *in, int maxlen)
00244 {
00245        int encode = 0;
00246        size_t out = 0;
00247        const char *p;
00248 
00249        assert(ap != NULL);
00250        assert(allow == UT_ALLOW_U || allow == UT_ALLOW_UR);
00251        assert(in != NULL);
00252 
00253        for (p = in; *p != '\0'; p++)
00254        {
00255               if (allow == UT_ALLOW_U && !UT_UNRESERVED(*p))
00256                      encode = 1;
00257               else if (allow == UT_ALLOW_UR &&
00258                        !(UT_UNRESERVED(*p) ||
00259                          UT_RESERVED(*p) ||
00260                          ut_pct_encoded(p)))
00261                      encode = 1;
00262               else
00263                      encode = 0;
00264 
00265               if (encode)
00266               {
00267                      (void) snprintf(ap, rem, "%%%02X", *p);
00268                      ap += 3;
00269                      rem -= 3;
00270                      out += 3;
00271               }
00272               else
00273               {
00274                      *ap++ = *p;
00275                      rem--;
00276                      out++;
00277 
00278               }
00279 
00280               if (maxlen > 0)
00281               {
00282                      maxlen--;
00283                      if (maxlen <= 0)
00284                             break;
00285               }
00286        }
00287 
00288        return out;
00289 }
00290 
00291 /*
00292 **  UT_INIT -- initialize a URI template handle
00293 **
00294 **  Parameters:
00295 **     None.
00296 **
00297 **  Return value:
00298 **     None.
00299 */
00300 
00301 URITEMP
00302 ut_init(void)
00303 {
00304        struct uri_template *new;
00305 
00306        new = malloc(sizeof *new);
00307 
00308        if (new != NULL)
00309               memset(new, '\0', sizeof *new);
00310 
00311        return new;
00312 }
00313 
00314 /*
00315 **  UT_DESTROY -- release a URI template handle and all allocated resources
00316 **                associated with it
00317 **
00318 **  Parameters:
00319 **     ut -- URITEMP handle previously allocated by ut_init()
00320 **
00321 **  Return value:
00322 **     None.
00323 */
00324 
00325 void
00326 ut_destroy(URITEMP ut)
00327 {
00328        assert(ut != NULL);
00329 
00330        struct ut_keyvalue *kv;
00331        struct ut_keyvalue *tmp;
00332 
00333        kv = ut->ut_params;
00334        while (kv != NULL)
00335        {
00336               tmp = kv->ukv_next;
00337               ut_free(kv);
00338               kv = tmp;
00339        }
00340 
00341        free(ut);
00342 }
00343 
00344 /*
00345 **  UT_KEYVALUE -- set a key-value of some kind inside a URI template
00346 **
00347 **  Parameters:
00348 **     ut -- URITEMP handle previously returned by ut_init();
00349 **
00350 **  Return value:
00351 **     0 -- success
00352 **     !0 -- error
00353 */
00354 
00355 int
00356 ut_keyvalue(URITEMP ut, int type, const char *key, void *value)
00357 {
00358        int c;
00359        const char **strings;
00360        struct ut_keyvalue *kv;
00361        struct ut_keyvalue *prev;
00362        struct ut_keyvalue *new;
00363        struct ut_keyvalue *child;
00364        struct ut_keyvalue *head;
00365        struct ut_keyvalue *tail;
00366 
00367        assert(ut != NULL);
00368        assert(key != NULL);
00369        assert(value != NULL);
00370        assert(type == UT_KEYTYPE_STRING ||
00371               type == UT_KEYTYPE_LIST ||
00372               type == UT_KEYTYPE_KEYVALUE);
00373 
00374        /* see if we have it already */
00375        prev = kv;
00376        kv = ut->ut_params;
00377        while (kv != NULL)
00378        {
00379               if (strcasecmp(key, kv->ukv_key) == 0)
00380               {
00381                      if (prev != NULL)
00382                      {
00383                             prev->ukv_next = kv->ukv_next;
00384                             if (kv == ut->ut_paramstail)
00385                                    ut->ut_paramstail = prev;
00386                             ut_free(kv);
00387                             kv = prev;
00388                      }
00389                      else
00390                      {
00391                             ut->ut_params = kv->ukv_next;
00392                             if (kv == ut->ut_paramstail)
00393                                    ut->ut_paramstail = prev;
00394                             ut_free(kv);
00395                             kv = ut->ut_params;
00396                      }
00397 
00398                      break;
00399               }
00400 
00401               prev = kv;
00402               kv = kv->ukv_next;
00403        }
00404 
00405        /* store the new one */
00406        new = malloc(sizeof *new);
00407        if (new == NULL)
00408               return -1;
00409 
00410        memset(new, '\0', sizeof *new);
00411        new->ukv_type = type;
00412 
00413        new->ukv_key = strdup(key);
00414        if (new->ukv_key == NULL)
00415        {
00416               free(new);
00417               return -1;
00418        }
00419 
00420        switch (type)
00421        {
00422          case UT_KEYTYPE_STRING:
00423               new->ukv_value = strdup((char *) value);
00424               if (new->ukv_value == NULL)
00425               {
00426                      free((void *) new->ukv_key);
00427                      free(new);
00428                      return -1;
00429               }
00430               break;
00431 
00432          case UT_KEYTYPE_LIST:
00433               strings = (const char **) value;
00434               head = NULL;
00435               tail = NULL;
00436 
00437               for (c = 0; strings[c] != NULL; c++)
00438               {
00439                      child = malloc(sizeof *child);
00440                      if (child == NULL)
00441                      {
00442                             ut_free(new);
00443                             return -1;
00444                      }
00445 
00446                      memset(child, '\0', sizeof *child);
00447 
00448                      child->ukv_key = strdup(strings[c]);
00449                      if (child->ukv_key == NULL)
00450                      {
00451                             ut_free(new);
00452                             return -1;
00453                      }
00454 
00455                      if (head == NULL)
00456                      {
00457                             head = child;
00458                             tail = child;
00459                      }
00460                      else
00461                      {
00462                             tail->ukv_next = child;
00463                             tail = child;
00464                      }
00465               }
00466 
00467               new->ukv_value = head;
00468               break;
00469 
00470          case UT_KEYTYPE_KEYVALUE:
00471               strings = (const char **) value;
00472               head = NULL;
00473               tail = NULL;
00474 
00475               for (c = 0; strings[c] != NULL; c++)
00476               {
00477                      if (c % 2 == 0)
00478                      {
00479                             child = malloc(sizeof *child);
00480                             if (child == NULL)
00481                             {
00482                                    ut_free(new);
00483                                    return -1;
00484                             }
00485 
00486                             memset(child, '\0', sizeof *child);
00487 
00488                             child->ukv_key = strdup(strings[c]);
00489                             if (child->ukv_key == NULL)
00490                             {
00491                                    ut_free(new);
00492                                    return -1;
00493                             }
00494                      }
00495                      else
00496                      {
00497                             child->ukv_value = strdup(strings[c]);
00498                             if (child->ukv_value == NULL)
00499                             {
00500                                    ut_free(new);
00501                                    return -1;
00502                             }
00503                      }
00504 
00505                      if (c % 2 == 1)
00506                      {
00507                             if (head == NULL)
00508                             {
00509                                    head = child;
00510                                    tail = child;
00511                             }
00512                             else
00513                             {
00514                                    tail->ukv_next = child;
00515                                    tail = child;
00516                             }
00517                      }
00518               }
00519 
00520               if (c % 2 != 0)
00521               {
00522                      ut_free(new);
00523                      return -1;
00524               }
00525 
00526               new->ukv_value = head;
00527               break;
00528 
00529          default:
00530               /* inconceivable! */
00531               return -1;
00532        }
00533 
00534        new->ukv_type = type;
00535 
00536        if (ut->ut_params == NULL)
00537        {
00538               ut->ut_params = new;
00539               ut->ut_paramstail = new;
00540        }
00541        else
00542        {
00543               ut->ut_paramstail->ukv_next = new;
00544               ut->ut_paramstail = new;
00545        }
00546 
00547        return 0;
00548 }
00549 
00550 /*
00551 **  UT_GENERATE -- generate a URI based on a template and some values
00552 **
00553 **  Parameters:
00554 **     ut -- URITEMP template previously initialized with ut_init()
00555 **     template -- input template
00556 **     out -- output buffer
00557 **     outlen -- bytes available at "out"
00558 **
00559 **  Return value:
00560 **     < 0 -- error (see error codes)
00561 **     otherwise -- length of the generated string; if larger than "outlen",
00562 **                  truncation has occurred
00563 **
00564 **  Notes:
00565 **     "out" is always properly terminated.
00566 **
00567 **     This doesn't support UTF-8 encoding yet.
00568 */
00569 
00570 size_t
00571 ut_generate(URITEMP ut, const char *template, char *out, size_t outlen)
00572 {
00573        char op;
00574        unsigned int maxlen;
00575        int firstout;
00576        int named;
00577        int error = UT_ERROR_OK;
00578        int allow;
00579        int lsep;
00580        size_t alen;
00581        size_t rem;
00582        size_t olen = 0;
00583        size_t vlistlen = 0;
00584        const char *p;
00585        char *q;
00586        char *eb;
00587        char *sep;
00588        char *first;
00589        char *ifemp;
00590        char *v;
00591        char *ctx;
00592        char *vlist;
00593        char *colon;
00594        char *explode;
00595        struct ut_keyvalue *ukv;
00596 
00597        assert(ut != NULL);
00598        assert(template != NULL);
00599        assert(out != NULL);
00600 
00601        rem = outlen - 1;
00602 
00603        memset(out, '\0', outlen);
00604 
00605        q = out;
00606 
00607        for (p = template; *p != '\0'; p++)
00608        {
00609               if (error != 0)
00610               {
00611                      if (rem > 0)
00612                      {
00613                             *q = *p;
00614                             q++;
00615                             rem--;
00616                      }
00617 
00618                      olen++;
00619                      continue;
00620               }
00621 
00622               if (UT_UNRESERVED(*p) || UT_RESERVED(*p))
00623               {
00624                      if (rem > 0)
00625                             *q = *p;
00626                      rem--;
00627                      q++;
00628                      olen++;
00629                      continue;
00630               }
00631               else if (ut_pct_encoded(p))
00632               {
00633                      char c;
00634 
00635                      c = 16 * ut_hexdigit(*(p + 1)) + ut_hexdigit(*(p + 2));
00636 
00637                      *q++ = c;
00638                      olen++;
00639                      rem--;
00640                      p += 2;
00641                      continue;
00642               }
00643               else if (*p == '{')
00644               {
00645                      eb = strchr(p, '}');
00646                      if (eb == NULL)
00647                      {
00648                             *q++ = '{';
00649                             rem--;
00650                             error = UT_ERROR_MALFORMED;
00651                             continue;
00652                      }
00653 
00654                      vlistlen = eb - p;
00655 
00656                      p++;
00657 
00658                      if (*p == '}' || (!UT_OPERATOR(*p) && !UT_VARCHAR(p)))
00659                      {
00660                             *q++ = '{';
00661                             rem--;
00662                             *q++ = *p;
00663                             rem--;
00664                             error = UT_ERROR_MALFORMED;
00665                             continue;
00666                      }
00667 
00668                      op = *p;
00669 
00670                      firstout = 0;
00671 
00672                      switch (op)
00673                      {
00674                        case '.':
00675                             first = ".";
00676                             sep = ".";
00677                             named = 0;
00678                             ifemp = "";
00679                             allow = UT_ALLOW_U;
00680                             p++;
00681                             vlistlen--;
00682                             break;
00683 
00684                        case '/':
00685                             first = "/";
00686                             sep = "/";
00687                             named = 0;
00688                             ifemp = "";
00689                             allow = UT_ALLOW_U;
00690                             p++;
00691                             vlistlen--;
00692                             break;
00693 
00694                        case ';':
00695                             first = ";";
00696                             sep = ";";
00697                             named = 1;
00698                             ifemp = "";
00699                             allow = UT_ALLOW_U;
00700                             p++;
00701                             vlistlen--;
00702                             break;
00703 
00704                        case '?':
00705                             first = "?";
00706                             sep = "&";
00707                             named = 1;
00708                             ifemp = "=";
00709                             allow = UT_ALLOW_U;
00710                             p++;
00711                             vlistlen--;
00712                             break;
00713 
00714                        case '&':
00715                             first = "&";
00716                             sep = "&";
00717                             named = 1;
00718                             ifemp = "=";
00719                             allow = UT_ALLOW_U;
00720                             p++;
00721                             vlistlen--;
00722                             break;
00723 
00724                        case '#':
00725                             first = "#";
00726                             sep = ",";
00727                             named = 0;
00728                             ifemp = "";
00729                             allow = UT_ALLOW_UR;
00730                             p++;
00731                             vlistlen--;
00732                             break;
00733 
00734                        case '+':
00735                             first = "";
00736                             sep = ",";
00737                             named = 0;
00738                             ifemp = "";
00739                             allow = UT_ALLOW_UR;
00740                             p++;
00741                             vlistlen--;
00742                             break;
00743 
00744                        default:
00745                             first = "";
00746                             sep = ",";
00747                             named = 0;
00748                             ifemp = "";
00749                             allow = UT_ALLOW_U;
00750                             break;
00751                      }
00752 
00753                      vlist = strdup(p);
00754                      vlist[vlistlen - 1] = '\0';
00755 
00756                      for (v = strtok_r(vlist, ",", &ctx);
00757                           v != NULL;
00758                           v = strtok_r(NULL, ",", &ctx))
00759                      {
00760                             colon = strchr(v, ':');
00761                             explode = strchr(v, '*');
00762 
00763                             if (colon != NULL)
00764                             {
00765                                    *colon = '\0';
00766                                    maxlen = atoi(colon + 1);
00767                             }
00768                             else
00769                             {
00770                                    maxlen = -1;
00771                             }
00772 
00773                             if (explode != NULL)
00774                                    *explode = '\0';
00775 
00776                             ukv = ut_findkey(ut, v);
00777                             if (ukv == NULL)
00778                                    continue;
00779 
00780                             if (!ut_valid_varname(v))
00781                                    continue;
00782 
00783                             if (firstout == 0)
00784                             {
00785                                    if (first[0] != '\0')
00786                                    {
00787                                           if (rem > 0)
00788                                           {
00789                                                  *q++ = first[0];
00790                                                  rem--;
00791                                           }
00792                                           olen++;
00793                                    }
00794                                    firstout = 1;
00795                             }
00796                             else if (sep[0] != '\0')
00797                             {
00798                                    if (rem > 0)
00799                                    {
00800                                           *q++ = sep[0];
00801                                           rem--;
00802                                    }
00803                                    olen++;
00804                             }
00805 
00806                             switch (ukv->ukv_type)
00807                             {
00808                               case UT_KEYTYPE_STRING:
00809                                    if (named == 1)
00810                                    {
00811                                           char *val;
00812 
00813                                           alen = ut_append(q, rem, allow,
00814                                                            v, -1);
00815                                           q += alen;
00816                                           if (alen > rem)
00817                                                  rem = 0;
00818                                           else
00819                                                  rem -= alen;
00820                                           olen += alen;
00821 
00822                                           val = (char *) ukv->ukv_value;
00823                                           if (val == NULL ||
00824                                               val[0] == '\0')
00825                                           {
00826                                                  if (ifemp[0] != '\0')
00827                                                  {
00828                                                         if (rem > 0)
00829                                                         {
00830                                                                *q++ = ifemp[0];
00831                                                                rem--;
00832                                                         }
00833 
00834                                                         olen++;
00835                                                  }
00836                                           }
00837                                           else
00838                                           {
00839                                                  if (rem > 0)
00840                                                  {
00841                                                         *q++ = '=';
00842                                                         rem--;
00843                                                  }
00844 
00845                                                  olen++;
00846                                           }
00847                                    }
00848 
00849                                    if (colon != NULL)
00850                                    {
00851                                           alen = ut_append(q, rem, allow,
00852                                                            ukv->ukv_value,
00853                                                            maxlen);
00854 
00855                                           q += alen;
00856                                           if (alen > rem)
00857                                                  rem = 0;
00858                                           else
00859                                                  rem -= alen;
00860                                           olen += alen;
00861                                    }
00862                                    else
00863                                    {
00864                                           alen = ut_append(q, rem, allow,
00865                                                            ukv->ukv_value,
00866                                                            -1);
00867 
00868                                           q += alen;
00869                                           if (alen > rem)
00870                                                  rem = 0;
00871                                           else
00872                                                  rem -= alen;
00873                                           olen += alen;
00874                                    }
00875 
00876                                    break;
00877 
00878                               case UT_KEYTYPE_LIST:
00879                                    if (explode == NULL)
00880                                    {
00881                                           struct ut_keyvalue *ikv;
00882 
00883                                           if (named == 1)
00884                                           {
00885                                                  alen = ut_append(q,
00886                                                                   rem,
00887                                                                   allow,
00888                                                                   v,
00889                                                                   -1);
00890 
00891                                                  q += alen;
00892                                                  if (alen > rem)
00893                                                         rem = 0;
00894                                                  else
00895                                                         rem -= alen;
00896                                                  olen += alen;
00897 
00898                                                  if (ukv->ukv_value == NULL)
00899                                                  {
00900                                                         if (ifemp[0] != '\0')
00901                                                         {
00902                                                                if (rem > 0)
00903                                                                {
00904                                                                       *q++ = ifemp[0];
00905                                                                       rem--;
00906                                                                }
00907        
00908                                                                olen++;
00909                                                         }
00910                                                  }
00911                                                  else
00912                                                  {
00913                                                         if (rem > 0)
00914                                                         {
00915                                                                *q++ = '=';
00916                                                                rem--;
00917                                                         }
00918        
00919                                                         olen++;
00920                                                  }
00921                                           }
00922 
00923                                           ikv = ukv->ukv_value;
00924                                           lsep = 0;
00925 
00926                                           while (ikv != NULL)
00927                                           {
00928                                                  if (lsep == 1 &&
00929                                                      ikv != ukv->ukv_value)
00930                                                  {
00931                                                         if (rem > 0)
00932                                                         {
00933                                                                *q++ = ',';
00934                                                                rem--;
00935                                                         }
00936        
00937                                                         olen++;
00938                                                  }
00939 
00940                                                  alen = ut_append(q,
00941                                                                   rem,
00942                                                                   allow,
00943                                                                   ikv->ukv_key,
00944                                                                   -1);
00945 
00946                                                  q += alen;
00947                                                  if (alen > rem)
00948                                                         rem = 0;
00949                                                  else
00950                                                         rem -= alen;
00951                                                  olen += alen;
00952 
00953                                                  ikv = ikv->ukv_next;
00954 
00955                                                  lsep = 1;
00956                                           }
00957                                    }
00958                                    else
00959                                    {
00960                                           struct ut_keyvalue *ikv;
00961 
00962                                           ikv = ukv->ukv_value;
00963                                           lsep = 0;
00964 
00965                                           while (ikv != NULL)
00966                                           {
00967                                                  if (lsep == 1 &&
00968                                                      ikv != ukv->ukv_value &&
00969                                                      sep[0] != '\0')
00970                                                  {
00971                                                         if (rem > 0)
00972                                                         {
00973                                                                *q++ = sep[0];
00974                                                                rem--;
00975                                                         }
00976        
00977                                                         olen++;
00978                                                  }
00979 
00980                                                  alen = ut_append(q,
00981                                                                   rem,
00982                                                                   allow,
00983                                                                   ikv->ukv_key,
00984                                                                   -1);
00985 
00986                                                  q += alen;
00987                                                  if (alen > rem)
00988                                                         rem = 0;
00989                                                  else
00990                                                         rem -= alen;
00991                                                  olen += alen;
00992 
00993                                                  ikv = ikv->ukv_next;
00994 
00995                                                  lsep = 1;
00996                                           }
00997                                    }
00998 
00999                                    break;
01000 
01001                               case UT_KEYTYPE_KEYVALUE:
01002                                    if (explode == NULL)
01003                                    {
01004                                           struct ut_keyvalue *ikv;
01005 
01006                                           if (named == 1)
01007                                           {
01008                                                  char *val;
01009 
01010                                                  alen = ut_append(q,
01011                                                                   rem,
01012                                                                   allow,
01013                                                                   v,
01014                                                                   -1);
01015 
01016                                                  q += alen;
01017                                                  if (alen > rem)
01018                                                         rem = 0;
01019                                                  else
01020                                                         rem -= alen;
01021                                                  olen += alen;
01022 
01023                                                  val = ukv->ukv_value;
01024                                                  if (val == NULL)
01025                                                  {
01026                                                         if (ifemp[0] != '\0')
01027                                                         {
01028                                                                if (rem > 0)
01029                                                                {
01030                                                                       *q++ = ifemp[0];
01031                                                                       rem--;
01032                                                                }
01033        
01034                                                                olen++;
01035                                                         }
01036                                                  }
01037                                                  else
01038                                                  {
01039                                                         if (rem > 0)
01040                                                         {
01041                                                                *q++ = '=';
01042                                                                rem--;
01043                                                         }
01044        
01045                                                         olen++;
01046                                                  }
01047                                           }
01048 
01049                                           ikv = ukv->ukv_value;
01050                                           lsep = 0;
01051 
01052                                           while (ikv != NULL)
01053                                           {
01054                                                  if (lsep == 1 &&
01055                                                      ikv != ukv->ukv_value)
01056                                                  {
01057                                                         if (rem > 0)
01058                                                         {
01059                                                                *q++ = ',';
01060                                                                rem--;
01061                                                         }
01062        
01063                                                         olen++;
01064                                                  }
01065 
01066                                                  alen = ut_append(q,
01067                                                                   rem,
01068                                                                   allow,
01069                                                                   ikv->ukv_key,
01070                                                                   -1);
01071 
01072                                                  q += alen;
01073                                                  if (alen > rem)
01074                                                         rem = 0;
01075                                                  else
01076                                                         rem -= alen;
01077                                                  olen += alen;
01078 
01079                                                  if (rem > 0)
01080                                                  {
01081                                                         *q++ = ',';
01082                                                         rem--;
01083                                                  }
01084 
01085                                                  olen++;
01086 
01087                                                  alen = ut_append(q,
01088                                                                   rem,
01089                                                                   allow,
01090                                                                   ikv->ukv_value,
01091                                                                   -1);
01092 
01093                                                  q += alen;
01094                                                  if (alen > rem)
01095                                                         rem = 0;
01096                                                  else
01097                                                         rem -= alen;
01098                                                  olen += alen;
01099 
01100                                                  lsep = 1;
01101 
01102                                                  ikv = ikv->ukv_next;
01103                                           }
01104                                    }
01105                                    else
01106                                    {
01107                                           struct ut_keyvalue *ikv;
01108 
01109                                           ikv = ukv->ukv_value;
01110                                           lsep = 0;
01111 
01112                                           while (ikv != NULL)
01113                                           {
01114                                                  if (lsep == 1 &&
01115                                                      ikv != ukv->ukv_value &&
01116                                                      sep[0] != '\0')
01117                                                  {
01118                                                         if (rem > 0)
01119                                                         {
01120                                                                *q++ = sep[0];
01121                                                                rem--;
01122                                                         }
01123        
01124                                                         olen++;
01125                                                  }
01126 
01127                                                  alen = ut_append(q,
01128                                                                   rem,
01129                                                                   allow,
01130                                                                   ikv->ukv_key,
01131                                                                   -1);
01132 
01133                                                  q += alen;
01134                                                  if (alen > rem)
01135                                                         rem = 0;
01136                                                  else
01137                                                         rem -= alen;
01138                                                  olen += alen;
01139 
01140                                                  if (rem > 0)
01141                                                  {
01142                                                         *q++ = '=';
01143                                                         rem--;
01144                                                  }
01145 
01146                                                  olen++;
01147 
01148                                                  alen = ut_append(q,
01149                                                                   rem,
01150                                                                   allow,
01151                                                                   ikv->ukv_value,
01152                                                                   -1);
01153 
01154                                                  q += alen;
01155                                                  if (alen > rem)
01156                                                         rem = 0;
01157                                                  else
01158                                                         rem -= alen;
01159                                                  olen += alen;
01160 
01161                                                  lsep = 1;
01162 
01163                                                  ikv = ikv->ukv_next;
01164                                           }
01165                                    }
01166 
01167                                    break;
01168                             }
01169                      }
01170 
01171                      free(vlist);
01172 
01173                      p = eb;
01174               }
01175        }
01176 
01177        if (error != UT_ERROR_OK)
01178               return error;
01179        else
01180               return olen;
01181 }
01182 
01183 #ifdef TEST
01184 /*
01185 **  MAIN -- program mainline
01186 **
01187 **  Parameters:
01188 **     argc, argv -- the usual
01189 **
01190 **  Return value:
01191 **     Exit status.
01192 */
01193 
01194 char *listvals[] = { "red", "green", "blue", NULL };
01195 char *keyvals[] = { "semi", ";", "dot", ".", "comma", ",", NULL };
01196 
01197 int
01198 main(int argc, char **argv)
01199 {
01200        int status;
01201        URITEMP ut;
01202        char outbuf[4096];
01203 
01204        /* Level 1 examples */
01205        ut = ut_init();
01206        assert(ut != NULL);
01207        
01208        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "var", "value");
01209        assert(status == 0);
01210        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "hello", "Hello World!");
01211        assert(status == 0);
01212 
01213        status = ut_generate(ut, "{var}", outbuf, sizeof outbuf);
01214        assert(status > 0);
01215        assert(strcmp(outbuf, "value") == 0);
01216        
01217        status = ut_generate(ut, "{hello}", outbuf, sizeof outbuf);
01218        assert(status > 0);
01219        assert(strcmp(outbuf, "Hello%20World%21") == 0);
01220 
01221        ut_destroy(ut);
01222 
01223        /* Level 2 examples */
01224        ut = ut_init();
01225        assert(ut != NULL);
01226 
01227        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "var", "value");
01228        assert(status == 0);
01229        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "hello", "Hello World!");
01230        assert(status == 0);
01231        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "path", "/foo/bar");
01232        assert(status == 0);
01233 
01234        status = ut_generate(ut, "{+var}", outbuf, sizeof outbuf);
01235        assert(status > 0);
01236        assert(strcmp(outbuf, "value") == 0);
01237        
01238        status = ut_generate(ut, "{+hello}", outbuf, sizeof outbuf);
01239        assert(status > 0);
01240        assert(strcmp(outbuf, "Hello%20World!") == 0);
01241        
01242        status = ut_generate(ut, "{+path}/here", outbuf, sizeof outbuf);
01243        assert(status > 0);
01244        assert(strcmp(outbuf, "/foo/bar/here") == 0);
01245        
01246        status = ut_generate(ut, "here?ref={+path}", outbuf, sizeof outbuf);
01247        assert(status > 0);
01248        assert(strcmp(outbuf, "here?ref=/foo/bar") == 0);
01249        
01250        status = ut_generate(ut, "X{#var}", outbuf, sizeof outbuf);
01251        assert(status > 0);
01252        assert(strcmp(outbuf, "X#value") == 0);
01253        
01254        status = ut_generate(ut, "X{#hello}", outbuf, sizeof outbuf);
01255        assert(status > 0);
01256        assert(strcmp(outbuf, "X#Hello%20World!") == 0);
01257        
01258        ut_destroy(ut);
01259 
01260        /* Level 3 examples */
01261        ut = ut_init();
01262        assert(ut != NULL);
01263 
01264        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "var", "value");
01265        assert(status == 0);
01266        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "hello", "Hello World!");
01267        assert(status == 0);
01268        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "empty", "");
01269        assert(status == 0);
01270        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "path", "/foo/bar");
01271        assert(status == 0);
01272        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "x", "1024");
01273        assert(status == 0);
01274        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "y", "768");
01275        assert(status == 0);
01276 
01277        status = ut_generate(ut, "map?{x,y}", outbuf, sizeof outbuf);
01278        assert(status > 0);
01279        assert(strcmp(outbuf, "map?1024,768") == 0);
01280 
01281        status = ut_generate(ut, "{x,hello,y}", outbuf, sizeof outbuf);
01282        assert(status > 0);
01283        assert(strcmp(outbuf, "1024,Hello%20World%21,768") == 0);
01284 
01285        status = ut_generate(ut, "{+x,hello,y}", outbuf, sizeof outbuf);
01286        assert(status > 0);
01287        assert(strcmp(outbuf, "1024,Hello%20World!,768") == 0);
01288 
01289        status = ut_generate(ut, "{+path,x}/here", outbuf, sizeof outbuf);
01290        assert(status > 0);
01291        assert(strcmp(outbuf, "/foo/bar,1024/here") == 0);
01292 
01293        status = ut_generate(ut, "{#x,hello,y}", outbuf, sizeof outbuf);
01294        assert(status > 0);
01295        assert(strcmp(outbuf, "#1024,Hello%20World!,768") == 0);
01296 
01297        status = ut_generate(ut, "{#path,x}/here", outbuf, sizeof outbuf);
01298        assert(status > 0);
01299        assert(strcmp(outbuf, "#/foo/bar,1024/here") == 0);
01300 
01301        status = ut_generate(ut, "X{.var}", outbuf, sizeof outbuf);
01302        assert(status > 0);
01303        assert(strcmp(outbuf, "X.value") == 0);
01304 
01305        status = ut_generate(ut, "X{.x,y}", outbuf, sizeof outbuf);
01306        assert(status > 0);
01307        assert(strcmp(outbuf, "X.1024.768") == 0);
01308 
01309        status = ut_generate(ut, "{/var}", outbuf, sizeof outbuf);
01310        assert(status > 0);
01311        assert(strcmp(outbuf, "/value") == 0);
01312 
01313        status = ut_generate(ut, "{/var,x}/here", outbuf, sizeof outbuf);
01314        assert(status > 0);
01315        assert(strcmp(outbuf, "/value/1024/here") == 0);
01316 
01317        status = ut_generate(ut, "{;x,y}", outbuf, sizeof outbuf);
01318        assert(status > 0);
01319        assert(strcmp(outbuf, ";x=1024;y=768") == 0);
01320 
01321        status = ut_generate(ut, "{;x,y,empty}", outbuf, sizeof outbuf);
01322        assert(status > 0);
01323        assert(strcmp(outbuf, ";x=1024;y=768;empty") == 0);
01324 
01325        status = ut_generate(ut, "{?x,y}", outbuf, sizeof outbuf);
01326        assert(status > 0);
01327        assert(strcmp(outbuf, "?x=1024&y=768") == 0);
01328 
01329        status = ut_generate(ut, "{?x,y,empty}", outbuf, sizeof outbuf);
01330        assert(status > 0);
01331        assert(strcmp(outbuf, "?x=1024&y=768&empty=") == 0);
01332 
01333        status = ut_generate(ut, "?fixed=yes{&x}", outbuf, sizeof outbuf);
01334        assert(status > 0);
01335        assert(strcmp(outbuf, "?fixed=yes&x=1024") == 0);
01336 
01337        status = ut_generate(ut, "{&x,y,empty}", outbuf, sizeof outbuf);
01338        assert(status > 0);
01339        assert(strcmp(outbuf, "&x=1024&y=768&empty=") == 0);
01340 
01341        ut_destroy(ut);
01342 
01343        /* Level 4 examples */
01344        ut = ut_init();
01345        assert(ut != NULL);
01346 
01347        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "var", "value");
01348        assert(status == 0);
01349        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "hello", "Hello World!");
01350        assert(status == 0);
01351        status = ut_keyvalue(ut, UT_KEYTYPE_STRING, "path", "/foo/bar");
01352        assert(status == 0);
01353        status = ut_keyvalue(ut, UT_KEYTYPE_LIST, "list", listvals);
01354        assert(status == 0);
01355        status = ut_keyvalue(ut, UT_KEYTYPE_KEYVALUE, "keys", keyvals);
01356        assert(status == 0);
01357 
01358        status = ut_generate(ut, "{var:3}", outbuf, sizeof outbuf);
01359        assert(status > 0);
01360        assert(strcmp(outbuf, "val") == 0);
01361 
01362        status = ut_generate(ut, "{var:30}", outbuf, sizeof outbuf);
01363        assert(status > 0);
01364        assert(strcmp(outbuf, "value") == 0);
01365 
01366        status = ut_generate(ut, "{list}", outbuf, sizeof outbuf);
01367        assert(status > 0);
01368        assert(strcmp(outbuf, "red,green,blue") == 0);
01369 
01370        status = ut_generate(ut, "{list*}", outbuf, sizeof outbuf);
01371        assert(status > 0);
01372        assert(strcmp(outbuf, "red,green,blue") == 0);
01373 
01374        status = ut_generate(ut, "{keys}", outbuf, sizeof outbuf);
01375        assert(status > 0);
01376        assert(strcmp(outbuf, "semi,%3B,dot,.,comma,%2C") == 0);
01377 
01378        status = ut_generate(ut, "{keys*}", outbuf, sizeof outbuf);
01379        assert(status > 0);
01380        assert(strcmp(outbuf, "semi=%3B,dot=.,comma=%2C") == 0);
01381 
01382        status = ut_generate(ut, "{+path:6}/here", outbuf, sizeof outbuf);
01383        assert(status > 0);
01384        assert(strcmp(outbuf, "/foo/b/here") == 0);
01385 
01386        status = ut_generate(ut, "{+list}", outbuf, sizeof outbuf);
01387        assert(status > 0);
01388        assert(strcmp(outbuf, "red,green,blue") == 0);
01389 
01390        status = ut_generate(ut, "{+list*}", outbuf, sizeof outbuf);
01391        assert(status > 0);
01392        assert(strcmp(outbuf, "red,green,blue") == 0);
01393 
01394        status = ut_generate(ut, "{+keys}", outbuf, sizeof outbuf);
01395        assert(status > 0);
01396        assert(strcmp(outbuf, "semi,;,dot,.,comma,,") == 0);
01397 
01398        status = ut_generate(ut, "{+keys*}", outbuf, sizeof outbuf);
01399        assert(status > 0);
01400        assert(strcmp(outbuf, "semi=;,dot=.,comma=,") == 0);
01401 
01402        status = ut_generate(ut, "{#path:6*}/here", outbuf, sizeof outbuf);
01403        assert(status > 0);
01404        assert(strcmp(outbuf, "#/foo/b/here") == 0);
01405 
01406        status = ut_generate(ut, "{#list}", outbuf, sizeof outbuf);
01407        assert(status > 0);
01408        assert(strcmp(outbuf, "#red,green,blue") == 0);
01409 
01410        status = ut_generate(ut, "{#list*}", outbuf, sizeof outbuf);
01411        assert(status > 0);
01412        assert(strcmp(outbuf, "#red,green,blue") == 0);
01413 
01414        status = ut_generate(ut, "{#keys}", outbuf, sizeof outbuf);
01415        assert(status > 0);
01416        assert(strcmp(outbuf, "#semi,;,dot,.,comma,,") == 0);
01417 
01418        status = ut_generate(ut, "{#keys*}", outbuf, sizeof outbuf);
01419        assert(status > 0);
01420        assert(strcmp(outbuf, "#semi=;,dot=.,comma=,") == 0);
01421 
01422        status = ut_generate(ut, "X{.var:3}", outbuf, sizeof outbuf);
01423        assert(status > 0);
01424        assert(strcmp(outbuf, "X.val") == 0);
01425 
01426        status = ut_generate(ut, "X{.list}", outbuf, sizeof outbuf);
01427        assert(status > 0);
01428        assert(strcmp(outbuf, "X.red,green,blue") == 0);
01429 
01430        status = ut_generate(ut, "X{.list*}", outbuf, sizeof outbuf);
01431        assert(status > 0);
01432        assert(strcmp(outbuf, "X.red.green.blue") == 0);
01433 
01434        status = ut_generate(ut, "X{.keys}", outbuf, sizeof outbuf);
01435        assert(status > 0);
01436        assert(strcmp(outbuf, "X.semi,%3B,dot,.,comma,%2C") == 0);
01437 
01438        status = ut_generate(ut, "X{.keys*}", outbuf, sizeof outbuf);
01439        assert(status > 0);
01440        assert(strcmp(outbuf, "X.semi=%3B.dot=..comma=%2C") == 0);
01441 
01442        status = ut_generate(ut, "{/var:1,var}", outbuf, sizeof outbuf);
01443        assert(status > 0);
01444        assert(strcmp(outbuf, "/v/value") == 0);
01445 
01446        status = ut_generate(ut, "{/list}", outbuf, sizeof outbuf);
01447        assert(status > 0);
01448        assert(strcmp(outbuf, "/red,green,blue") == 0);
01449 
01450        status = ut_generate(ut, "{/list*}", outbuf, sizeof outbuf);
01451        assert(status > 0);
01452        assert(strcmp(outbuf, "/red/green/blue") == 0);
01453 
01454        status = ut_generate(ut, "{/list*,path:4}", outbuf, sizeof outbuf);
01455        assert(status > 0);
01456        assert(strcmp(outbuf, "/red/green/blue/%2Ffoo") == 0);
01457 
01458        status = ut_generate(ut, "{/keys}", outbuf, sizeof outbuf);
01459        assert(status > 0);
01460        assert(strcmp(outbuf, "/semi,%3B,dot,.,comma,%2C") == 0);
01461 
01462        status = ut_generate(ut, "{/keys*}", outbuf, sizeof outbuf);
01463        assert(status > 0);
01464        assert(strcmp(outbuf, "/semi=%3B/dot=./comma=%2C") == 0);
01465 
01466        status = ut_generate(ut, "{;hello:5}", outbuf, sizeof outbuf);
01467        assert(status > 0);
01468        assert(strcmp(outbuf, ";hello=Hello") == 0);
01469 
01470        status = ut_generate(ut, "{;list}", outbuf, sizeof outbuf);
01471        assert(status > 0);
01472        assert(strcmp(outbuf, ";list=red,green,blue") == 0);
01473 
01474        status = ut_generate(ut, "{;list*}", outbuf, sizeof outbuf);
01475        assert(status > 0);
01476        assert(strcmp(outbuf, ";red;green;blue") == 0);
01477 
01478        status = ut_generate(ut, "{;keys}", outbuf, sizeof outbuf);
01479        assert(status > 0);
01480        assert(strcmp(outbuf, ";keys=semi,%3B,dot,.,comma,%2C") == 0);
01481 
01482        status = ut_generate(ut, "{;keys*}", outbuf, sizeof outbuf);
01483        assert(status > 0);
01484        assert(strcmp(outbuf, ";semi=%3B;dot=.;comma=%2C") == 0);
01485 
01486        status = ut_generate(ut, "{?var:3}", outbuf, sizeof outbuf);
01487        assert(status > 0);
01488        assert(strcmp(outbuf, "?var=val") == 0);
01489 
01490        status = ut_generate(ut, "{?list}", outbuf, sizeof outbuf);
01491        assert(status > 0);
01492        assert(strcmp(outbuf, "?list=red,green,blue") == 0);
01493 
01494        status = ut_generate(ut, "{?list*}", outbuf, sizeof outbuf);
01495        assert(status > 0);
01496        assert(strcmp(outbuf, "?red&green&blue") == 0);
01497 
01498        status = ut_generate(ut, "{?keys}", outbuf, sizeof outbuf);
01499        assert(status > 0);
01500        assert(strcmp(outbuf, "?keys=semi,%3B,dot,.,comma,%2C") == 0);
01501 
01502        status = ut_generate(ut, "{?keys*}", outbuf, sizeof outbuf);
01503        assert(status > 0);
01504        assert(strcmp(outbuf, "?semi=%3B&dot=.&comma=%2C") == 0);
01505 
01506        status = ut_generate(ut, "{&var:3}", outbuf, sizeof outbuf);
01507        assert(status > 0);
01508        assert(strcmp(outbuf, "&var=val") == 0);
01509 
01510        status = ut_generate(ut, "{&list}", outbuf, sizeof outbuf);
01511        assert(status > 0);
01512        assert(strcmp(outbuf, "&list=red,green,blue") == 0);
01513 
01514        status = ut_generate(ut, "{&list*}", outbuf, sizeof outbuf);
01515        assert(status > 0);
01516        assert(strcmp(outbuf, "&red&green&blue") == 0);
01517 
01518        status = ut_generate(ut, "{&keys}", outbuf, sizeof outbuf);
01519        assert(status > 0);
01520        assert(strcmp(outbuf, "&keys=semi,%3B,dot,.,comma,%2C") == 0);
01521 
01522        status = ut_generate(ut, "{&keys*}", outbuf, sizeof outbuf);
01523        assert(status > 0);
01524        assert(strcmp(outbuf, "&semi=%3B&dot=.&comma=%2C") == 0);
01525 
01526        ut_destroy(ut);
01527 
01528        return 0;
01529 }
01530 #endif /* TEST */