1 /***************************************
2   $Header: /home/amb/CVS/wwwoffle/src/configmisc.c,v 1.33 2007-05-27 11:24:14 amb Exp $
3 
4   WWWOFFLE - World Wide Web Offline Explorer - Version 2.9c.
5   Configuration file data management functions.
6   ******************/ /******************
7   Written by Andrew M. Bishop
8 
9   This file Copyright 1997,98,99,2000,01,02,03,04,05,06 Andrew M. Bishop
10   It may be distributed under the GNU Public License, version 2, or
11   any higher version.  See section COPYING of the GNU Public license
12   for conditions under which this file may be redistributed.
13   ***************************************/
14 
15 
16 #include "autoconfig.h"
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 
23 #include <pwd.h>
24 #include <grp.h>
25 
26 #include "misc.h"
27 #include "errors.h"
28 #include "configpriv.h"
29 
30 
31 /* Local functions */
32 
33 static /*@null@*/ char* sprintf_key_or_value(ConfigType type,KeyOrValue key_or_val);
34 static /*@null@*/ char* sprintf_url_spec(const UrlSpec *urlspec);
35 static /*@null@*/ char *strstrn(const char *phaystack, const char *pneedle, size_t n, int nocase);
36 
37 
38 /*+ The backup version of the config file. +*/
39 static ConfigFile BackupConfig;
40 
41 
42 /*++++++++++++++++++++++++++++++++++++++
43   Set the configuration file default values.
44   ++++++++++++++++++++++++++++++++++++++*/
45 
DefaultConfigFile(void)46 void DefaultConfigFile(void)
47 {
48  int s,i;
49  char *errmsg;
50 
51  for(s=0;s<CurrentConfig.nsections;s++)
52     for(i=0;i<CurrentConfig.sections[s]->nitemdefs;i++)
53        if(CurrentConfig.sections[s]->itemdefs[i].def_val)
54          {
55           ConfigItem *item=CurrentConfig.sections[s]->itemdefs[i].item;
56 
57           *item=(ConfigItem)malloc(sizeof(struct _ConfigItem));
58           (*item)->itemdef=&CurrentConfig.sections[s]->itemdefs[i];
59           (*item)->nentries=0;
60           (*item)->url=NULL;
61           (*item)->key=NULL;
62           (*item)->val=NULL;
63           (*item)->def_val=(KeyOrValue*)malloc(sizeof(KeyOrValue));
64 
65           if(CurrentConfig.sections[s]->itemdefs[i].key_type!=Fixed)
66              PrintMessage(Fatal,"Configuration file error at %s:%d",__FILE__,__LINE__);
67 
68           if((errmsg=ParseKeyOrValue(CurrentConfig.sections[s]->itemdefs[i].def_val,CurrentConfig.sections[s]->itemdefs[i].val_type,(*item)->def_val)))
69              PrintMessage(Fatal,"Configuration file error at %s:%d; %s",__FILE__,__LINE__,errmsg);
70          }
71 }
72 
73 
74 /*++++++++++++++++++++++++++++++++++++++
75   Save the old values in case the re-read of the file fails.
76   ++++++++++++++++++++++++++++++++++++++*/
77 
CreateBackupConfigFile(void)78 void CreateBackupConfigFile(void)
79 {
80  int s,i;
81 
82  /* Create a backup of all of the sections. */
83 
84  BackupConfig=CurrentConfig;
85  BackupConfig.sections=(ConfigSection**)malloc(CurrentConfig.nsections*sizeof(ConfigSection*));
86 
87  for(s=0;s<CurrentConfig.nsections;s++)
88    {
89     BackupConfig.sections[s]=(ConfigSection*)malloc(sizeof(ConfigSection));
90     *BackupConfig.sections[s]=*CurrentConfig.sections[s];
91     BackupConfig.sections[s]->itemdefs=(ConfigItemDef*)malloc(CurrentConfig.sections[s]->nitemdefs*sizeof(ConfigItemDef));
92 
93     for(i=0;i<CurrentConfig.sections[s]->nitemdefs;i++)
94       {
95        BackupConfig.sections[s]->itemdefs[i]=CurrentConfig.sections[s]->itemdefs[i];
96        BackupConfig.sections[s]->itemdefs[i].item=(ConfigItem*)malloc(sizeof(ConfigItem));
97 
98        *BackupConfig.sections[s]->itemdefs[i].item=*CurrentConfig.sections[s]->itemdefs[i].item;
99        *CurrentConfig.sections[s]->itemdefs[i].item=NULL;
100       }
101    }
102 
103  /* Restore the default values */
104 
105  DefaultConfigFile();
106 }
107 
108 
109 /*++++++++++++++++++++++++++++++++++++++
110   Restore the old values if the re-read of the file failed.
111   ++++++++++++++++++++++++++++++++++++++*/
112 
RestoreBackupConfigFile(void)113 void RestoreBackupConfigFile(void)
114 {
115  int s,i;
116 
117  /* Restore all of the sections. */
118 
119  for(s=0;s<CurrentConfig.nsections;s++)
120    {
121     for(i=0;i<CurrentConfig.sections[s]->nitemdefs;i++)
122       {
123        FreeConfigItem(*CurrentConfig.sections[s]->itemdefs[i].item);
124 
125        *CurrentConfig.sections[s]->itemdefs[i].item=*BackupConfig.sections[s]->itemdefs[i].item;
126 
127        free(BackupConfig.sections[s]->itemdefs[i].item);
128       }
129 
130     free(BackupConfig.sections[s]->itemdefs);
131     free(BackupConfig.sections[s]);
132    }
133 
134  free(BackupConfig.sections);
135 }
136 
137 
138 /*++++++++++++++++++++++++++++++++++++++
139   Remove the old values if the re-read of the file succeeded.
140 
141   int restore_startup Set to true if the StartUp section is to be restored.
142   ++++++++++++++++++++++++++++++++++++++*/
143 
PurgeBackupConfigFile(int restore_startup)144 void PurgeBackupConfigFile(int restore_startup)
145 {
146  int s,i;
147 
148  /* Purge all of the sections and restore StartUp if needed. */
149 
150  for(s=0;s<BackupConfig.nsections;s++)
151    {
152     for(i=0;i<BackupConfig.sections[s]->nitemdefs;i++)
153       {
154        if(s==0 && restore_startup)
155          {
156           FreeConfigItem(*CurrentConfig.sections[s]->itemdefs[i].item);
157 
158           *CurrentConfig.sections[s]->itemdefs[i].item=*BackupConfig.sections[s]->itemdefs[i].item;
159          }
160        else
161           FreeConfigItem(*BackupConfig.sections[s]->itemdefs[i].item);
162 
163        free(BackupConfig.sections[s]->itemdefs[i].item);
164       }
165 
166     free(BackupConfig.sections[s]->itemdefs);
167     free(BackupConfig.sections[s]);
168    }
169 
170  free(BackupConfig.sections);
171 }
172 
173 
174 /*++++++++++++++++++++++++++++++++++++++
175   Remove the values in the config file.
176   ++++++++++++++++++++++++++++++++++++++*/
177 
PurgeConfigFile(void)178 void PurgeConfigFile(void)
179 {
180  int s,i;
181 
182  /* Purge all of the sections. */
183 
184  for(s=0;s<CurrentConfig.nsections;s++)
185    {
186     for(i=0;i<CurrentConfig.sections[s]->nitemdefs;i++)
187       {
188        FreeConfigItem(*CurrentConfig.sections[s]->itemdefs[i].item);
189       }
190    }
191 }
192 
193 
194 /*++++++++++++++++++++++++++++++++++++++
195   Free a ConfigItem list.
196 
197   ConfigItem item The item to free.
198   ++++++++++++++++++++++++++++++++++++++*/
199 
FreeConfigItem(ConfigItem item)200 void FreeConfigItem(ConfigItem item)
201 {
202  int i;
203 
204  if(!item)
205     return;
206 
207  for(i=0;i<item->nentries;i++)
208    {
209     if(item->url)
210        FreeKeyOrValue((KeyOrValue*)&item->url[i],UrlSpecification);
211 
212     FreeKeyOrValue(&item->key[i],item->itemdef->key_type);
213 
214     if(item->val)
215        FreeKeyOrValue(&item->val[i],item->itemdef->val_type);
216    }
217 
218  if(item->nentries)
219    {
220     if(item->url)
221        free(item->url);
222     free(item->key);
223     if(item->val)
224        free(item->val);
225    }
226 
227  if(item->def_val)
228    {
229     FreeKeyOrValue(item->def_val,item->itemdef->val_type);
230     free(item->def_val);
231    }
232 
233  free(item);
234 }
235 
236 
237 /*++++++++++++++++++++++++++++++++++++++
238   Free a Key or Value.
239 
240   KeyOrValue *keyval The key or value to free.
241 
242   ConfigType type The type of key or value.
243   ++++++++++++++++++++++++++++++++++++++*/
244 
FreeKeyOrValue(KeyOrValue * keyval,ConfigType type)245 void FreeKeyOrValue(KeyOrValue *keyval,ConfigType type)
246 {
247  switch(type)
248    {
249     /* None or Fixed */
250 
251    case Fixed:
252    case None:
253     break;
254 
255     /* Integer */
256 
257    case CfgMaxServers:
258    case CfgMaxFetchServers:
259    case CfgLogLevel:
260    case Boolean:
261    case PortNumber:
262    case AgeDays:
263    case TimeSecs:
264    case CacheSize:
265    case FileSize:
266    case Percentage:
267    case UserId:
268    case GroupId:
269    case FileMode:
270     break;
271 
272     /* String */
273 
274    case String:
275    case PathName:
276    case FileExt:
277    case MIMEType:
278    case Host:
279    case HostOrNone:
280    case HostAndPort:
281    case HostAndPortOrNone:
282    case HostWild:
283    case HostAndPortWild:
284    case UserPass:
285    case Url:
286    case UrlWild:
287     if(keyval->string)
288        free(keyval->string);
289     break;
290 
291    case UrlSpecification:
292     if(keyval->urlspec)
293        free(keyval->urlspec);
294    }
295 }
296 
297 
298 /*++++++++++++++++++++++++++++++++++++++
299   Check if a protocol, host, path and args match a URL-SPECIFICATION in the config file.
300 
301   int MatchUrlSpecification Return the matching length if true else 0.
302 
303   const UrlSpec *spec The URL-SPECIFICATION.
304 
305   const char *proto The protocol.
306 
307   const char *host The host.
308 
309   int port The port number (or -1).
310 
311   const char *path The path.
312 
313   const char *args The arguments.
314   ++++++++++++++++++++++++++++++++++++++*/
315 
MatchUrlSpecification(const UrlSpec * spec,const char * proto,const char * host,int port,const char * path,const char * args)316 int MatchUrlSpecification(const UrlSpec *spec,const char *proto,const char *host,int port,const char *path,const char *args)
317 {
318  int match=0;
319 
320  if((!spec->proto || !strcmp(UrlSpecProto(spec),proto)) &&
321     (!spec->host || WildcardMatch(host,UrlSpecHost(spec),0)) &&
322     (spec->port==-1 || (port==-1 && spec->port==0) || (port!=-1 && port==spec->port)) &&
323     (!spec->path || WildcardMatch(path,UrlSpecPath(spec),spec->nocase) ||
324      ((!strncmp(UrlSpecPath(spec),"/*/",(size_t)3) && WildcardMatch(path,UrlSpecPath(spec)+2,spec->nocase)))) &&
325     (!spec->args || (args && WildcardMatch(args,UrlSpecArgs(spec),spec->nocase)) || (!args && *UrlSpecArgs(spec)==0)))
326    {
327     match=(spec->proto?strlen(UrlSpecProto(spec)):0)+
328           (spec->host ?strlen(UrlSpecHost(spec) ):0)+
329           (spec->path ?strlen(UrlSpecPath(spec) ):0)+
330           (spec->args ?strlen(UrlSpecArgs(spec) ):0)+1;
331    }
332 
333  return(match);
334 }
335 
336 
337 /*++++++++++++++++++++++++++++++++++++++
338   Do a match using a wildcard specified with '*' in it.
339 
340   int WildcardMatch returns 1 if there is a match.
341 
342   const char *string The fixed string that is being matched.
343 
344   const char *pattern The pattern to match against.
345 
346   int nocase A flag that if set to 1 ignores the case of the string.
347 
348   By Paul A. Rombouts <p.a.rombouts@home.nl>, handles more than two '*' using simpler algorithm than previously.
349 
350   See also the strstrn() function at the bottom of this file.
351   ++++++++++++++++++++++++++++++++++++++*/
352 
WildcardMatch(const char * string,const char * pattern,int nocase)353 int WildcardMatch(const char *string,const char *pattern,int nocase)
354 {
355  size_t len_beg;
356  const char *midstr, *endstr;
357  const char *pattstr, *starp=strchr(pattern,'*');
358 
359  if(!starp)
360     return(( nocase && !strcasecmp(string,pattern)) ||
361            (!nocase && !strcmp(string,pattern)));
362 
363  len_beg=starp-pattern;
364  if(( nocase && strncasecmp(string,pattern,len_beg)) ||
365     (!nocase && strncmp(string,pattern,len_beg)))
366     return(0);
367 
368  midstr=string+len_beg;
369 
370  while(pattstr=starp+1,starp=strchr(pattstr,'*'))
371    {
372     size_t len_patt=starp-pattstr;
373     char *match=strstrn(midstr,pattstr,len_patt,nocase);
374 
375     if(!match)
376        return(0);
377 
378     midstr=match+len_patt;
379    }
380 
381  endstr=midstr+strlen(midstr)-strlen(pattstr);
382 
383  if(midstr>endstr)
384     return(0);
385 
386  return(( nocase && !strcasecmp(endstr,pattstr)) ||
387         (!nocase && !strcmp(endstr,pattstr)));
388 }
389 
390 
391 /*++++++++++++++++++++++++++++++++++++++
392   Return the string that represents the Configuration type.
393 
394   char *ConfigTypeString Returns a static string.
395 
396   ConfigType type The configuration type.
397   ++++++++++++++++++++++++++++++++++++++*/
398 
ConfigTypeString(ConfigType type)399 char *ConfigTypeString(ConfigType type)
400 {
401  switch(type)
402    {
403    case Fixed:
404     return "Fixed";              /* key */
405    case None:
406     return "None";                         /* val */
407    case CfgMaxServers:
408     return "CfgMaxServers";                /* val */
409    case CfgMaxFetchServers:
410     return "CfgMaxFetchServers";           /* val */
411    case CfgLogLevel:
412     return "CfgLogLevel";                  /* val */
413    case Boolean:
414     return "Boolean";                      /* val */
415    case PortNumber:
416     return "PortNumber";                   /* val */
417    case AgeDays:
418     return "AgeDays";                      /* val */
419    case TimeSecs:
420     return "TimeSecs";                     /* val */
421    case CacheSize:
422     return "CacheSize";                    /* val */
423    case FileSize:
424     return "FileSize";                     /* val */
425    case Percentage:
426     return "Percentage";                   /* val */
427    case UserId:
428     return "UserId";                       /* val */
429    case GroupId:
430     return "GroupId";                      /* val */
431    case String:
432     return "String";             /* key */ /* val */
433    case PathName:
434     return "PathName";                     /* val */
435    case FileExt:
436     return "FileExt";            /* key */ /* val */
437    case FileMode:
438     return "FileMode";                     /* val */
439    case MIMEType:
440     return "MIMEType";                     /* val */
441    case Host:
442     return "Host";               /* key */
443    case HostOrNone:
444     return "HostOrNone";                   /* val */
445    case HostAndPort:
446     return "HostAndPort";
447    case HostAndPortOrNone:
448     return "HostAndPortOrNone";            /* val */
449    case HostWild:
450     return "HostWild";                     /* val */
451    case HostAndPortWild:
452     return "HostAndPortWild";              /* val */
453    case UserPass:
454     return "UserPass";           /* key */
455    case Url:
456     return "Url";                          /* val */
457    case UrlWild:
458     return "UrlWild";                      /* val */
459    case UrlSpecification:
460     return "UrlSpecification";   /* key */ /* val */
461    }
462 
463  /*@notreached@*/
464 
465  return("??Unknown??");
466 }
467 
468 
469 /*++++++++++++++++++++++++++++++++++++++
470   Convert a Configuration entry into a canonical printable string.
471 
472   char *ConfigEntryString Returns a malloced string.
473 
474   ConfigItem item The configuration item.
475 
476   int which Which particular entry in the ConfigItem to print.
477   ++++++++++++++++++++++++++++++++++++++*/
478 
ConfigEntryString(ConfigItem item,int which)479 char *ConfigEntryString(ConfigItem item,int which)
480 {
481  char *url=NULL,*key=NULL,*val=NULL;
482  char *string;
483 
484  /* Get the sub-strings */
485 
486  ConfigEntryStrings(item,which,&url,&key,&val);
487 
488  /* Create the string */
489 
490  string=MakeConfigEntryString(item->itemdef,url,key,val);
491 
492  /* Send the results back */
493 
494  if(url) free(url);
495  if(key) free(key);
496  if(val) free(val);
497 
498  return(string);
499 }
500 
501 
502 /*++++++++++++++++++++++++++++++++++++++
503   Convert a Configuration entry into a canonical printable string.
504 
505   ConfigItem item The configuration item.
506 
507   int which Which particular entry in the ConfigItem to print.
508 
509   char **url Returns the URL string.
510 
511   char **key Returns the key string.
512 
513   char **val Returns the value string.
514   ++++++++++++++++++++++++++++++++++++++*/
515 
ConfigEntryStrings(ConfigItem item,int which,char ** url,char ** key,char ** val)516 void ConfigEntryStrings(ConfigItem item,int which,char **url,char **key,char **val)
517 {
518  /* Handle the URL */
519 
520  if(item->url && item->url[which])
521     *url=sprintf_url_spec(item->url[which]);
522  else
523     *url=NULL;
524 
525  /* Handle the key */
526 
527  *key=sprintf_key_or_value(item->itemdef->key_type,item->key[which]);
528 
529  /* Handle the value */
530 
531  if(item->itemdef->val_type!=None)
532     *val=sprintf_key_or_value(item->itemdef->val_type,item->val[which]);
533  else
534     *val=NULL;
535 }
536 
537 
538 /*++++++++++++++++++++++++++++++++++++++
539   Make a Configuration entry string from supplied arguments.
540 
541   char *MakeConfigEntryString Returns a malloced string.
542 
543   const ConfigItemDef *itemdef The configuration item definition.
544 
545   const char *url Specifies the URL string.
546 
547   const char *key Specifies the key string.
548 
549   const char *val Specifies the val string.
550   ++++++++++++++++++++++++++++++++++++++*/
551 
MakeConfigEntryString(const ConfigItemDef * itemdef,const char * url,const char * key,const char * val)552 char *MakeConfigEntryString(const ConfigItemDef *itemdef,const char *url,const char *key,const char *val)
553 {
554  int strpos=0;
555  char *string=(char*)calloc((size_t)8,sizeof(char));
556 
557  /* Handle the URL */
558 
559  if(url)
560    {
561     string=(char*)realloc((void*)string,strpos+1+3+strlen(url));
562     sprintf(string+strpos,"<%s> ",url);
563     strpos+=3+strlen(url);
564    }
565 
566  /* Handle the key */
567 
568  if(key)
569    {
570     string=(char*)realloc((void*)string,strpos+1+strlen(key));
571     sprintf(string+strpos,"%s",key);
572     strpos+=strlen(key);
573    }
574 
575  /* Handle the value */
576 
577  if(itemdef->val_type!=None)
578    {
579     string=(char*)realloc((void*)string,strpos+1+3);
580     sprintf(string+strpos," = ");
581     strpos+=3;
582 
583     if(val)
584       {
585        string=(char*)realloc((void*)string,strpos+1+strlen(val));
586        sprintf(string+strpos,"%s",val);
587        strpos+=strlen(val);
588       }
589    }
590 
591  /* Send the result back */
592 
593  return(string);
594 }
595 
596 
597 /*++++++++++++++++++++++++++++++++++++++
598   Convert a KeyOrValue type into a string.
599 
600   char* sprintf_key_or_value Return the newly malloced string.
601 
602   ConfigType type The type of the KeyOrValue.
603 
604   KeyOrValue key_or_val The KeyOrValue.
605   ++++++++++++++++++++++++++++++++++++++*/
606 
sprintf_key_or_value(ConfigType type,KeyOrValue key_or_val)607 static char* sprintf_key_or_value(ConfigType type,KeyOrValue key_or_val)
608 {
609  char *string=NULL;
610 
611  switch(type)
612    {
613     /* None or Fixed */
614 
615    case Fixed:
616     string=(char*)malloc(1+strlen(key_or_val.string));
617     strcpy(string,key_or_val.string);
618     break;
619 
620    case None:
621     break;
622 
623     /* Integer */
624 
625    case Boolean:
626     string=(char*)malloc((size_t)4);
627     strcpy(string,key_or_val.integer?"yes":"no");
628     break;
629 
630    case CfgMaxServers:
631    case CfgMaxFetchServers:
632    case PortNumber:
633    case CacheSize:
634    case FileSize:
635    case Percentage:
636     string=(char*)malloc((size_t)(MAX_INT_STR+1));
637     sprintf(string,"%d",key_or_val.integer);
638     break;
639 
640    case CfgLogLevel:
641     string=(char*)malloc((size_t)17);
642     if(key_or_val.integer==Debug)
643        strcpy(string,"debug");
644     if(key_or_val.integer==Inform)
645        strcpy(string,"info");
646     if(key_or_val.integer==Important)
647        strcpy(string,"important");
648     if(key_or_val.integer==Warning)
649        strcpy(string,"debug");
650     if(key_or_val.integer==Fatal)
651        strcpy(string,"fatal");
652     break;
653 
654    case UserId:
655     {
656      struct passwd *pwd=getpwuid((uid_t)key_or_val.integer);
657      if(pwd)
658        {
659         string=(char*)malloc(1+strlen(pwd->pw_name));
660         strcpy(string,pwd->pw_name);
661        }
662      else
663        {
664         string=(char*)malloc((size_t)(MAX_INT_STR+1));
665         sprintf(string,"%d",key_or_val.integer);
666        }
667     }
668    break;
669 
670    case GroupId:
671     {
672      struct group *grp=getgrgid((gid_t)key_or_val.integer);
673      if(grp)
674        {
675         string=(char*)malloc(1+strlen(grp->gr_name));
676         strcpy(string,grp->gr_name);
677        }
678      else
679        {
680         string=(char*)malloc((size_t)(MAX_INT_STR+1));
681         sprintf(string,"%d",key_or_val.integer);
682        }
683     }
684    break;
685 
686    case FileMode:
687     string=(char*)malloc((size_t)(1+MAX_INT_STR+1));
688     sprintf(string,"0%o",(unsigned)key_or_val.integer);
689     break;
690 
691    case AgeDays:
692     {
693      int weeks,months,years,days=key_or_val.integer;
694 
695      string=(char*)malloc((size_t)(MAX_INT_STR+1+1));
696 
697      years=days/365;
698      if(years*365==days)
699         sprintf(string,"%dy",years);
700      else
701        {
702         months=days/30;
703         if(months*30==days)
704            sprintf(string,"%dm",months);
705         else
706           {
707            weeks=days/7;
708            if(weeks*7==days)
709               sprintf(string,"%dw",weeks);
710            else
711               sprintf(string,"%d",days);
712           }
713        }
714     }
715    break;
716 
717    case TimeSecs:
718     {
719      int weeks,days,hours,minutes,seconds=key_or_val.integer;
720 
721      string=(char*)malloc((size_t)(MAX_INT_STR+1+1));
722 
723      weeks=seconds/(3600*24*7);
724      if(weeks*(3600*24*7)==seconds)
725         sprintf(string,"%dw",weeks);
726      else
727        {
728         days=seconds/(3600*24);
729         if(days*(3600*24)==seconds)
730            sprintf(string,"%dd",days);
731         else
732           {
733            hours=seconds/(3600);
734            if(hours*(3600)==seconds)
735               sprintf(string,"%dh",hours);
736            else
737              {
738               minutes=seconds/(60);
739               if(minutes*(60)==seconds)
740                  sprintf(string,"%dm",minutes);
741               else
742                  sprintf(string,"%d",seconds);
743              }
744           }
745        }
746     }
747     break;
748 
749     /* String */
750 
751    case String:
752    case PathName:
753    case FileExt:
754    case MIMEType:
755    case Host:
756    case HostOrNone:
757    case HostAndPort:
758    case HostAndPortOrNone:
759    case HostWild:
760    case HostAndPortWild:
761    case UserPass:
762    case Url:
763    case UrlWild:
764     if(key_or_val.string)
765       {
766        string=(char*)malloc(1+strlen(key_or_val.string));
767        strcpy(string,key_or_val.string);
768       }
769     else
770       {
771        string=(char*)malloc((size_t)1);
772        *string=0;
773       }
774     break;
775 
776     /* Url Specification */
777 
778    case UrlSpecification:
779     string=sprintf_url_spec(key_or_val.urlspec);
780    }
781 
782  return(string);
783 }
784 
785 
786 /*++++++++++++++++++++++++++++++++++++++
787   Convert a URL-SPECIFICATION into a string.
788 
789   char* sprintf_url_spec Return the new string.
790 
791   const UrlSpec *urlspec The URL-SPECIFICATION to convert.
792   ++++++++++++++++++++++++++++++++++++++*/
793 
sprintf_url_spec(const UrlSpec * urlspec)794 static char* sprintf_url_spec(const UrlSpec *urlspec)
795 {
796  char *string=NULL;
797  int strpos=0;
798  size_t newlen;
799 
800  if(!urlspec)
801     return(NULL);
802 
803  newlen=1+8;
804  if(HasUrlSpecProto(urlspec)) newlen+=strlen(UrlSpecProto(urlspec));
805  if(HasUrlSpecHost (urlspec)) newlen+=strlen(UrlSpecHost (urlspec));
806  if(UrlSpecPort(urlspec)>0)   newlen+=MAX_INT_STR;
807  if(HasUrlSpecPath (urlspec)) newlen+=strlen(UrlSpecPath (urlspec));
808  if(HasUrlSpecArgs (urlspec)) newlen+=strlen(UrlSpecArgs (urlspec));
809 
810  string=(char*)malloc(newlen);
811  *string=0;
812 
813  if(urlspec->negated)
814    {
815     sprintf(string+strpos,"%s","!");
816     strpos+=strlen(string+strpos);
817    }
818 
819  if(urlspec->nocase)
820    {
821     sprintf(string+strpos,"%s","~");
822     strpos+=strlen(string+strpos);
823    }
824 
825  sprintf(string+strpos,"%s://",HasUrlSpecProto(urlspec)?UrlSpecProto(urlspec):"*");
826  strpos+=strlen(string+strpos);
827 
828  sprintf(string+strpos,"%s",HasUrlSpecHost(urlspec)?UrlSpecHost(urlspec):"*");
829  strpos+=strlen(string+strpos);
830 
831  if(UrlSpecPort(urlspec)==0)
832     sprintf(string+strpos,":");
833  else if(UrlSpecPort(urlspec)!=-1)
834     sprintf(string+strpos,":%d",UrlSpecPort(urlspec));
835  strpos+=strlen(string+strpos);
836 
837  sprintf(string+strpos,"%s",HasUrlSpecPath(urlspec)?UrlSpecPath(urlspec):"/*");
838  strpos+=strlen(string+strpos);
839 
840  if(HasUrlSpecArgs(urlspec))
841    {
842     sprintf(string+strpos,"?%s",*UrlSpecArgs(urlspec)?UrlSpecArgs(urlspec):"*");
843     strpos+=strlen(string+strpos);
844    }
845 
846  return(string);
847 }
848 
849 
850 
851 /* Return the offset of one string within another.
852    Copyright (C) 1994, 1996, 1997, 2000 Free Software Foundation, Inc.
853 
854    The GNU C Library is free software; you can redistribute it and/or
855    modify it under the terms of the GNU Lesser General Public
856    License as published by the Free Software Foundation; either
857    version 2.1 of the License, or (at your option) any later version.
858 
859    The GNU C Library is distributed in the hope that it will be useful,
860    but WITHOUT ANY WARRANTY; without even the implied warranty of
861    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
862    Lesser General Public License for more details.
863 
864    You should have received a copy of the GNU Lesser General Public
865    License along with the GNU C Library; if not, write to the Free
866    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
867    02111-1307 USA.  */
868 
869 /*
870  * My personal strstr() implementation that beats most other algorithms.
871  * Until someone tells me otherwise, I assume that this is the
872  * fastest implementation of strstr() in C.
873  * I deliberately chose not to comment it.  You should have at least
874  * as much fun trying to understand it, as I had to write it :-).
875  *
876  * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de	*/
877 
878 /* strstrn() is a variation of strstr() that only tries to find
879    the first n characters of "needle" in "haystack".
880    If strlen(needle) happens to be less than n, strstrn() behaves
881    exactly like strstr().
882    Modifications made by Paul Rombouts <p.a.rombouts@home.nl>.
883 */
884 
885 /* Added a parameter "nocase" to select case insensitive test (value 1)
886    or case sensitive (0).
887    Modification by Marc Boucher.
888 */
889 
890 typedef unsigned chartype;
891 
strstrn(const char * phaystack,const char * pneedle,size_t n,int nocase)892 static char *strstrn(const char *phaystack, const char *pneedle, size_t n, int nocase)
893 {
894   register const unsigned char *haystack, *needle;
895   register chartype b, c;
896   const unsigned char *needle_end;
897 
898   char *lowhaystack=NULL;
899   char *lowneedle=NULL;
900 
901   if (nocase) {
902      int i;
903      lowhaystack=malloc(strlen(phaystack)+1);
904      lowneedle=malloc(strlen(pneedle)+1);
905 
906      for(i=0;phaystack[i];i++) { lowhaystack[i]=tolower(phaystack[i]); }
907      lowhaystack[i]=0;
908      for(i=0;pneedle[i];i++) { lowneedle[i]=tolower(pneedle[i]); }
909      lowneedle[i]=0;
910 
911      phaystack=lowhaystack;
912      pneedle=lowneedle;
913      }
914 
915   haystack = (const unsigned char *) phaystack;
916   needle = (const unsigned char *) pneedle;
917   needle_end = needle+n;
918 
919   if (needle != needle_end && (b = *needle) != '\0' )
920     {
921       haystack--;                               /* possible ANSI violation */
922       do
923         {
924           c = *++haystack;
925           if (c == '\0')
926             goto ret0;
927         }
928       while (c != b);
929 
930       if (++needle == needle_end || (c = *needle) == '\0')
931         goto foundneedle;
932       ++needle;
933       goto jin;
934 
935       for (;;)
936         {
937           register chartype a;
938           register const unsigned char *rhaystack, *rneedle;
939 
940           do
941             {
942               a = *++haystack;
943               if (a == '\0')
944                 goto ret0;
945               if (a == b)
946                 break;
947               a = *++haystack;
948               if (a == '\0')
949                 goto ret0;
950 shloop:
951               ;
952             }
953           while (a != b);
954 
955 jin:      a = *++haystack;
956           if (a == '\0')
957             goto ret0;
958 
959           if (a != c)
960             goto shloop;
961 
962           rhaystack = haystack-- + 1;
963           if(needle == needle_end) goto foundneedle;
964           rneedle = needle;
965           a = *rneedle;
966 
967           if (*rhaystack == a)
968             do
969               {
970                 if (a == '\0')
971                   goto foundneedle;
972                 ++rhaystack;
973                 if(++needle == needle_end) goto foundneedle;
974                 a = *needle;
975                 if (*rhaystack != a)
976                   break;
977                 if (a == '\0')
978                   goto foundneedle;
979                 ++rhaystack;
980                 if(++needle == needle_end) goto foundneedle;
981                 a = *needle;
982               }
983             while (*rhaystack == a);
984 
985           needle = rneedle;             /* took the register-poor approach */
986 
987           if (a == '\0')
988             break;
989         }
990     }
991 foundneedle:
992   if (nocase) {
993      if (lowhaystack) free(lowhaystack);
994      if (lowneedle) free(lowneedle);
995      }
996   return (char*) haystack;
997 ret0:
998   if (nocase) {
999      if (lowhaystack) free(lowhaystack);
1000      if (lowneedle) free(lowneedle);
1001      }
1002   return 0;
1003 }
1004