home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / main / util.c < prev   
Encoding:
C/C++ Source or Header  |  1999-01-08  |  44.7 KB  |  1,905 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59.  * util.c: string utility things
  60.  * 
  61.  * 3/21/93 Rob McCool
  62.  * 1995-96 Many changes by the Apache Group
  63.  * 
  64.  */
  65.  
  66. /* Debugging aid:
  67.  * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
  68.  * #define DEBUG_CFG_LINES  to trace every line read from the config files
  69.  */
  70.  
  71. #include "httpd.h"
  72. #include "http_conf_globals.h"    /* for user_id & group_id */
  73. #include "http_log.h"
  74. #if defined(SUNOS4)
  75. /* stdio.h has been read in ap_config.h already. Add missing prototypes here: */
  76. extern int fgetc(FILE *);
  77. extern char *fgets(char *s, int, FILE*);
  78. extern int fclose(FILE *);
  79. #endif
  80.  
  81. /* A bunch of functions in util.c scan strings looking for certain characters.
  82.  * To make that more efficient we encode a lookup table.  The test_char_table
  83.  * is generated automatically by gen_test_char.c.
  84.  */
  85. #include "test_char.h"
  86.  
  87. /* we assume the folks using this ensure 0 <= c < 256... which means
  88.  * you need a cast to (unsigned char) first, you can't just plug a
  89.  * char in here and get it to work, because if char is signed then it
  90.  * will first be sign extended.
  91.  */
  92. #define TEST_CHAR(c, f)    (test_char_table[(unsigned)(c)] & (f))
  93.  
  94. void ap_util_init(void)
  95. {
  96.     /* nothing to do... previously there was run-time initialization of
  97.      * test_char_table here
  98.      */
  99. }
  100.  
  101.  
  102. API_VAR_EXPORT const char ap_month_snames[12][4] =
  103. {
  104.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  105. };
  106. API_VAR_EXPORT const char ap_day_snames[7][4] =
  107. {
  108.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  109. };
  110.  
  111. API_EXPORT(char *) ap_get_time()
  112. {
  113.     time_t t;
  114.     char *time_string;
  115.  
  116.     t = time(NULL);
  117.     time_string = ctime(&t);
  118.     time_string[strlen(time_string) - 1] = '\0';
  119.     return (time_string);
  120. }
  121.  
  122. API_EXPORT(char *) ap_ht_time(pool *p, time_t t, const char *fmt, int gmt)
  123. {
  124.     char ts[MAX_STRING_LEN];
  125.     char tf[MAX_STRING_LEN];
  126.     struct tm *tms;
  127.  
  128.     tms = (gmt ? gmtime(&t) : localtime(&t));
  129.     if(gmt) {
  130.     /* Convert %Z to "GMT" and %z to "+0000";
  131.      * on hosts that do not have a time zone string in struct tm,
  132.      * strftime must assume its argument is local time.
  133.      */
  134.     const char *f;
  135.     char *strp;
  136.     for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
  137.         ; f++, strp++) {
  138.         if (*f != '%') continue;
  139.         switch (f[1]) {
  140.         case '%':
  141.         *++strp = *++f;
  142.         break;
  143.         case 'Z':
  144.         *strp++ = 'G';
  145.         *strp++ = 'M';
  146.         *strp = 'T';
  147.         f++;
  148.         break;
  149.         case 'z': /* common extension */
  150.         *strp++ = '+';
  151.         *strp++ = '0';
  152.         *strp++ = '0';
  153.         *strp++ = '0';
  154.         *strp = '0';
  155.         f++;
  156.         break;
  157.         }
  158.     }
  159.     *strp = '\0';
  160.     fmt = tf;
  161.     }
  162.  
  163.     /* check return code? */
  164.     strftime(ts, MAX_STRING_LEN, fmt, tms);
  165.     ts[MAX_STRING_LEN - 1] = '\0';
  166.     return ap_pstrdup(p, ts);
  167. }
  168.  
  169. API_EXPORT(char *) ap_gm_timestr_822(pool *p, time_t sec)
  170. {
  171.     struct tm *tms;
  172.  
  173.     tms = gmtime(&sec);
  174.  
  175.     /* RFC date format; as strftime '%a, %d %b %Y %T GMT' */
  176.     return ap_psprintf(p,
  177.         "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[tms->tm_wday],
  178.         tms->tm_mday, ap_month_snames[tms->tm_mon], tms->tm_year + 1900,
  179.         tms->tm_hour, tms->tm_min, tms->tm_sec);
  180. }
  181.  
  182. /* What a pain in the ass. */
  183. #if defined(HAVE_GMTOFF)
  184. API_EXPORT(struct tm *) ap_get_gmtoff(int *tz)
  185. {
  186.     time_t tt = time(NULL);
  187.     struct tm *t;
  188.  
  189.     t = localtime(&tt);
  190.     *tz = (int) (t->tm_gmtoff / 60);
  191.     return t;
  192. }
  193. #else
  194. API_EXPORT(struct tm *) ap_get_gmtoff(int *tz)
  195. {
  196.     time_t tt = time(NULL);
  197.     struct tm gmt;
  198.     struct tm *t;
  199.     int days, hours, minutes;
  200.  
  201.     /* Assume we are never more than 24 hours away. */
  202.     gmt = *gmtime(&tt);        /* remember gmtime/localtime return ptr to static */
  203.     t = localtime(&tt);        /* buffer... so be careful */
  204.     days = t->tm_yday - gmt.tm_yday;
  205.     hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
  206.          + t->tm_hour - gmt.tm_hour);
  207.     minutes = hours * 60 + t->tm_min - gmt.tm_min;
  208.     *tz = minutes;
  209.     return t;
  210. }
  211. #endif
  212.  
  213. /* Roy owes Rob beer. */
  214. /* Rob owes Roy dinner. */
  215.  
  216. /* These legacy comments would make a lot more sense if Roy hadn't
  217.  * replaced the old later_than() routine with util_date.c.
  218.  *
  219.  * Well, okay, they still wouldn't make any sense.
  220.  */
  221.  
  222. /* Match = 0, NoMatch = 1, Abort = -1
  223.  * Based loosely on sections of wildmat.c by Rich Salz
  224.  * Hmmm... shouldn't this really go component by component?
  225.  */
  226. API_EXPORT(int) ap_strcmp_match(const char *str, const char *exp)
  227. {
  228.     int x, y;
  229.  
  230.     for (x = 0, y = 0; exp[y]; ++y, ++x) {
  231.     if ((!str[x]) && (exp[y] != '*'))
  232.         return -1;
  233.     if (exp[y] == '*') {
  234.         while (exp[++y] == '*');
  235.         if (!exp[y])
  236.         return 0;
  237.         while (str[x]) {
  238.         int ret;
  239.         if ((ret = ap_strcmp_match(&str[x++], &exp[y])) != 1)
  240.             return ret;
  241.         }
  242.         return -1;
  243.     }
  244.     else if ((exp[y] != '?') && (str[x] != exp[y]))
  245.         return 1;
  246.     }
  247.     return (str[x] != '\0');
  248. }
  249.  
  250. API_EXPORT(int) ap_strcasecmp_match(const char *str, const char *exp)
  251. {
  252.     int x, y;
  253.  
  254.     for (x = 0, y = 0; exp[y]; ++y, ++x) {
  255.     if ((!str[x]) && (exp[y] != '*'))
  256.         return -1;
  257.     if (exp[y] == '*') {
  258.         while (exp[++y] == '*');
  259.         if (!exp[y])
  260.         return 0;
  261.         while (str[x]) {
  262.         int ret;
  263.         if ((ret = ap_strcasecmp_match(&str[x++], &exp[y])) != 1)
  264.             return ret;
  265.         }
  266.         return -1;
  267.     }
  268.     else if ((exp[y] != '?') && (ap_tolower(str[x]) != ap_tolower(exp[y])))
  269.         return 1;
  270.     }
  271.     return (str[x] != '\0');
  272. }
  273.  
  274. API_EXPORT(int) ap_is_matchexp(const char *str)
  275. {
  276.     register int x;
  277.  
  278.     for (x = 0; str[x]; x++)
  279.     if ((str[x] == '*') || (str[x] == '?'))
  280.         return 1;
  281.     return 0;
  282. }
  283.  
  284. /* This function substitutes for $0-$9, filling in regular expression
  285.  * submatches. Pass it the same nmatch and pmatch arguments that you
  286.  * passed regexec(). pmatch should not be greater than the maximum number
  287.  * of subexpressions - i.e. one more than the re_nsub member of regex_t.
  288.  *
  289.  * input should be the string with the $-expressions, source should be the
  290.  * string that was matched against.
  291.  *
  292.  * It returns the substituted string, or NULL on error.
  293.  *
  294.  * Parts of this code are based on Henry Spencer's regsub(), from his
  295.  * AT&T V8 regexp package.
  296.  */
  297.  
  298. API_EXPORT(char *) ap_pregsub(pool *p, const char *input, const char *source,
  299.                size_t nmatch, regmatch_t pmatch[])
  300. {
  301.     const char *src = input;
  302.     char *dest, *dst;
  303.     char c;
  304.     size_t no;
  305.     int len;
  306.  
  307.     if (!source)
  308.     return NULL;
  309.     if (!nmatch)
  310.     return ap_pstrdup(p, src);
  311.  
  312.     /* First pass, find the size */
  313.  
  314.     len = 0;
  315.  
  316.     while ((c = *src++) != '\0') {
  317.     if (c == '&')
  318.         no = 0;
  319.     else if (c == '$' && ap_isdigit(*src))
  320.         no = *src++ - '0';
  321.     else
  322.         no = 10;
  323.  
  324.     if (no > 9) {        /* Ordinary character. */
  325.         if (c == '\\' && (*src == '$' || *src == '&'))
  326.         c = *src++;
  327.         len++;
  328.     }
  329.     else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
  330.         len += pmatch[no].rm_eo - pmatch[no].rm_so;
  331.     }
  332.  
  333.     }
  334.  
  335.     dest = dst = ap_pcalloc(p, len + 1);
  336.  
  337.     /* Now actually fill in the string */
  338.  
  339.     src = input;
  340.  
  341.     while ((c = *src++) != '\0') {
  342.     if (c == '&')
  343.         no = 0;
  344.     else if (c == '$' && ap_isdigit(*src))
  345.         no = *src++ - '0';
  346.     else
  347.         no = 10;
  348.  
  349.     if (no > 9) {        /* Ordinary character. */
  350.         if (c == '\\' && (*src == '$' || *src == '&'))
  351.         c = *src++;
  352.         *dst++ = c;
  353.     }
  354.     else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
  355.         len = pmatch[no].rm_eo - pmatch[no].rm_so;
  356.         memcpy(dst, source + pmatch[no].rm_so, len);
  357.         dst += len;
  358.     }
  359.  
  360.     }
  361.     *dst = '\0';
  362.  
  363.     return dest;
  364. }
  365.  
  366. /*
  367.  * Parse .. so we don't compromise security
  368.  */
  369. API_EXPORT(void) ap_getparents(char *name)
  370. {
  371.     int l, w;
  372.  
  373.     /* Four paseses, as per RFC 1808 */
  374.     /* a) remove ./ path segments */
  375.  
  376.     for (l = 0, w = 0; name[l] != '\0';) {
  377.     if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/'))
  378.         l += 2;
  379.     else
  380.         name[w++] = name[l++];
  381.     }
  382.  
  383.     /* b) remove trailing . path, segment */
  384.     if (w == 1 && name[0] == '.')
  385.     w--;
  386.     else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
  387.     w--;
  388.     name[w] = '\0';
  389.  
  390.     /* c) remove all xx/../ segments. (including leading ../ and /../) */
  391.     l = 0;
  392.  
  393.     while (name[l] != '\0') {
  394.     if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
  395.         (l == 0 || name[l - 1] == '/')) {
  396.         register int m = l + 3, n;
  397.  
  398.         l = l - 2;
  399.         if (l >= 0) {
  400.         while (l >= 0 && name[l] != '/')
  401.             l--;
  402.         l++;
  403.         }
  404.         else
  405.         l = 0;
  406.         n = l;
  407.         while ((name[n] = name[m]))
  408.         (++n, ++m);
  409.     }
  410.     else
  411.         ++l;
  412.     }
  413.  
  414.     /* d) remove trailing xx/.. segment. */
  415.     if (l == 2 && name[0] == '.' && name[1] == '.')
  416.     name[0] = '\0';
  417.     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') {
  418.     l = l - 4;
  419.     if (l >= 0) {
  420.         while (l >= 0 && name[l] != '/')
  421.         l--;
  422.         l++;
  423.     }
  424.     else
  425.         l = 0;
  426.     name[l] = '\0';
  427.     }
  428. }
  429.  
  430. API_EXPORT(void) ap_no2slash(char *name)
  431. {
  432.     char *d, *s;
  433.  
  434.     s = d = name;
  435.  
  436. #ifdef WIN32
  437.     /* Check for UNC names.  Leave leading two slashes. */
  438.     if (s[0] == '/' && s[1] == '/')
  439.         *d++ = *s++;
  440. #endif
  441.  
  442.     while (*s) {
  443.     if ((*d++ = *s) == '/') {
  444.         do {
  445.         ++s;
  446.         } while (*s == '/');
  447.     }
  448.     else {
  449.         ++s;
  450.     }
  451.     }
  452.     *d = '\0';
  453. }
  454.  
  455.  
  456. /*
  457.  * copy at most n leading directories of s into d
  458.  * d should be at least as large as s plus 1 extra byte
  459.  * assumes n > 0
  460.  * the return value is the ever useful pointer to the trailing \0 of d
  461.  *
  462.  * examples:
  463.  *    /a/b, 1  ==> /
  464.  *    /a/b, 2  ==> /a/
  465.  *    /a/b, 3  ==> /a/b/
  466.  *    /a/b, 4  ==> /a/b/
  467.  */
  468. API_EXPORT(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
  469. {
  470.     for (;;) {
  471.     *d = *s;
  472.     if (*d == '\0') {
  473.         *d = '/';
  474.         break;
  475.     }
  476.     if (*d == '/' && (--n) == 0)
  477.         break;
  478.     ++d;
  479.     ++s;
  480.     }
  481.     *++d = 0;
  482.     return (d);
  483. }
  484.  
  485.  
  486. /*
  487.  * return the parent directory name including trailing / of the file s
  488.  */
  489. API_EXPORT(char *) ap_make_dirstr_parent(pool *p, const char *s)
  490. {
  491.     char *last_slash = strrchr(s, '/');
  492.     char *d;
  493.     int l;
  494.  
  495.     if (last_slash == NULL) {
  496.     /* XXX: well this is really broken if this happens */
  497.     return (ap_pstrdup(p, "/"));
  498.     }
  499.     l = (last_slash - s) + 1;
  500.     d = ap_palloc(p, l + 1);
  501.     memcpy(d, s, l);
  502.     d[l] = 0;
  503.     return (d);
  504. }
  505.  
  506.  
  507. /*
  508.  * This function is deprecated.  Use one of the preceeding two functions
  509.  * which are faster.
  510.  */
  511. API_EXPORT(char *) ap_make_dirstr(pool *p, const char *s, int n)
  512. {
  513.     register int x, f;
  514.     char *res;
  515.  
  516.     for (x = 0, f = 0; s[x]; x++) {
  517.     if (s[x] == '/')
  518.         if ((++f) == n) {
  519.         res = ap_palloc(p, x + 2);
  520.         memcpy(res, s, x);
  521.         res[x] = '/';
  522.         res[x + 1] = '\0';
  523.         return res;
  524.         }
  525.     }
  526.  
  527.     if (s[strlen(s) - 1] == '/')
  528.     return ap_pstrdup(p, s);
  529.     else
  530.     return ap_pstrcat(p, s, "/", NULL);
  531. }
  532.  
  533. API_EXPORT(int) ap_count_dirs(const char *path)
  534. {
  535.     register int x, n;
  536.  
  537.     for (x = 0, n = 0; path[x]; x++)
  538.     if (path[x] == '/')
  539.         n++;
  540.     return n;
  541. }
  542.  
  543.  
  544. API_EXPORT(void) ap_chdir_file(const char *file)
  545. {
  546.     const char *x;
  547.     char buf[HUGE_STRING_LEN];
  548.  
  549.     x = strrchr(file, '/');
  550.     if (x == NULL) {
  551.     chdir(file);
  552.     }
  553.     else if (x - file < sizeof(buf) - 1) {
  554.     memcpy(buf, file, x - file);
  555.     buf[x - file] = '\0';
  556.     chdir(buf);
  557.     }
  558.     /* XXX: well, this is a silly function, no method of reporting an
  559.      * error... ah well. */
  560. }
  561.  
  562. API_EXPORT(char *) ap_getword_nc(pool *atrans, char **line, char stop)
  563. {
  564.     return ap_getword(atrans, (const char **) line, stop);
  565. }
  566.  
  567. API_EXPORT(char *) ap_getword(pool *atrans, const char **line, char stop)
  568. {
  569.     char *pos = strchr(*line, stop);
  570.     char *res;
  571.  
  572.     if (!pos) {
  573.     res = ap_pstrdup(atrans, *line);
  574.     *line += strlen(*line);
  575.     return res;
  576.     }
  577.  
  578.     res = ap_pstrndup(atrans, *line, pos - *line);
  579.  
  580.     while (*pos == stop) {
  581.     ++pos;
  582.     }
  583.  
  584.     *line = pos;
  585.  
  586.     return res;
  587. }
  588.  
  589. API_EXPORT(char *) ap_getword_white_nc(pool *atrans, char **line)
  590. {
  591.     return ap_getword_white(atrans, (const char **) line);
  592. }
  593.  
  594. API_EXPORT(char *) ap_getword_white(pool *atrans, const char **line)
  595. {
  596.     int pos = -1, x;
  597.     char *res;
  598.  
  599.     for (x = 0; (*line)[x]; x++) {
  600.     if (ap_isspace((*line)[x])) {
  601.         pos = x;
  602.         break;
  603.     }
  604.     }
  605.  
  606.     if (pos == -1) {
  607.     res = ap_pstrdup(atrans, *line);
  608.     *line += strlen(*line);
  609.     return res;
  610.     }
  611.  
  612.     res = ap_palloc(atrans, pos + 1);
  613.     ap_cpystrn(res, *line, pos + 1);
  614.  
  615.     while (ap_isspace((*line)[pos]))
  616.     ++pos;
  617.  
  618.     *line += pos;
  619.  
  620.     return res;
  621. }
  622.  
  623. API_EXPORT(char *) ap_getword_nulls_nc(pool *atrans, char **line, char stop)
  624. {
  625.     return ap_getword_nulls(atrans, (const char **) line, stop);
  626. }
  627.  
  628. API_EXPORT(char *) ap_getword_nulls(pool *atrans, const char **line, char stop)
  629. {
  630.     char *pos = strchr(*line, stop);
  631.     char *res;
  632.  
  633.     if (!pos) {
  634.     res = ap_pstrdup(atrans, *line);
  635.     *line += strlen(*line);
  636.     return res;
  637.     }
  638.  
  639.     res = ap_pstrndup(atrans, *line, pos - *line);
  640.  
  641.     ++pos;
  642.  
  643.     *line = pos;
  644.  
  645.     return res;
  646. }
  647.  
  648. /* Get a word, (new) config-file style --- quoted strings and backslashes
  649.  * all honored
  650.  */
  651.  
  652. static char *substring_conf(pool *p, const char *start, int len, char quote)
  653. {
  654.     char *result = ap_palloc(p, len + 2);
  655.     char *resp = result;
  656.     int i;
  657.  
  658.     for (i = 0; i < len; ++i) {
  659.     if (start[i] == '\\' && (start[i + 1] == '\\'
  660.                  || (quote && start[i + 1] == quote)))
  661.         *resp++ = start[++i];
  662.     else
  663.         *resp++ = start[i];
  664.     }
  665.  
  666.     *resp++ = '\0';
  667.     return result;
  668. }
  669.  
  670. API_EXPORT(char *) ap_getword_conf_nc(pool *p, char **line)
  671. {
  672.     return ap_getword_conf(p, (const char **) line);
  673. }
  674.  
  675. API_EXPORT(char *) ap_getword_conf(pool *p, const char **line)
  676. {
  677.     const char *str = *line, *strend;
  678.     char *res;
  679.     char quote;
  680.  
  681.     while (*str && ap_isspace(*str))
  682.     ++str;
  683.  
  684.     if (!*str) {
  685.     *line = str;
  686.     return "";
  687.     }
  688.  
  689.     if ((quote = *str) == '"' || quote == '\'') {
  690.     strend = str + 1;
  691.     while (*strend && *strend != quote) {
  692.         if (*strend == '\\' && strend[1] && strend[1] == quote)
  693.         strend += 2;
  694.         else
  695.         ++strend;
  696.     }
  697.     res = substring_conf(p, str + 1, strend - str - 1, quote);
  698.  
  699.     if (*strend == quote)
  700.         ++strend;
  701.     }
  702.     else {
  703.     strend = str;
  704.     while (*strend && !ap_isspace(*strend))
  705.         ++strend;
  706.  
  707.     res = substring_conf(p, str, strend - str, 0);
  708.     }
  709.  
  710.     while (*strend && ap_isspace(*strend))
  711.     ++strend;
  712.     *line = strend;
  713.     return res;
  714. }
  715.  
  716. API_EXPORT(int) ap_cfg_closefile(configfile_t *cfp)
  717. {
  718. #ifdef DEBUG
  719.     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL, 
  720.         "Done with config file %s", cfp->name);
  721. #endif
  722.     return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
  723. }
  724.  
  725. /* Common structure that holds the file and pool for ap_pcfg_openfile */
  726. typedef struct {
  727.     struct pool *pool;
  728.     FILE *file;
  729. } poolfile_t;
  730.  
  731. static int cfg_close(void *param)
  732. {
  733.     poolfile_t *cfp = (poolfile_t *) param;
  734.     return (ap_pfclose(cfp->pool, cfp->file));
  735. }
  736.  
  737. static int cfg_getch(void *param)
  738. {
  739.     poolfile_t *cfp = (poolfile_t *) param;
  740.     return (fgetc(cfp->file));
  741. }
  742.  
  743. static void *cfg_getstr(void *buf, size_t bufsiz, void *param)
  744. {
  745.     poolfile_t *cfp = (poolfile_t *) param;
  746.     return (fgets(buf, bufsiz, cfp->file));
  747. }
  748.  
  749. /* Open a configfile_t as FILE, return open configfile_t struct pointer */
  750. API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name)
  751. {
  752.     configfile_t *new_cfg;
  753.     poolfile_t *new_pfile;
  754.     FILE *file;
  755.     struct stat stbuf;
  756.     int saved_errno;
  757.  
  758.     if (name == NULL) {
  759.         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
  760.                "Internal error: pcfg_openfile() called with NULL filename");
  761.         return NULL;
  762.     }
  763.  
  764.     if (!ap_os_is_filename_valid(name)) {
  765.         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
  766.                     "Access to config file %s denied: not a valid filename",
  767.                     name);
  768.     errno = EACCES;
  769.         return NULL;
  770.     }
  771.  
  772.     file = ap_pfopen(p, name, "r");
  773. #ifdef DEBUG
  774.     saved_errno = errno;
  775.     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, NULL,
  776.                 "Opening config file %s (%s)",
  777.                 name, (file == NULL) ? strerror(errno) : "successful");
  778.     errno = saved_errno;
  779. #endif
  780.     if (file == NULL)
  781.         return NULL;
  782.  
  783.     if (fstat(fileno(file), &stbuf) == 0 &&
  784.         !S_ISREG(stbuf.st_mode) &&
  785. #if defined(WIN32) || defined(OS2)
  786.         !(strcasecmp(name, "nul") == 0 ||
  787.           (strlen(name) >= 4 &&
  788.            strcasecmp(name + strlen(name) - 4, "/nul") == 0))) {
  789. #else
  790.         strcmp(name, "/dev/null") != 0) {
  791. #endif /* WIN32 || OS2 */
  792.     saved_errno = errno;
  793.         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
  794.                     "Access to file %s denied by server: not a regular file",
  795.                     name);
  796.         ap_pfclose(p, file);
  797.     errno = saved_errno;
  798.         return NULL;
  799.     }
  800.  
  801.     new_cfg = ap_palloc(p, sizeof(*new_cfg));
  802.     new_pfile = ap_palloc(p, sizeof(*new_pfile));
  803.     new_pfile->file = file;
  804.     new_pfile->pool = p;
  805.     new_cfg->param = new_pfile;
  806.     new_cfg->name = ap_pstrdup(p, name);
  807.     new_cfg->getch = (int (*)(void *)) cfg_getch;
  808.     new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr;
  809.     new_cfg->close = (int (*)(void *)) cfg_close;
  810.     new_cfg->line_number = 0;
  811.     return new_cfg;
  812. }
  813.  
  814.  
  815. /* Allocate a configfile_t handle with user defined functions and params */
  816. API_EXPORT(configfile_t *) ap_pcfg_open_custom(pool *p, const char *descr,
  817.     void *param,
  818.     int(*getch)(void *param),
  819.     void *(*getstr) (void *buf, size_t bufsiz, void *param),
  820.     int(*close_func)(void *param))
  821. {
  822.     configfile_t *new_cfg = ap_palloc(p, sizeof(*new_cfg));
  823. #ifdef DEBUG
  824.     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, NULL, "Opening config handler %s", descr);
  825. #endif
  826.     new_cfg->param = param;
  827.     new_cfg->name = descr;
  828.     new_cfg->getch = getch;
  829.     new_cfg->getstr = getstr;
  830.     new_cfg->close = close_func;
  831.     new_cfg->line_number = 0;
  832.     return new_cfg;
  833. }
  834.  
  835.  
  836. /* Read one character from a configfile_t */
  837. API_EXPORT(int) ap_cfg_getc(configfile_t *cfp)
  838. {
  839.     register int ch = cfp->getch(cfp->param);
  840.     if (ch == LF) 
  841.     ++cfp->line_number;
  842.     return ch;
  843. }
  844.  
  845.  
  846. /* Read one line from open configfile_t, strip LF, increase line number */
  847. /* If custom handler does not define a getstr() function, read char by char */
  848. API_EXPORT(int) ap_cfg_getline(char *buf, size_t bufsize, configfile_t *cfp)
  849. {
  850.     /* If a "get string" function is defined, use it */
  851.     if (cfp->getstr != NULL) {
  852.     char *src, *dst;
  853.     char *cp;
  854.     char *cbuf = buf;
  855.     size_t cbufsize = bufsize;
  856.  
  857.     while (1) {
  858.         ++cfp->line_number;
  859.         if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL)
  860.         return 1;
  861.  
  862.         /*
  863.          *  check for line continuation,
  864.          *  i.e. match [^\\]\\[\r]\n only
  865.          */
  866.         cp = cbuf;
  867.         while (cp < cbuf+cbufsize && *cp != '\0')
  868.         cp++;
  869.         if (cp > cbuf && cp[-1] == LF) {
  870.         cp--;
  871.         if (cp > cbuf && cp[-1] == CR)
  872.             cp--;
  873.         if (cp > cbuf && cp[-1] == '\\') {
  874.             cp--;
  875.             if (!(cp > cbuf && cp[-1] == '\\')) {
  876.             /*
  877.              * line continuation requested -
  878.              * then remove backslash and continue
  879.              */
  880.             cbuf = cp;
  881.             cbufsize -= (cp-cbuf);
  882.             continue;
  883.             }
  884.             else {
  885.             /* 
  886.              * no real continuation because escaped -
  887.              * then just remove escape character
  888.              */
  889.             for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++)
  890.                 cp[0] = cp[1];
  891.             }   
  892.         }
  893.         }
  894.         break;
  895.     }
  896.  
  897.     /*
  898.      * Leading and trailing white space is eliminated completely
  899.      */
  900.     src = buf;
  901.     while (ap_isspace(*src))
  902.         ++src;
  903.     /* blast trailing whitespace */
  904.     dst = &src[strlen(src)];
  905.     while (--dst >= src && ap_isspace(*dst))
  906.         *dst = '\0';
  907.         /* Zap leading whitespace by shifting */
  908.         if (src != buf)
  909.         for (dst = buf; (*dst++ = *src++) != '\0'; )
  910.             ;
  911.  
  912. #ifdef DEBUG_CFG_LINES
  913.     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL, "Read config: %s", buf);
  914. #endif
  915.     return 0;
  916.     } else {
  917.     /* No "get string" function defined; read character by character */
  918.     register int c;
  919.     register size_t i = 0;
  920.  
  921.     buf[0] = '\0';
  922.     /* skip leading whitespace */
  923.     do {
  924.         c = cfp->getch(cfp->param);
  925.     } while (c == '\t' || c == ' ');
  926.  
  927.     if (c == EOF)
  928.         return 1;
  929.     
  930.     if(bufsize < 2) {
  931.         /* too small, assume caller is crazy */
  932.         return 1;
  933.     }
  934.  
  935.     while (1) {
  936.         if ((c == '\t') || (c == ' ')) {
  937.         buf[i++] = ' ';
  938.         while ((c == '\t') || (c == ' '))
  939.             c = cfp->getch(cfp->param);
  940.         }
  941.         if (c == CR) {
  942.         /* silently ignore CR (_assume_ that a LF follows) */
  943.         c = cfp->getch(cfp->param);
  944.         }
  945.         if (c == LF) {
  946.         /* increase line number and return on LF */
  947.         ++cfp->line_number;
  948.         }
  949.         if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) {
  950.         /* 
  951.          *  check for line continuation
  952.          */
  953.         if (i > 0 && buf[i-1] == '\\') {
  954.             i--;
  955.             if (!(i > 0 && buf[i-1] == '\\')) {
  956.             /* line is continued */
  957.             c = cfp->getch(cfp->param);
  958.             continue;
  959.             }
  960.             /* else nothing needs be done because
  961.              * then the backslash is escaped and
  962.              * we just strip to a single one
  963.              */
  964.         }
  965.         /* blast trailing whitespace */
  966.         while (i > 0 && ap_isspace(buf[i - 1]))
  967.             --i;
  968.         buf[i] = '\0';
  969. #ifdef DEBUG_CFG_LINES
  970.         ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL, "Read config: %s", buf);
  971. #endif
  972.         return 0;
  973.         }
  974.         buf[i] = c;
  975.         ++i;
  976.         c = cfp->getch(cfp->param);
  977.     }
  978.     }
  979. }
  980.  
  981. /* Retrieve a token, spacing over it and returning a pointer to
  982.  * the first non-white byte afterwards.  Note that these tokens
  983.  * are delimited by semis and commas; and can also be delimited
  984.  * by whitespace at the caller's option.
  985.  */
  986.  
  987. API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_white)
  988. {
  989.     const char *ptr = *accept_line;
  990.     const char *tok_start;
  991.     char *token;
  992.     int tok_len;
  993.  
  994.     /* Find first non-white byte */
  995.  
  996.     while (*ptr && ap_isspace(*ptr))
  997.     ++ptr;
  998.  
  999.     tok_start = ptr;
  1000.  
  1001.     /* find token end, skipping over quoted strings.
  1002.      * (comments are already gone).
  1003.      */
  1004.  
  1005.     while (*ptr && (accept_white || !ap_isspace(*ptr))
  1006.        && *ptr != ';' && *ptr != ',') {
  1007.     if (*ptr++ == '"')
  1008.         while (*ptr)
  1009.         if (*ptr++ == '"')
  1010.             break;
  1011.     }
  1012.  
  1013.     tok_len = ptr - tok_start;
  1014.     token = ap_pstrndup(p, tok_start, tok_len);
  1015.  
  1016.     /* Advance accept_line pointer to the next non-white byte */
  1017.  
  1018.     while (*ptr && ap_isspace(*ptr))
  1019.     ++ptr;
  1020.  
  1021.     *accept_line = ptr;
  1022.     return token;
  1023. }
  1024.  
  1025.  
  1026. /* find http tokens, see the definition of token from RFC2068 */
  1027. API_EXPORT(int) ap_find_token(pool *p, const char *line, const char *tok)
  1028. {
  1029.     const unsigned char *start_token;
  1030.     const unsigned char *s;
  1031.  
  1032.     if (!line)
  1033.     return 0;
  1034.  
  1035.     s = (const unsigned char *)line;
  1036.     for (;;) {
  1037.     /* find start of token, skip all stop characters, note NUL
  1038.      * isn't a token stop, so we don't need to test for it
  1039.      */
  1040.     while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
  1041.         ++s;
  1042.     }
  1043.     if (!*s) {
  1044.         return 0;
  1045.     }
  1046.     start_token = s;
  1047.     /* find end of the token */
  1048.     while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
  1049.         ++s;
  1050.     }
  1051.     if (!strncasecmp((const char *)start_token, (const char *)tok, s - start_token)) {
  1052.         return 1;
  1053.     }
  1054.     if (!*s) {
  1055.         return 0;
  1056.     }
  1057.     }
  1058. }
  1059.  
  1060.  
  1061. API_EXPORT(int) ap_find_last_token(pool *p, const char *line, const char *tok)
  1062. {
  1063.     int llen, tlen, lidx;
  1064.  
  1065.     if (!line)
  1066.     return 0;
  1067.  
  1068.     llen = strlen(line);
  1069.     tlen = strlen(tok);
  1070.     lidx = llen - tlen;
  1071.  
  1072.     if ((lidx < 0) ||
  1073.     ((lidx > 0) && !(ap_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
  1074.     return 0;
  1075.  
  1076.     return (strncasecmp(&line[lidx], tok, tlen) == 0);
  1077. }
  1078.  
  1079. API_EXPORT(char *) ap_escape_shell_cmd(pool *p, const char *str)
  1080. {
  1081.     char *cmd;
  1082.     unsigned char *d;
  1083.     const unsigned char *s;
  1084.  
  1085.     cmd = ap_palloc(p, 2 * strlen(str) + 1);    /* Be safe */
  1086.     d = (unsigned char *)cmd;
  1087.     s = (const unsigned char *)str;
  1088.     for (; *s; ++s) {
  1089.  
  1090. #if defined(OS2) || defined(WIN32)
  1091.     /* Don't allow '&' in parameters under OS/2. */
  1092.     /* This can be used to send commands to the shell. */
  1093.     if (*s == '&') {
  1094.         *d++ = ' ';
  1095.         continue;
  1096.     }
  1097. #endif
  1098.  
  1099.     if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
  1100.         *d++ = '\\';
  1101.     }
  1102.     *d++ = *s;
  1103.     }
  1104.     *d = '\0';
  1105.  
  1106.     return cmd;
  1107. }
  1108.  
  1109. static char x2c(const char *what)
  1110. {
  1111.     register char digit;
  1112.  
  1113. #ifndef CHARSET_EBCDIC
  1114.     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
  1115.     digit *= 16;
  1116.     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
  1117. #else /*CHARSET_EBCDIC*/
  1118.     char xstr[5];
  1119.     xstr[0]='0';
  1120.     xstr[1]='x';
  1121.     xstr[2]=what[0];
  1122.     xstr[3]=what[1];
  1123.     xstr[4]='\0';
  1124.     digit = os_toebcdic[0xFF & strtol(xstr, NULL, 16)];
  1125. #endif /*CHARSET_EBCDIC*/
  1126.     return (digit);
  1127. }
  1128.  
  1129. /*
  1130.  * Unescapes a URL.
  1131.  * Returns 0 on success, non-zero on error
  1132.  * Failure is due to
  1133.  *   bad % escape       returns BAD_REQUEST
  1134.  *
  1135.  *   decoding %00 -> \0
  1136.  *   decoding %2f -> /   (a special character)
  1137.  *                      returns NOT_FOUND
  1138.  */
  1139. API_EXPORT(int) ap_unescape_url(char *url)
  1140. {
  1141.     register int x, y, badesc, badpath;
  1142.  
  1143.     badesc = 0;
  1144.     badpath = 0;
  1145.     for (x = 0, y = 0; url[y]; ++x, ++y) {
  1146.     if (url[y] != '%')
  1147.         url[x] = url[y];
  1148.     else {
  1149.         if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) {
  1150.         badesc = 1;
  1151.         url[x] = '%';
  1152.         }
  1153.         else {
  1154.         url[x] = x2c(&url[y + 1]);
  1155.         y += 2;
  1156.         if (url[x] == '/' || url[x] == '\0')
  1157.             badpath = 1;
  1158.         }
  1159.     }
  1160.     }
  1161.     url[x] = '\0';
  1162.     if (badesc)
  1163.     return BAD_REQUEST;
  1164.     else if (badpath)
  1165.     return NOT_FOUND;
  1166.     else
  1167.     return OK;
  1168. }
  1169.  
  1170. API_EXPORT(char *) ap_construct_server(pool *p, const char *hostname,
  1171.                     unsigned port, const request_rec *r)
  1172. {
  1173.     if (ap_is_default_port(port, r))
  1174.     return ap_pstrdup(p, hostname);
  1175.     else {
  1176.     return ap_psprintf(p, "%s:%u", hostname, port);
  1177.     }
  1178. }
  1179.  
  1180. /* c2x takes an unsigned, and expects the caller has guaranteed that
  1181.  * 0 <= what < 256... which usually means that you have to cast to
  1182.  * unsigned char first, because (unsigned)(char)(x) fist goes through
  1183.  * signed extension to an int before the unsigned cast.
  1184.  *
  1185.  * The reason for this assumption is to assist gcc code generation --
  1186.  * the unsigned char -> unsigned extension is already done earlier in
  1187.  * both uses of this code, so there's no need to waste time doing it
  1188.  * again.
  1189.  */
  1190. static const char c2x_table[] = "0123456789abcdef";
  1191.  
  1192. static ap_inline unsigned char *c2x(unsigned what, unsigned char *where)
  1193. {
  1194.     *where++ = '%';
  1195.     *where++ = c2x_table[what >> 4];
  1196.     *where++ = c2x_table[what & 0xf];
  1197.     return where;
  1198. }
  1199.  
  1200. /*
  1201.  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
  1202.  * routine is (should be) OS independent.
  1203.  *
  1204.  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
  1205.  * cases if a ':' occurs before the first '/' in the URL, the URL should be
  1206.  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
  1207.  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
  1208.  * efficiency reasons, we don't use escape_path_segment(), which is provided for
  1209.  * reference. Again, RFC 1808 is where this stuff is defined.
  1210.  *
  1211.  * If partial is set, os_escape_path() assumes that the path will be appended to
  1212.  * something with a '/' in it (and thus does not prefix "./").
  1213.  */
  1214.  
  1215. API_EXPORT(char *) ap_escape_path_segment(pool *p, const char *segment)
  1216. {
  1217.     char *copy = ap_palloc(p, 3 * strlen(segment) + 1);
  1218.     const unsigned char *s = (const unsigned char *)segment;
  1219.     unsigned char *d = (unsigned char *)copy;
  1220.     unsigned c;
  1221.  
  1222.     while ((c = *s)) {
  1223.     if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
  1224.         d = c2x(c, d);
  1225.     }
  1226.     else {
  1227.         *d++ = c;
  1228.     }
  1229.     ++s;
  1230.     }
  1231.     *d = '\0';
  1232.     return copy;
  1233. }
  1234.  
  1235. API_EXPORT(char *) ap_os_escape_path(pool *p, const char *path, int partial)
  1236. {
  1237.     char *copy = ap_palloc(p, 3 * strlen(path) + 3);
  1238.     const unsigned char *s = (const unsigned char *)path;
  1239.     unsigned char *d = (unsigned char *)copy;
  1240.     unsigned c;
  1241.  
  1242.     if (!partial) {
  1243.     char *colon = strchr(path, ':');
  1244.     char *slash = strchr(path, '/');
  1245.  
  1246.     if (colon && (!slash || colon < slash)) {
  1247.         *d++ = '.';
  1248.         *d++ = '/';
  1249.     }
  1250.     }
  1251.     while ((c = *s)) {
  1252.     if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
  1253.         d = c2x(c, d);
  1254.     }
  1255.     else {
  1256.         *d++ = c;
  1257.     }
  1258.     ++s;
  1259.     }
  1260.     *d = '\0';
  1261.     return copy;
  1262. }
  1263.  
  1264. /* ap_escape_uri is now a macro for os_escape_path */
  1265.  
  1266. API_EXPORT(char *) ap_escape_html(pool *p, const char *s)
  1267. {
  1268.     int i, j;
  1269.     char *x;
  1270.  
  1271.     /* first, count the number of extra characters */
  1272.     for (i = 0, j = 0; s[i] != '\0'; i++)
  1273.     if (s[i] == '<' || s[i] == '>')
  1274.         j += 3;
  1275.     else if (s[i] == '&')
  1276.         j += 4;
  1277.  
  1278.     if (j == 0)
  1279.     return ap_pstrndup(p, s, i);
  1280.  
  1281.     x = ap_palloc(p, i + j + 1);
  1282.     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
  1283.     if (s[i] == '<') {
  1284.         memcpy(&x[j], "<", 4);
  1285.         j += 3;
  1286.     }
  1287.     else if (s[i] == '>') {
  1288.         memcpy(&x[j], ">", 4);
  1289.         j += 3;
  1290.     }
  1291.     else if (s[i] == '&') {
  1292.         memcpy(&x[j], "&", 5);
  1293.         j += 4;
  1294.     }
  1295.     else
  1296.         x[j] = s[i];
  1297.  
  1298.     x[j] = '\0';
  1299.     return x;
  1300. }
  1301.  
  1302. API_EXPORT(int) ap_is_directory(const char *path)
  1303. {
  1304.     struct stat finfo;
  1305.  
  1306.     if (stat(path, &finfo) == -1)
  1307.     return 0;        /* in error condition, just return no */
  1308.  
  1309.     return (S_ISDIR(finfo.st_mode));
  1310. }
  1311.  
  1312. API_EXPORT(char *) ap_make_full_path(pool *a, const char *src1,
  1313.                   const char *src2)
  1314. {
  1315.     register int x;
  1316.  
  1317.     x = strlen(src1);
  1318.     if (x == 0)
  1319.     return ap_pstrcat(a, "/", src2, NULL);
  1320.  
  1321.     if (src1[x - 1] != '/')
  1322.     return ap_pstrcat(a, src1, "/", src2, NULL);
  1323.     else
  1324.     return ap_pstrcat(a, src1, src2, NULL);
  1325. }
  1326.  
  1327. /*
  1328.  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
  1329.  */
  1330. API_EXPORT(int) ap_is_url(const char *u)
  1331. {
  1332.     register int x;
  1333.  
  1334.     for (x = 0; u[x] != ':'; x++) {
  1335.     if ((!u[x]) ||
  1336.         ((!ap_isalpha(u[x])) && (!ap_isdigit(u[x])) &&
  1337.          (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
  1338.         return 0;
  1339.     }
  1340.     }
  1341.  
  1342.     return (x ? 1 : 0);        /* If the first character is ':', it's broken, too */
  1343. }
  1344.  
  1345. API_EXPORT(int) ap_can_exec(const struct stat *finfo)
  1346. {
  1347. #ifdef MULTIPLE_GROUPS
  1348.     int cnt;
  1349. #endif
  1350. #if defined(OS2) || defined(WIN32)
  1351.     /* OS/2 dosen't have Users and Groups */
  1352.     return 1;
  1353. #else
  1354.     if (ap_user_id == finfo->st_uid)
  1355.     if (finfo->st_mode & S_IXUSR)
  1356.         return 1;
  1357.     if (ap_group_id == finfo->st_gid)
  1358.     if (finfo->st_mode & S_IXGRP)
  1359.         return 1;
  1360. #ifdef MULTIPLE_GROUPS
  1361.     for (cnt = 0; cnt < NGROUPS_MAX; cnt++) {
  1362.     if (group_id_list[cnt] == finfo->st_gid)
  1363.         if (finfo->st_mode & S_IXGRP)
  1364.         return 1;
  1365.     }
  1366. #endif
  1367.     return (finfo->st_mode & S_IXOTH);
  1368. #endif
  1369. }
  1370.  
  1371. #ifdef NEED_STRDUP
  1372. char *strdup(const char *str)
  1373. {
  1374.     char *sdup;
  1375.  
  1376.     if (!(sdup = (char *) malloc(strlen(str) + 1)))
  1377.     return NULL;
  1378.     sdup = strcpy(sdup, str);
  1379.  
  1380.     return sdup;
  1381. }
  1382. #endif
  1383.  
  1384. /* The following two routines were donated for SVR4 by Andreas Vogel */
  1385. #ifdef NEED_STRCASECMP
  1386. int strcasecmp(const char *a, const char *b)
  1387. {
  1388.     const char *p = a;
  1389.     const char *q = b;
  1390.     for (p = a, q = b; *p && *q; p++, q++) {
  1391.     int diff = ap_tolower(*p) - ap_tolower(*q);
  1392.     if (diff)
  1393.         return diff;
  1394.     }
  1395.     if (*p)
  1396.     return 1;        /* p was longer than q */
  1397.     if (*q)
  1398.     return -1;        /* p was shorter than q */
  1399.     return 0;            /* Exact match */
  1400. }
  1401.  
  1402. #endif
  1403.  
  1404. #ifdef NEED_STRNCASECMP
  1405. int strncasecmp(const char *a, const char *b, int n)
  1406. {
  1407.     const char *p = a;
  1408.     const char *q = b;
  1409.  
  1410.     for (p = a, q = b; /*NOTHING */ ; p++, q++) {
  1411.     int diff;
  1412.     if (p == a + n)
  1413.         return 0;        /*   Match up to n characters */
  1414.     if (!(*p && *q))
  1415.         return *p - *q;
  1416.     diff = ap_tolower(*p) - ap_tolower(*q);
  1417.     if (diff)
  1418.         return diff;
  1419.     }
  1420.     /*NOTREACHED */
  1421. }
  1422. #endif
  1423.  
  1424. /* The following routine was donated for UTS21 by dwd@bell-labs.com */
  1425. #ifdef NEED_STRSTR
  1426. char *strstr(char *s1, char *s2)
  1427. {
  1428.     char *p1, *p2;
  1429.     if (*s2 == '\0') {
  1430.     /* an empty s2 */
  1431.         return(s1);
  1432.     }
  1433.     while((s1 = strchr(s1, *s2)) != NULL) {
  1434.     /* found first character of s2, see if the rest matches */
  1435.         p1 = s1;
  1436.         p2 = s2;
  1437.         while (*++p1 == *++p2) {
  1438.             if (*p1 == '\0') {
  1439.                 /* both strings ended together */
  1440.                 return(s1);
  1441.             }
  1442.         }
  1443.         if (*p2 == '\0') {
  1444.             /* second string ended, a match */
  1445.             break;
  1446.         }
  1447.     /* didn't find a match here, try starting at next character in s1 */
  1448.         s1++;
  1449.     }
  1450.     return(s1);
  1451. }
  1452. #endif
  1453.  
  1454. #ifdef NEED_INITGROUPS
  1455. int initgroups(const char *name, gid_t basegid)
  1456. {
  1457. #if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF)
  1458. /* QNX, MPE and BeOS do not appear to support supplementary groups. */
  1459.     return 0;
  1460. #else /* ndef QNX */
  1461.     gid_t groups[NGROUPS_MAX];
  1462.     struct group *g;
  1463.     int index = 0;
  1464.  
  1465.     setgrent();
  1466.  
  1467.     groups[index++] = basegid;
  1468.  
  1469.     while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
  1470.     if (g->gr_gid != basegid) {
  1471.         char **names;
  1472.  
  1473.         for (names = g->gr_mem; *names != NULL; ++names)
  1474.         if (!strcmp(*names, name))
  1475.             groups[index++] = g->gr_gid;
  1476.     }
  1477.  
  1478.     endgrent();
  1479.  
  1480.     return setgroups(index, groups);
  1481. #endif /* def QNX */
  1482. }
  1483. #endif /* def NEED_INITGROUPS */
  1484.  
  1485. #ifdef NEED_WAITPID
  1486. /* From ikluft@amdahl.com
  1487.  * this is not ideal but it works for SVR3 variants
  1488.  * Modified by dwd@bell-labs.com to call wait3 instead of wait because
  1489.  *   apache started to use the WNOHANG option.
  1490.  */
  1491. int waitpid(pid_t pid, int *statusp, int options)
  1492. {
  1493.     int tmp_pid;
  1494.     if (kill(pid, 0) == -1) {
  1495.     errno = ECHILD;
  1496.     return -1;
  1497.     }
  1498.     while (((tmp_pid = wait3(statusp, options, 0)) != pid) &&
  1499.         (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
  1500.     ;
  1501.     return tmp_pid;
  1502. }
  1503. #endif
  1504.  
  1505. API_EXPORT(int) ap_ind(const char *s, char c)
  1506. {
  1507.     register int x;
  1508.  
  1509.     for (x = 0; s[x]; x++)
  1510.     if (s[x] == c)
  1511.         return x;
  1512.  
  1513.     return -1;
  1514. }
  1515.  
  1516. API_EXPORT(int) ap_rind(const char *s, char c)
  1517. {
  1518.     register int x;
  1519.  
  1520.     for (x = strlen(s) - 1; x != -1; x--)
  1521.     if (s[x] == c)
  1522.         return x;
  1523.  
  1524.     return -1;
  1525. }
  1526.  
  1527. API_EXPORT(void) ap_str_tolower(char *str)
  1528. {
  1529.     while (*str) {
  1530.     *str = ap_tolower(*str);
  1531.     ++str;
  1532.     }
  1533. }
  1534.  
  1535. API_EXPORT(uid_t) ap_uname2id(const char *name)
  1536. {
  1537. #ifdef WIN32
  1538.     return (1);
  1539. #else
  1540.     struct passwd *ent;
  1541.  
  1542.     if (name[0] == '#')
  1543.     return (atoi(&name[1]));
  1544.  
  1545.     if (!(ent = getpwnam(name))) {
  1546.     fprintf(stderr, "%s: bad user name %s\n", ap_server_argv0, name);
  1547.     exit(1);
  1548.     }
  1549.     return (ent->pw_uid);
  1550. #endif
  1551. }
  1552.  
  1553. API_EXPORT(gid_t) ap_gname2id(const char *name)
  1554. {
  1555. #ifdef WIN32
  1556.     return (1);
  1557. #else
  1558.     struct group *ent;
  1559.  
  1560.     if (name[0] == '#')
  1561.     return (atoi(&name[1]));
  1562.  
  1563.     if (!(ent = getgrnam(name))) {
  1564.     fprintf(stderr, "%s: bad group name %s\n", ap_server_argv0, name);
  1565.     exit(1);
  1566.     }
  1567.     return (ent->gr_gid);
  1568. #endif
  1569. }
  1570.  
  1571.  
  1572. /*
  1573.  * Parses a host of the form <address>[:port]
  1574.  * :port is permitted if 'port' is not NULL
  1575.  */
  1576. unsigned long ap_get_virthost_addr(char *w, unsigned short *ports)
  1577. {
  1578.     struct hostent *hep;
  1579.     unsigned long my_addr;
  1580.     char *p;
  1581.  
  1582.     p = strchr(w, ':');
  1583.     if (ports != NULL) {
  1584.     *ports = 0;
  1585.     if (p != NULL && strcmp(p + 1, "*") != 0)
  1586.         *ports = atoi(p + 1);
  1587.     }
  1588.  
  1589.     if (p != NULL)
  1590.     *p = '\0';
  1591.     if (strcmp(w, "*") == 0) {
  1592.     if (p != NULL)
  1593.         *p = ':';
  1594.     return htonl(INADDR_ANY);
  1595.     }
  1596.  
  1597.     my_addr = ap_inet_addr((char *)w);
  1598.     if (my_addr != INADDR_NONE) {
  1599.     if (p != NULL)
  1600.         *p = ':';
  1601.     return my_addr;
  1602.     }
  1603.  
  1604.     hep = gethostbyname(w);
  1605.  
  1606.     if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
  1607.     fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
  1608.     exit(1);
  1609.     }
  1610.  
  1611.     if (hep->h_addr_list[1]) {
  1612.     fprintf(stderr, "Host %s has multiple addresses ---\n", w);
  1613.     fprintf(stderr, "you must choose one explicitly for use as\n");
  1614.     fprintf(stderr, "a virtual host.  Exiting!!!\n");
  1615.     exit(1);
  1616.     }
  1617.  
  1618.     if (p != NULL)
  1619.     *p = ':';
  1620.  
  1621.     return ((struct in_addr *) (hep->h_addr))->s_addr;
  1622. }
  1623.  
  1624.  
  1625. static char *find_fqdn(pool *a, struct hostent *p)
  1626. {
  1627.     int x;
  1628.  
  1629.     if (!strchr(p->h_name, '.')) {
  1630.     for (x = 0; p->h_aliases[x]; ++x) {
  1631.         if (strchr(p->h_aliases[x], '.') &&
  1632.         (!strncasecmp(p->h_aliases[x], p->h_name, strlen(p->h_name))))
  1633.         return ap_pstrdup(a, p->h_aliases[x]);
  1634.     }
  1635.     return NULL;
  1636.     }
  1637.     return ap_pstrdup(a, (void *) p->h_name);
  1638. }
  1639.  
  1640. char *ap_get_local_host(pool *a)
  1641. {
  1642. #ifndef MAXHOSTNAMELEN
  1643. #define MAXHOSTNAMELEN 256
  1644. #endif
  1645.     char str[MAXHOSTNAMELEN + 1];
  1646.     char *server_hostname;
  1647.     struct hostent *p;
  1648.  
  1649.     if (gethostname(str, sizeof(str) - 1) != 0) {
  1650.     perror("Unable to gethostname");
  1651.     exit(1);
  1652.     }
  1653.     str[MAXHOSTNAMELEN] = '\0';
  1654.     if ((!(p = gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) {
  1655.     fprintf(stderr, "%s: cannot determine local host name.\n",
  1656.         ap_server_argv0);
  1657.     fprintf(stderr, "Use the ServerName directive to set it manually.\n");
  1658.     exit(1);
  1659.     }
  1660.  
  1661.     return server_hostname;
  1662. }
  1663.  
  1664. /* aaaack but it's fast and const should make it shared text page. */
  1665. static const unsigned char pr2six[256] =
  1666. {
  1667.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1668.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1669.     64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54,
  1670.     55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3,
  1671.     4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
  1672.     22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32,
  1673.     33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
  1674.     50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1675.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1676.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1677.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1678.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1679.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1680.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1681.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  1682. };
  1683.  
  1684. API_EXPORT(char *) ap_uudecode(pool *p, const char *bufcoded)
  1685. {
  1686.     int nbytesdecoded;
  1687.     register const unsigned char *bufin;
  1688.     register char *bufplain;
  1689.     register unsigned char *bufout;
  1690.     register int nprbytes;
  1691.  
  1692.     /* Strip leading whitespace. */
  1693.  
  1694.     while (*bufcoded == ' ' || *bufcoded == '\t')
  1695.     bufcoded++;
  1696.  
  1697.     /* Figure out how many characters are in the input buffer.
  1698.      * Allocate this many from the per-transaction pool for the result.
  1699.      */
  1700. #ifndef CHARSET_EBCDIC
  1701.     bufin = (const unsigned char *) bufcoded;
  1702.     while (pr2six[*(bufin++)] <= 63);
  1703.     nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  1704.     nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  1705.  
  1706.     bufplain = ap_palloc(p, nbytesdecoded + 1);
  1707.     bufout = (unsigned char *) bufplain;
  1708.  
  1709.     bufin = (const unsigned char *) bufcoded;
  1710.  
  1711.     while (nprbytes > 0) {
  1712.     *(bufout++) =
  1713.         (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  1714.     *(bufout++) =
  1715.         (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  1716.     *(bufout++) =
  1717.         (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  1718.     bufin += 4;
  1719.     nprbytes -= 4;
  1720.     }
  1721.  
  1722.     if (nprbytes & 03) {
  1723.     if (pr2six[bufin[-2]] > 63)
  1724.         nbytesdecoded -= 2;
  1725.     else
  1726.         nbytesdecoded -= 1;
  1727.     }
  1728.     bufplain[nbytesdecoded] = '\0';
  1729. #else /*CHARSET_EBCDIC*/
  1730.     bufin = (const unsigned char *) bufcoded;
  1731.     while (pr2six[os_toascii[(unsigned char)*(bufin++)]] <= 63);
  1732.     nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  1733.     nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  1734.  
  1735.     bufplain = ap_palloc(p, nbytesdecoded + 1);
  1736.     bufout = (unsigned char *) bufplain;
  1737.  
  1738.     bufin = (const unsigned char *) bufcoded;
  1739.  
  1740.     while (nprbytes > 0) {
  1741.     *(bufout++) = os_toebcdic[
  1742.         (unsigned char) (pr2six[os_toascii[*bufin]] << 2 | pr2six[os_toascii[bufin[1]]] >> 4)];
  1743.     *(bufout++) = os_toebcdic[
  1744.         (unsigned char) (pr2six[os_toascii[bufin[1]]] << 4 | pr2six[os_toascii[bufin[2]]] >> 2)];
  1745.     *(bufout++) = os_toebcdic[
  1746.         (unsigned char) (pr2six[os_toascii[bufin[2]]] << 6 | pr2six[os_toascii[bufin[3]]])];
  1747.     bufin += 4;
  1748.     nprbytes -= 4;
  1749.     }
  1750.  
  1751.     if (nprbytes & 03) {
  1752.     if (pr2six[os_toascii[bufin[-2]]] > 63)
  1753.         nbytesdecoded -= 2;
  1754.     else
  1755.         nbytesdecoded -= 1;
  1756.     }
  1757.     bufplain[nbytesdecoded] = '\0';
  1758. #endif /*CHARSET_EBCDIC*/
  1759.     return bufplain;
  1760. }
  1761.  
  1762. static const char basis_64[] = 
  1763. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 
  1764.  
  1765. API_EXPORT(char *) ap_uuencode(pool *a, char *string) 
  1766.     int i, len = strlen(string); 
  1767.     char *p; 
  1768.     char *encoded = (char *) ap_pcalloc(a, (len+2) / 3 * 4); 
  1769.  
  1770.     p = encoded; 
  1771.     for (i = 0; i < len; i += 3) { 
  1772.         *p++ = basis_64[string[i] >> 2]; 
  1773.         *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; 
  1774.         *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; 
  1775.         *p++ = basis_64[string[i + 2] & 0x3F]; 
  1776.     } 
  1777.     *p-- = '\0'; 
  1778.     *p-- = '='; 
  1779.     *p-- = '='; 
  1780.     return encoded; 
  1781.  
  1782. #ifdef OS2
  1783. void os2pathname(char *path)
  1784. {
  1785.     char newpath[MAX_STRING_LEN];
  1786.     int loop;
  1787.     int offset;
  1788.  
  1789.     offset = 0;
  1790.     for (loop = 0; loop < (strlen(path) + 1) && loop < sizeof(newpath) - 1; loop++) {
  1791.     if (path[loop] == '/') {
  1792.         newpath[offset] = '\\';
  1793.         /*
  1794.            offset = offset + 1;
  1795.            newpath[offset] = '\\';
  1796.          */
  1797.     }
  1798.     else
  1799.         newpath[offset] = path[loop];
  1800.     offset = offset + 1;
  1801.     };
  1802.     /* Debugging code */
  1803.     /* fprintf(stderr, "%s \n", newpath); */
  1804.  
  1805.     strcpy(path, newpath);
  1806. };
  1807. #endif
  1808.  
  1809.  
  1810. #ifdef NEED_STRERROR
  1811. char *
  1812.      strerror(int err)
  1813. {
  1814.  
  1815.     char *p;
  1816.     extern char *const sys_errlist[];
  1817.  
  1818.     p = sys_errlist[err];
  1819.     return (p);
  1820. }
  1821. #endif
  1822.  
  1823. #if defined(NEED_DIFFTIME)
  1824. double difftime(time_t time1, time_t time0)
  1825. {
  1826.     return (time1 - time0);
  1827. }
  1828. #endif
  1829.  
  1830. /* we want to downcase the type/subtype for comparison purposes
  1831.  * but nothing else because ;parameter=foo values are case sensitive.
  1832.  * XXX: in truth we want to downcase parameter names... but really,
  1833.  * apache has never handled parameters and such correctly.  You
  1834.  * also need to compress spaces and such to be able to compare
  1835.  * properly. -djg
  1836.  */
  1837. API_EXPORT(void) ap_content_type_tolower(char *str)
  1838. {
  1839.     char *semi;
  1840.  
  1841.     semi = strchr(str, ';');
  1842.     if (semi) {
  1843.     *semi = '\0';
  1844.     }
  1845.     while (*str) {
  1846.     *str = ap_tolower(*str);
  1847.     ++str;
  1848.     }
  1849.     if (semi) {
  1850.     *semi = ';';
  1851.     }
  1852. }
  1853.  
  1854. /*
  1855.  * Given a string, replace any bare " with \" .
  1856.  */
  1857. API_EXPORT(char *) ap_escape_quotes (pool *p, const char *instring)
  1858. {
  1859.     int newlen = 0;
  1860.     const char *inchr = instring;
  1861.     char *outchr, *outstring;
  1862.  
  1863.     /*
  1864.      * Look through the input string, jogging the length of the output
  1865.      * string up by an extra byte each time we find an unescaped ".
  1866.      */
  1867.     while (*inchr != '\0') {
  1868.     newlen++;
  1869.         if (*inchr == '"') {
  1870.         newlen++;
  1871.     }
  1872.     /*
  1873.      * If we find a slosh, and it's not the last byte in the string,
  1874.      * it's escaping something - advance past both bytes.
  1875.      */
  1876.     if ((*inchr == '\\') && (inchr[1] != '\0')) {
  1877.         inchr++;
  1878.     }
  1879.     inchr++;
  1880.     }
  1881.     outstring = ap_palloc(p, newlen + 1);
  1882.     inchr = instring;
  1883.     outchr = outstring;
  1884.     /*
  1885.      * Now copy the input string to the output string, inserting a slosh
  1886.      * in front of every " that doesn't already have one.
  1887.      */
  1888.     while (*inchr != '\0') {
  1889.     if ((*inchr == '\\') && (inchr[1] != '\0')) {
  1890.         *outchr++ = *inchr++;
  1891.         *outchr++ = *inchr++;
  1892.     }
  1893.     if (*inchr == '"') {
  1894.         *outchr++ = '\\';
  1895.     }
  1896.     if (*inchr != '\0') {
  1897.         *outchr++ = *inchr++;
  1898.     }
  1899.     }
  1900.     *outchr = '\0';
  1901.     return outstring;
  1902. }
  1903.