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