f4137fc4aceec4e016e34c11e1f356b35311cab0
[platform/upstream/nss.git] / nss / cmd / modutil / install-ds.c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "install-ds.h"
6 #include <prmem.h>
7 #include <plstr.h>
8 #include <prprf.h>
9 #include <string.h>
10
11 #define PORT_Strcasecmp PL_strcasecmp
12
13 #define MODULE_FILE_STRING "ModuleFile"
14 #define MODULE_NAME_STRING "ModuleName"
15 #define MECH_FLAGS_STRING "DefaultMechanismFlags"
16 #define CIPHER_FLAGS_STRING "DefaultCipherFlags"
17 #define FILES_STRING "Files"
18 #define FORWARD_COMPATIBLE_STRING "ForwardCompatible"
19 #define PLATFORMS_STRING "Platforms"
20 #define RELATIVE_DIR_STRING "RelativePath"
21 #define ABSOLUTE_DIR_STRING "AbsolutePath"
22 #define FILE_PERMISSIONS_STRING "FilePermissions"
23 #define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform"
24 #define EXECUTABLE_STRING "Executable"
25
26 #define DEFAULT_PERMISSIONS 0777
27
28 #define PLATFORM_SEPARATOR_CHAR ':'
29
30 /* Error codes */
31 enum {
32         BOGUS_RELATIVE_DIR=0,
33         BOGUS_ABSOLUTE_DIR,
34         BOGUS_FILE_PERMISSIONS,
35         NO_RELATIVE_DIR,
36         NO_ABSOLUTE_DIR,
37         EMPTY_PLATFORM_STRING,
38         BOGUS_PLATFORM_STRING,
39         REPEAT_MODULE_FILE,
40         REPEAT_MODULE_NAME,
41         BOGUS_MODULE_FILE,
42         BOGUS_MODULE_NAME,
43         REPEAT_MECH,
44         BOGUS_MECH_FLAGS,
45         REPEAT_CIPHER,
46         BOGUS_CIPHER_FLAGS,
47         REPEAT_FILES,
48         REPEAT_EQUIV,
49         BOGUS_EQUIV,
50         EQUIV_TOO_MUCH_INFO,
51         NO_FILES,
52         NO_MODULE_FILE,
53         NO_MODULE_NAME,
54         NO_PLATFORMS,
55         EQUIV_LOOP,
56         UNKNOWN_MODULE_FILE
57 };
58
59 /* Indexed by the above error codes */
60 static const char *errString[] = {
61         "%s: Invalid relative directory",
62         "%s: Invalid absolute directory",
63         "%s: Invalid file permissions",
64         "%s: No relative directory specified",
65         "%s: No absolute directory specified",
66         "Empty string given for platform name",
67         "%s: invalid platform string",
68         "More than one ModuleFile entry given for platform %s",
69         "More than one ModuleName entry given for platform %s",
70         "Invalid ModuleFile specification for platform %s",
71         "Invalid ModuleName specification for platform %s",
72         "More than one DefaultMechanismFlags entry given for platform %s",
73         "Invalid DefaultMechanismFlags specification for platform %s",
74         "More than one DefaultCipherFlags entry given for platform %s",
75         "Invalid DefaultCipherFlags entry given for platform %s",
76         "More than one Files entry given for platform %s",
77         "More than one EquivalentPlatform entry given for platform %s",
78         "Invalid EquivalentPlatform specification for platform %s",
79         "Module %s uses an EquivalentPlatform but also specifies its own"
80                 " information",
81         "No Files specification in module %s",
82         "No ModuleFile specification in module %s",
83         "No ModuleName specification in module %s",
84         "No Platforms specification in installer script",
85         "Platform %s has an equivalency loop",
86         "Module file \"%s\" in platform \"%s\" does not exist"
87 };
88
89 static char* PR_Strdup(const char* str);
90
91 #define PAD(x)  {int i; for(i=0;i<x;i++) printf(" ");}
92 #define PADINC 4
93
94 Pk11Install_File*
95 Pk11Install_File_new()
96 {
97         Pk11Install_File* new_this;
98         new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File));
99         Pk11Install_File_init(new_this);
100         return new_this;
101 }
102
103 void
104 Pk11Install_File_init(Pk11Install_File* _this)
105 {
106         _this->jarPath=NULL;
107         _this->relativePath=NULL;
108         _this->absolutePath=NULL;
109         _this->executable=PR_FALSE;
110         _this->permissions=0;
111 }
112
113 /*
114 //////////////////////////////////////////////////////////////////////////
115 // Method:      ~Pk11Install_File
116 // Class:       Pk11Install_File
117 // Notes:       Destructor.
118 */
119 void
120 Pk11Install_File_delete(Pk11Install_File* _this)
121 {
122         Pk11Install_File_Cleanup(_this);
123 }
124
125 /*
126 //////////////////////////////////////////////////////////////////////////
127 // Method:      Cleanup
128 // Class:       Pk11Install_File
129 */
130 void
131 Pk11Install_File_Cleanup(Pk11Install_File* _this)
132 {
133         if(_this->jarPath) {
134                 PR_Free(_this->jarPath);
135                 _this->jarPath = NULL;
136         }
137         if(_this->relativePath) {
138                 PR_Free(_this->relativePath);
139                 _this->relativePath = NULL;
140         }
141         if(_this->absolutePath) {
142                 PR_Free(_this->absolutePath);
143                 _this->absolutePath = NULL;
144         }
145
146         _this->permissions = 0;
147         _this->executable = PR_FALSE;
148 }
149
150 /*
151 //////////////////////////////////////////////////////////////////////////
152 // Method:      Generate
153 // Class:       Pk11Install_File
154 // Notes:       Creates a file data structure from a syntax tree.
155 // Returns:     NULL for success, otherwise an error message.
156 */
157 char*
158 Pk11Install_File_Generate(Pk11Install_File* _this,
159                           const Pk11Install_Pair *pair)
160 {
161         Pk11Install_ListIter *iter;
162         Pk11Install_Value *val;
163         Pk11Install_Pair *subpair;
164         Pk11Install_ListIter *subiter;
165         Pk11Install_Value *subval;
166         char* errStr;
167         char *endp;
168         PRBool gotPerms;
169
170         iter=NULL;
171         subiter=NULL;
172         errStr=NULL;
173         gotPerms=PR_FALSE;
174
175         /* Clear out old values */
176         Pk11Install_File_Cleanup(_this);
177
178         _this->jarPath = PR_Strdup(pair->key);
179
180         /* Go through all the pairs under this file heading */
181         iter = Pk11Install_ListIter_new(pair->list);
182         for( ; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
183                 if(val->type == PAIR_VALUE) {
184                         subpair = val->pair;
185
186                         /* Relative directory */
187                         if(!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) {
188                                 subiter = Pk11Install_ListIter_new(subpair->list);
189                                 subval = subiter->current;
190                                 if(!subval || (subval->type != STRING_VALUE)){
191                                         errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR], 
192                                     _this->jarPath);
193                                         goto loser;
194                                 }
195                                 _this->relativePath = PR_Strdup(subval->string);
196                                 Pk11Install_ListIter_delete(subiter);
197                                 subiter = NULL;
198
199                                 /* Absolute directory */
200                         } else if( !PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) {
201                                 subiter = Pk11Install_ListIter_new(subpair->list);
202                                 subval = subiter->current;
203                                 if(!subval || (subval->type != STRING_VALUE)){
204                                         errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR], 
205                                     _this->jarPath);
206                                         goto loser;
207                                 }
208                                 _this->absolutePath = PR_Strdup(subval->string);
209                                 Pk11Install_ListIter_delete(subiter);
210                                 subiter = NULL;
211
212                         /* file permissions */
213                         } else if( !PORT_Strcasecmp(subpair->key,
214                                      FILE_PERMISSIONS_STRING)) {
215                                 subiter = Pk11Install_ListIter_new(subpair->list);
216                                 subval = subiter->current;
217                                 if(!subval || (subval->type != STRING_VALUE)){
218                                         errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
219                                     _this->jarPath);
220                                         goto loser;
221                                 }
222                                 _this->permissions = (int) strtol(subval->string, &endp, 8);
223                                 if(*endp != '\0' || subval->string == "\0") {
224                                         errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
225                                     _this->jarPath);
226                                         goto loser;
227                                 }
228                                 gotPerms = PR_TRUE;
229                                 Pk11Install_ListIter_delete(subiter);
230                                 subiter = NULL;
231                         }
232                 } else {
233                         if(!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) {
234                                 _this->executable = PR_TRUE;
235                         }
236                 }
237         }
238
239         /* Default permission value */
240         if(!gotPerms) {
241                 _this->permissions = DEFAULT_PERMISSIONS;
242         }
243
244         /* Make sure we got all the information */
245         if(!_this->relativePath && !_this->absolutePath) {
246                 errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
247                 goto loser;
248         }
249 #if 0
250         if(!_this->relativePath ) {
251                 errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath);
252                 goto loser;
253         }
254         if(!_this->absolutePath) {
255                 errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
256                 goto loser;
257         }
258 #endif
259
260 loser:
261         if(iter) {
262                 Pk11Install_ListIter_delete(iter);
263                 PR_Free(iter);
264         }
265         if(subiter) {
266                 Pk11Install_ListIter_delete(subiter);
267                 PR_Free(subiter);
268         }
269         return errStr;
270 }
271
272 /*
273 //////////////////////////////////////////////////////////////////////////
274 // Method:      Print
275 // Class:       Pk11Install_File
276 */
277 void
278 Pk11Install_File_Print(Pk11Install_File* _this, int pad)
279 {
280         PAD(pad); printf("jarPath: %s\n", 
281                     _this->jarPath ? _this->jarPath : "<NULL>");
282         PAD(pad); printf("relativePath: %s\n",
283                                 _this->relativePath ? _this->relativePath: "<NULL>");
284         PAD(pad); printf("absolutePath: %s\n",
285                                 _this->absolutePath ? _this->absolutePath: "<NULL>");
286         PAD(pad); printf("permissions: %o\n", _this->permissions);
287 }
288
289 Pk11Install_PlatformName*
290 Pk11Install_PlatformName_new()
291 {
292         Pk11Install_PlatformName* new_this;
293         new_this = (Pk11Install_PlatformName*)
294                PR_Malloc(sizeof(Pk11Install_PlatformName));
295         Pk11Install_PlatformName_init(new_this);
296         return new_this;
297 }
298
299 void
300 Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this)
301 {
302         _this->OS = NULL;
303         _this->verString = NULL;
304         _this->numDigits = 0;
305         _this->arch = NULL;
306 }
307
308 /*
309 //////////////////////////////////////////////////////////////////////////
310 // Method:      ~Pk11Install_PlatformName
311 // Class:       Pk11Install_PlatformName
312 */
313 void
314 Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this)
315 {
316         Pk11Install_PlatformName_Cleanup(_this);
317 }
318
319 /*
320 //////////////////////////////////////////////////////////////////////////
321 // Method:      Cleanup
322 // Class:       Pk11Install_PlatformName
323 */
324 void
325 Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this)
326 {
327         if(_this->OS) {
328                 PR_Free(_this->OS);
329                 _this->OS = NULL;
330         }
331         if(_this->verString) {
332                 int i;
333                 for (i=0; i<_this->numDigits; i++) {
334                         PR_Free(_this->verString[i]);
335                 }
336                 PR_Free(_this->verString);
337                 _this->verString = NULL;
338         }
339         if(_this->arch) {
340                 PR_Free(_this->arch);
341                 _this->arch = NULL;
342         }
343         _this->numDigits = 0;
344 }
345
346 /*
347 //////////////////////////////////////////////////////////////////////////
348 // Method:      Generate
349 // Class:       Pk11Install_PlatformName
350 // Notes:       Extracts the information from a platform string.
351 */
352 char*
353 Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this,
354                                   const char *str)
355 {
356         char *errStr;
357         char *copy;
358         char *end, *start; /* start and end of a section (OS, version, arch)*/
359         char *pend, *pstart; /* start and end of one portion of version*/
360         char *endp; /* used by strtol*/
361         int periods, i;
362
363         errStr=NULL;
364         copy=NULL;
365
366         if(!str) {
367                 errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]);
368                 goto loser;
369         }
370         copy = PR_Strdup(str);
371
372         /*
373         // Get the OS
374         */
375         end = strchr(copy, PLATFORM_SEPARATOR_CHAR);
376         if(!end || end==copy) {
377                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
378                 goto loser;
379         }
380         *end = '\0';
381
382         _this->OS = PR_Strdup(copy);
383
384         /*
385         // Get the digits of the version of form: x.x.x (arbitrary number of digits)
386         */
387
388         start = end+1;
389         end = strchr(start, PLATFORM_SEPARATOR_CHAR);
390         if(!end) {
391                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
392                 goto loser;
393         }
394         *end = '\0';
395
396         if(end!=start) { 
397                 /* Find out how many periods*/
398                 periods = 0;
399                 pstart = start;
400                 while( (pend=strchr(pstart, '.')) ) {
401                         periods++;
402                         pstart = pend+1;
403                 }
404                 _this->numDigits= 1+ periods;
405                 _this->verString = (char**)PR_Malloc(sizeof(char*)*_this->numDigits);
406
407                 pstart = start;
408                 i = 0;
409                 /* Get the digits before each period*/
410                 while( (pend=strchr(pstart, '.')) ) {
411                         if(pend == pstart) {
412                                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
413                                 goto loser;
414                         }
415                         *pend = '\0';
416                         _this->verString[i] = PR_Strdup(pstart);
417                         endp = pend;
418                 if(endp==pstart || (*endp != '\0')) {
419                                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
420                                 goto loser;
421                         }
422                         pstart = pend+1;
423                         i++;
424                 }
425                 /* Last digit comes after the last period*/
426                 if(*pstart == '\0') {
427                         errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
428                         goto loser;
429                 }
430                 _this->verString[i] = PR_Strdup(pstart);
431                 /*
432                 if(endp==pstart || (*endp != '\0')) {
433                         errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
434                         goto loser;
435                 }
436                 */
437         } else {
438                 _this->verString = NULL;
439                 _this->numDigits = 0;
440         }
441
442         /*
443         // Get the architecture
444         */
445         start = end+1;
446         if( strchr(start, PLATFORM_SEPARATOR_CHAR) ) {
447                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
448                 goto loser;
449         }
450         _this->arch = PR_Strdup(start);
451
452         if(copy) {
453                 PR_Free(copy);
454         }
455         return NULL;
456 loser:
457         if(_this->OS) {
458                 PR_Free(_this->OS);
459                 _this->OS = NULL;
460         }
461         if(_this->verString) {
462                 for (i=0; i<_this->numDigits; i++) {
463                         PR_Free(_this->verString[i]);
464                 }
465                 PR_Free(_this->verString);
466                 _this->verString = NULL;
467         }
468         _this->numDigits = 0;
469         if(_this->arch) {
470                 PR_Free(_this->arch);
471                 _this->arch = NULL;
472         }
473
474         return errStr;
475 }
476
477 /*
478 //////////////////////////////////////////////////////////////////////////
479 // Method:      operator ==
480 // Class:       Pk11Install_PlatformName
481 // Returns:     PR_TRUE if the platform have the same OS, arch, and version
482 */
483 PRBool
484 Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this,
485                                Pk11Install_PlatformName* cmp) 
486 {
487         int i;
488
489         if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
490                 return PR_FALSE;
491         }
492
493         if(     PORT_Strcasecmp(_this->OS, cmp->OS) ||
494                 PORT_Strcasecmp(_this->arch, cmp->arch) ||
495                 _this->numDigits != cmp->numDigits ) {
496                         return PR_FALSE;
497         }
498
499         for(i=0; i < _this->numDigits; i++) {
500                 if(PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) {
501                         return PR_FALSE;
502                 }
503         }
504         return PR_TRUE;
505 }
506
507 /*
508 //////////////////////////////////////////////////////////////////////////
509 // Method:      operator <=
510 // Class:       Pk11Install_PlatformName
511 // Returns:     PR_TRUE if the platform have the same OS and arch and a lower
512 //                      or equal release.
513 */
514 PRBool
515 Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this,
516                               Pk11Install_PlatformName* cmp)
517 {
518         return (Pk11Install_PlatformName_equal(_this,cmp) ||
519           Pk11Install_PlatformName_lt(_this,cmp)) ? PR_TRUE : PR_FALSE;
520 }
521
522 /*
523 //////////////////////////////////////////////////////////////////////////
524 // Method:      operator <
525 // Class:       Pk11Install_PlatformName
526 // Returns:     PR_TRUE if the platform have the same OS and arch and a greater
527 //                      release.
528 */
529 PRBool
530 Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this,
531                             Pk11Install_PlatformName* cmp)
532 {
533         int i, scmp;
534
535         if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
536                 return PR_FALSE;
537         }
538
539         if( PORT_Strcasecmp(_this->OS, cmp->OS) ) {
540                 return PR_FALSE;
541         }
542         if( PORT_Strcasecmp(_this->arch, cmp->arch) ) {
543                 return PR_FALSE;
544         }
545
546         for(i=0; (i < _this->numDigits) && (i < cmp->numDigits); i++) {
547                 scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]);
548                 if (scmp > 0) {
549                         return PR_FALSE;
550                 } else if (scmp < 0) {
551                         return PR_TRUE;
552                 }
553         }
554         /* All the digits they have in common are the same. */
555         if(_this->numDigits < cmp->numDigits) {
556                 return  PR_TRUE;
557         } 
558
559         return PR_FALSE;
560 }
561
562 /*
563 //////////////////////////////////////////////////////////////////////////
564 // Method:      GetString
565 // Class:       Pk11Install_PlatformName
566 // Returns:     String composed of OS, release, and architecture separated
567 //                      by the separator char.  Memory is allocated by this function
568 //                      but is the responsibility of the caller to de-allocate.
569 */
570 char*
571 Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this) 
572 {
573         char *ret;
574         char *ver;
575         char *OS_;
576         char *arch_;
577
578         OS_=NULL;
579         arch_=NULL;
580
581         OS_ = _this->OS ? _this->OS : "";
582         arch_ = _this->arch ? _this->arch : "";
583
584         ver = Pk11Install_PlatformName_GetVerString(_this);
585         ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver,
586                                         PLATFORM_SEPARATOR_CHAR, arch_);
587
588         PR_Free(ver);
589
590         return ret;
591 }
592
593 /*
594 //////////////////////////////////////////////////////////////////////////
595 // Method:      GetVerString
596 // Class:       Pk11Install_PlatformName
597 // Returns:     The version string for this platform, in the form x.x.x with an
598 //                      arbitrary number of digits.  Memory allocated by function,
599 //                      must be de-allocated by caller.
600 */
601 char*
602 Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this) 
603 {
604         char *tmp;
605         char *ret;
606         int i;
607         char buf[80];
608
609         tmp = (char*)PR_Malloc(80*_this->numDigits+1);
610         tmp[0] = '\0';
611
612         for(i=0; i < _this->numDigits-1; i++) {
613                 sprintf(buf, "%s.", _this->verString[i]);
614                 strcat(tmp, buf);
615         }
616         if(i < _this->numDigits) {
617                 sprintf(buf, "%s", _this->verString[i]);
618                 strcat(tmp, buf);
619         }
620
621         ret = PR_Strdup(tmp);
622         free(tmp);
623
624         return ret;
625 }
626
627 /*
628 //////////////////////////////////////////////////////////////////////////
629 // Method:      Print
630 // Class:       Pk11Install_PlatformName
631 */
632 void
633 Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad)
634 {
635         PAD(pad); printf("OS: %s\n", _this->OS ? _this->OS : "<NULL>");
636         PAD(pad); printf("Digits: ");
637         if(_this->numDigits == 0) {
638                 printf("None\n");
639         } else {
640                 printf("%s\n", Pk11Install_PlatformName_GetVerString(_this));
641         }
642         PAD(pad); printf("arch: %s\n", _this->arch ? _this->arch : "<NULL>");
643 }
644
645 Pk11Install_Platform*
646 Pk11Install_Platform_new()
647 {
648         Pk11Install_Platform* new_this;
649         new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform));
650         Pk11Install_Platform_init(new_this);
651         return new_this;
652 }
653
654 void
655 Pk11Install_Platform_init(Pk11Install_Platform* _this)
656 {
657         Pk11Install_PlatformName_init(&_this->name);
658         Pk11Install_PlatformName_init(&_this->equivName);
659         _this->equiv = NULL;
660         _this->usesEquiv = PR_FALSE;
661         _this->moduleFile = NULL;
662         _this->moduleName = NULL;
663         _this->modFile = -1;
664         _this->mechFlags = 0;
665         _this->cipherFlags = 0;
666         _this->files = NULL;
667         _this->numFiles = 0;
668 }
669
670 /*
671 //////////////////////////////////////////////////////////////////////////
672 // Method:      ~Pk11Install_Platform
673 // Class:       Pk11Install_Platform
674 */
675 void
676 Pk11Install_Platform_delete(Pk11Install_Platform* _this)
677 {
678         Pk11Install_Platform_Cleanup(_this);
679 }
680
681 /*
682 //////////////////////////////////////////////////////////////////////////
683 // Method:      Cleanup
684 // Class:       Pk11Install_Platform
685 */
686 void
687 Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this)
688 {
689         int i;
690         if(_this->moduleFile) {
691                 PR_Free(_this->moduleFile);
692                 _this->moduleFile = NULL;
693         }
694         if(_this->moduleName) {
695                 PR_Free(_this->moduleName);
696                 _this->moduleName = NULL;
697         }
698         if(_this->files) {
699                 for (i=0;i<_this->numFiles;i++) {
700                         Pk11Install_File_delete(&_this->files[i]);
701                 }
702                 PR_Free(_this->files);
703                 _this->files = NULL;
704         }
705         _this->equiv = NULL;
706         _this->usesEquiv = PR_FALSE;
707         _this->modFile = -1;
708         _this->numFiles = 0;
709         _this->mechFlags = _this->cipherFlags = 0;
710 }
711
712 /*
713 //////////////////////////////////////////////////////////////////////////
714 // Method:      Generate
715 // Class:       Pk11Install_Platform
716 // Notes:       Creates a platform data structure from a syntax tree.
717 // Returns:     NULL for success, otherwise an error message.
718 */
719 char*
720 Pk11Install_Platform_Generate(Pk11Install_Platform* _this,
721                               const Pk11Install_Pair *pair)
722 {
723         char* errStr;
724         char* endptr;
725         char* tmp;
726         int i;
727         Pk11Install_ListIter *iter;
728         Pk11Install_Value *val;
729         Pk11Install_Value *subval;
730         Pk11Install_Pair *subpair;
731         Pk11Install_ListIter *subiter;
732         PRBool gotModuleFile, gotModuleName, gotMech, 
733           gotCipher, gotFiles, gotEquiv;
734
735         errStr=NULL;
736         iter=subiter=NULL;
737         val=subval=NULL;
738         subpair=NULL;
739         gotModuleFile=gotModuleName=gotMech=gotCipher=gotFiles=gotEquiv=PR_FALSE;
740         Pk11Install_Platform_Cleanup(_this);
741
742         errStr = Pk11Install_PlatformName_Generate(&_this->name,pair->key);
743         if(errStr) {
744                 tmp = PR_smprintf("%s: %s", pair->key, errStr);
745                 PR_smprintf_free(errStr);
746                 errStr = tmp;
747                 goto loser;
748         }
749
750         iter = Pk11Install_ListIter_new(pair->list);
751         for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) {
752                 if(val->type==PAIR_VALUE) {
753                         subpair = val->pair;
754
755                         if( !PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) {
756                                 if(gotModuleFile) {
757                                         errStr = PR_smprintf(errString[REPEAT_MODULE_FILE],
758                                     Pk11Install_PlatformName_GetString(&_this->name));
759                                         goto loser;
760                                 }
761                                 subiter = Pk11Install_ListIter_new(subpair->list);
762                                 subval = subiter->current;
763                                 if(!subval || (subval->type != STRING_VALUE)) {
764                                         errStr = PR_smprintf(errString[BOGUS_MODULE_FILE],
765                                     Pk11Install_PlatformName_GetString(&_this->name));
766                                         goto loser;
767                                 }
768                                 _this->moduleFile = PR_Strdup(subval->string);
769                                 Pk11Install_ListIter_delete(subiter);
770                                 PR_Free(subiter);
771                                 subiter = NULL;
772                                 gotModuleFile = PR_TRUE;
773                         } else if(!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)){
774                                 if(gotModuleName) {
775                                         errStr = PR_smprintf(errString[REPEAT_MODULE_NAME],
776                                     Pk11Install_PlatformName_GetString(&_this->name));
777                                         goto loser;
778                                 }
779                                 subiter = Pk11Install_ListIter_new(subpair->list);
780                                 subval = subiter->current;
781                                 if(!subval || (subval->type != STRING_VALUE)) {
782                                         errStr = PR_smprintf(errString[BOGUS_MODULE_NAME],
783                                     Pk11Install_PlatformName_GetString(&_this->name));
784                                         goto loser;
785                                 }
786                                 _this->moduleName = PR_Strdup(subval->string);
787                                 Pk11Install_ListIter_delete(subiter);
788                                 PR_Free(subiter);
789                                 subiter = NULL;
790                                 gotModuleName = PR_TRUE;
791                         } else if(!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) {
792                                 endptr=NULL;
793
794                                 if(gotMech) {
795                                         errStr = PR_smprintf(errString[REPEAT_MECH],
796                                     Pk11Install_PlatformName_GetString(&_this->name));
797                                         goto loser;
798                                 }
799                                 subiter = Pk11Install_ListIter_new(subpair->list);
800                                 subval = subiter->current;
801                                 if(!subval || (subval->type != STRING_VALUE)) {
802                                         errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
803                                     Pk11Install_PlatformName_GetString(&_this->name));
804                                         goto loser;
805                                 }
806                                 _this->mechFlags = strtol(subval->string, &endptr, 0);
807                                 if(*endptr!='\0' || (endptr==subval->string) ) {
808                                         errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
809                                     Pk11Install_PlatformName_GetString(&_this->name));
810                                         goto loser;
811                                 }
812                                 Pk11Install_ListIter_delete(subiter);
813                                 PR_Free(subiter);
814                                 subiter=NULL;
815                                 gotMech = PR_TRUE;
816                         } else if(!PORT_Strcasecmp(subpair->key,CIPHER_FLAGS_STRING)) {
817                                 endptr=NULL;
818
819                                 if(gotCipher) {
820                                         errStr = PR_smprintf(errString[REPEAT_CIPHER],
821                                     Pk11Install_PlatformName_GetString(&_this->name));
822                                         goto loser;
823                                 }
824                                 subiter = Pk11Install_ListIter_new(subpair->list);
825                                 subval = subiter->current;
826                                 if(!subval || (subval->type != STRING_VALUE)) {
827                                         errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
828                                     Pk11Install_PlatformName_GetString(&_this->name));
829                                         goto loser;
830                                 }
831                                 _this->cipherFlags = strtol(subval->string, &endptr, 0);
832                                 if(*endptr!='\0' || (endptr==subval->string) ) {
833                                         errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
834                                     Pk11Install_PlatformName_GetString(&_this->name));
835                                         goto loser;
836                                 }
837                                 Pk11Install_ListIter_delete(subiter);
838                                 PR_Free(subiter);
839                                 subiter=NULL;
840                                 gotCipher = PR_TRUE;
841                         } else if(!PORT_Strcasecmp(subpair->key, FILES_STRING)) {
842                                 if(gotFiles) {
843                                         errStr = PR_smprintf(errString[REPEAT_FILES],
844                                     Pk11Install_PlatformName_GetString(&_this->name));
845                                         goto loser;
846                                 }
847                                 subiter = Pk11Install_ListIter_new(subpair->list);
848                                 _this->numFiles = subpair->list->numPairs;
849                                 _this->files = (Pk11Install_File*)
850                             PR_Malloc(sizeof(Pk11Install_File)*_this->numFiles);
851                                 for(i=0; i < _this->numFiles; i++, 
852                                    Pk11Install_ListIter_nextItem(subiter)) {
853                                         Pk11Install_File_init(&_this->files[i]);
854                                         val = subiter->current;
855                                         if(val && (val->type==PAIR_VALUE)) {
856                                                 errStr = Pk11Install_File_Generate(&_this->files[i],val->pair);
857                                                 if(errStr) {
858                                                         tmp = PR_smprintf("%s: %s", 
859                                        Pk11Install_PlatformName_GetString(&_this->name),errStr);
860                                                         PR_smprintf_free(errStr);
861                                                         errStr = tmp;
862                                                         goto loser;
863                                                 }
864                                         }
865                                 }
866                                 gotFiles = PR_TRUE;
867                         } else if(!PORT_Strcasecmp(subpair->key,
868                                     EQUIVALENT_PLATFORM_STRING)) {
869                                 if(gotEquiv) {
870                                         errStr = PR_smprintf(errString[REPEAT_EQUIV],
871                                     Pk11Install_PlatformName_GetString(&_this->name));
872                                         goto loser;
873                                 }
874                                 subiter = Pk11Install_ListIter_new(subpair->list);
875                                 subval = subiter->current;
876                                 if(!subval || (subval->type != STRING_VALUE) ) {
877                                         errStr = PR_smprintf(errString[BOGUS_EQUIV],
878                                Pk11Install_PlatformName_GetString(&_this->name));
879                                         goto loser;
880                                 }
881                                 errStr = Pk11Install_PlatformName_Generate(&_this->equivName,
882                                                        subval->string);
883                                 if(errStr) {
884                                         tmp = PR_smprintf("%s: %s", 
885                             Pk11Install_PlatformName_GetString(&_this->name), errStr);
886                                         tmp = PR_smprintf("%s: %s", 
887                             Pk11Install_PlatformName_GetString(&_this->name), errStr);
888                                         PR_smprintf_free(errStr);
889                                         errStr = tmp;
890                                         goto loser;
891                                 }
892                                 _this->usesEquiv = PR_TRUE;
893                         }
894                 }
895         }
896
897         /* Make sure we either have an EquivalentPlatform or all the other info */
898         if(_this->usesEquiv &&
899                 (gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) {
900                 errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO], 
901                            Pk11Install_PlatformName_GetString(&_this->name));
902                 goto loser;
903         }
904         if(!gotFiles && !_this->usesEquiv) {
905                 errStr = PR_smprintf(errString[NO_FILES], 
906                            Pk11Install_PlatformName_GetString(&_this->name));
907                 goto loser;
908         }
909         if(!gotModuleFile && !_this->usesEquiv) {
910                 errStr= PR_smprintf(errString[NO_MODULE_FILE], 
911                           Pk11Install_PlatformName_GetString(&_this->name));
912                 goto loser;
913         }
914         if(!gotModuleName && !_this->usesEquiv) {
915                 errStr = PR_smprintf(errString[NO_MODULE_NAME], 
916                           Pk11Install_PlatformName_GetString(&_this->name));
917                 goto loser;
918         }
919
920         /* Point the modFile pointer to the correct file */
921         if(gotModuleFile) {
922                 for(i=0; i < _this->numFiles; i++) {
923                         if(!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath) ) {
924                                 _this->modFile = i;
925                                 break;
926                         }
927                 }
928                 if(_this->modFile==-1) {
929                         errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE], 
930                               _this->moduleFile,
931                               Pk11Install_PlatformName_GetString(&_this->name));
932                         goto loser;
933                 }
934         }
935         
936 loser:
937         if(iter) {
938                 PR_Free(iter);
939         }
940         if(subiter) {
941                 PR_Free(subiter);
942         }
943         return errStr;
944 }
945
946 /*
947 //////////////////////////////////////////////////////////////////////////
948 // Method:              Print
949 // Class:               Pk11Install_Platform
950 */
951 void
952 Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad)
953 {
954         int i;
955
956         PAD(pad); printf("Name:\n"); 
957         Pk11Install_PlatformName_Print(&_this->name,pad+PADINC);
958         PAD(pad); printf("equivName:\n"); 
959         Pk11Install_PlatformName_Print(&_this->equivName,pad+PADINC);
960         PAD(pad);
961         if(_this->usesEquiv) {
962                 printf("Uses equiv, which points to:\n");
963                 Pk11Install_Platform_Print(_this->equiv,pad+PADINC);
964         } else {
965                 printf("Doesn't use equiv\n");
966         }
967         PAD(pad); 
968         printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile 
969                                                  : "<NULL>");
970         PAD(pad); printf("mechFlags: %lx\n", _this->mechFlags);
971         PAD(pad); printf("cipherFlags: %lx\n", _this->cipherFlags);
972         PAD(pad); printf("Files:\n");
973         for(i=0; i < _this->numFiles; i++) {
974                 Pk11Install_File_Print(&_this->files[i],pad+PADINC);
975                 PAD(pad); printf("--------------------\n");
976         }
977 }
978
979 /*
980 //////////////////////////////////////////////////////////////////////////
981 // Method:              Pk11Install_Info
982 // Class:               Pk11Install_Info
983 */
984 Pk11Install_Info*
985 Pk11Install_Info_new()
986 {
987         Pk11Install_Info* new_this;
988         new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info));
989         Pk11Install_Info_init(new_this);
990         return new_this;
991 }
992
993 void
994 Pk11Install_Info_init(Pk11Install_Info* _this)
995 {
996         _this->platforms = NULL;
997         _this->numPlatforms = 0;
998         _this->forwardCompatible = NULL;
999         _this->numForwardCompatible = 0;
1000 }
1001
1002 /*
1003 //////////////////////////////////////////////////////////////////////////
1004 // Method:              ~Pk11Install_Info
1005 // Class:               Pk11Install_Info
1006 */
1007 void
1008 Pk11Install_Info_delete(Pk11Install_Info* _this)
1009 {
1010         Pk11Install_Info_Cleanup(_this);
1011 }
1012
1013 /*
1014 //////////////////////////////////////////////////////////////////////////
1015 // Method:              Cleanup
1016 // Class:               Pk11Install_Info
1017 */
1018 void
1019 Pk11Install_Info_Cleanup(Pk11Install_Info* _this)
1020 {
1021         int i;
1022         if(_this->platforms) {
1023                 for (i=0;i<_this->numPlatforms;i++) {
1024                         Pk11Install_Platform_delete(&_this->platforms[i]);
1025                 }
1026                 PR_Free(&_this->platforms);
1027                 _this->platforms = NULL;
1028                 _this->numPlatforms = 0;
1029         }
1030
1031         if(_this->forwardCompatible) {
1032                 for (i=0;i<_this->numForwardCompatible;i++) {
1033                         Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]);
1034                 }
1035                 PR_Free(&_this->forwardCompatible);
1036                 _this->numForwardCompatible = 0;
1037         }
1038 }
1039
1040 /*
1041 //////////////////////////////////////////////////////////////////////////
1042 // Method:              Generate
1043 // Class:               Pk11Install_Info
1044 // Takes:               Pk11Install_ValueList *list, the top-level list
1045 //                              resulting from parsing an installer file.
1046 // Returns:             char*, NULL if successful, otherwise an error string.
1047 //                              Caller is responsible for freeing memory.
1048 */
1049 char*
1050 Pk11Install_Info_Generate(Pk11Install_Info* _this,
1051                           const Pk11Install_ValueList *list)
1052 {
1053         char *errStr;
1054         Pk11Install_ListIter *iter;
1055         Pk11Install_Value *val;
1056         Pk11Install_Pair *pair;
1057         Pk11Install_ListIter *subiter;
1058         Pk11Install_Value *subval;
1059         Pk11Install_Platform *first, *second;
1060         int i, j;
1061
1062         errStr=NULL;
1063         iter=subiter=NULL;
1064         Pk11Install_Info_Cleanup(_this);
1065
1066         iter = Pk11Install_ListIter_new(list);
1067         for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) {
1068                 if(val->type == PAIR_VALUE) {
1069                         pair = val->pair;
1070
1071                         if(!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) {
1072                                 subiter = Pk11Install_ListIter_new(pair->list);
1073                                 _this->numForwardCompatible = pair->list->numStrings;
1074                                 _this->forwardCompatible = (Pk11Install_PlatformName*)
1075                                         PR_Malloc(sizeof(Pk11Install_PlatformName)*
1076                                                _this->numForwardCompatible);
1077                                 for(i=0; i < _this->numForwardCompatible; i++, 
1078                        Pk11Install_ListIter_nextItem(subiter)) {
1079                                         subval = subiter->current;
1080                                         if(subval->type == STRING_VALUE) {
1081                                                 errStr = Pk11Install_PlatformName_Generate(
1082                               &_this->forwardCompatible[i], subval->string);
1083                                                 if(errStr) {
1084                                                         goto loser;
1085                                                 }
1086                                         }
1087                                 }
1088                                 Pk11Install_ListIter_delete(subiter);
1089                                 PR_Free(subiter);
1090                                 subiter = NULL;
1091                         } else if(!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) {
1092                                 subiter = Pk11Install_ListIter_new(pair->list);
1093                                 _this->numPlatforms = pair->list->numPairs;
1094                                 _this->platforms = (Pk11Install_Platform*)
1095                             PR_Malloc(sizeof(Pk11Install_Platform)*
1096                             _this->numPlatforms);
1097                                 for(i=0; i < _this->numPlatforms; i++, 
1098                        Pk11Install_ListIter_nextItem(subiter)) {
1099                                          Pk11Install_Platform_init(&_this->platforms[i]);
1100                                         subval = subiter->current;
1101                                         if(subval->type == PAIR_VALUE) {
1102                                                 errStr = Pk11Install_Platform_Generate(&_this->platforms[i],subval->pair);
1103                                                 if(errStr) {
1104                                                         goto loser;
1105                                                 }
1106                                         }
1107                                 }
1108                                 Pk11Install_ListIter_delete(subiter);
1109                                 PR_Free(subiter);
1110                                 subiter = NULL;
1111                         }
1112                 }
1113         }
1114
1115         if(_this->numPlatforms == 0) {
1116                 errStr = PR_smprintf(errString[NO_PLATFORMS]);
1117                 goto loser;
1118         }
1119
1120 /*
1121         //
1122         // Now process equivalent platforms
1123         //
1124
1125         // First the naive pass
1126 */
1127         for(i=0; i < _this->numPlatforms; i++) {
1128                 if(_this->platforms[i].usesEquiv) {
1129                         _this->platforms[i].equiv = NULL;
1130                         for(j=0; j < _this->numPlatforms; j++) {
1131                                 if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName,
1132                                            &_this->platforms[j].name)) {
1133                                         if(i==j) {
1134                                                 errStr = PR_smprintf(errString[EQUIV_LOOP],
1135                               Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1136                                                 goto loser;
1137                                         }
1138                                         _this->platforms[i].equiv = &_this->platforms[j];
1139                                         break;
1140                                 }
1141                         }
1142                         if(_this->platforms[i].equiv == NULL) {
1143                                 errStr = PR_smprintf(errString[BOGUS_EQUIV],
1144                        Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1145                                 goto loser;
1146                         }
1147                 }
1148         }
1149
1150 /*
1151         // Now the intelligent pass, which will also detect loops.
1152         // We will send two pointers through the linked list of equivalent
1153         // platforms. Both start with the current node.  "first" traverses
1154         // two nodes for each iteration.  "second" lags behind, only traversing
1155         // one node per iteration.  Eventually one of two things will happen:
1156         // first will hit the end of the list (a platform that doesn't use
1157         // an equivalency), or first will equal second if there is a loop.
1158 */
1159         for(i=0; i < _this->numPlatforms; i++) {
1160                 if(_this->platforms[i].usesEquiv) {
1161                         second = _this->platforms[i].equiv;
1162                         if(!second->usesEquiv) {
1163                                 /* The first link is the terminal node */
1164                                 continue;
1165                         }
1166                         first = second->equiv;
1167                         while(first->usesEquiv) {
1168                                 if(first == second) {
1169                                         errStr = PR_smprintf(errString[EQUIV_LOOP],
1170                          Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1171                                         goto loser;
1172                                 }
1173                                 first = first->equiv;
1174                                 if(!first->usesEquiv) {
1175                                         break;
1176                                 }
1177                                 if(first == second) {
1178                                         errStr = PR_smprintf(errString[EQUIV_LOOP],
1179                        Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1180                                         goto loser;
1181                                 }
1182                                 second = second->equiv;
1183                                 first = first->equiv;
1184                         }
1185                         _this->platforms[i].equiv = first;
1186                 }
1187         }
1188
1189 loser:
1190         if(iter) {
1191                 Pk11Install_ListIter_delete(iter);
1192                 PR_Free(iter);
1193                 iter = NULL;
1194         }
1195         if(subiter) {
1196                 Pk11Install_ListIter_delete(subiter);
1197                 PR_Free(subiter);
1198                 subiter = NULL;
1199         }
1200         return errStr;
1201 }
1202
1203 /*
1204 //////////////////////////////////////////////////////////////////////////
1205 // Method:              GetBestPlatform
1206 // Class:               Pk11Install_Info
1207 // Takes:               char *myPlatform, the platform we are currently running
1208 //                              on.
1209 */
1210 Pk11Install_Platform*
1211 Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char *myPlatform)
1212 {
1213         Pk11Install_PlatformName plat;
1214         char *errStr;
1215         int i, j;
1216
1217         errStr=NULL;
1218
1219         Pk11Install_PlatformName_init(&plat);
1220         if( (errStr=Pk11Install_PlatformName_Generate(&plat, myPlatform)) ) {
1221                 PR_smprintf_free(errStr);
1222                 return NULL;
1223         }
1224
1225         /* First try real platforms */
1226         for(i=0; i < _this->numPlatforms; i++) {
1227                 if(Pk11Install_PlatformName_equal(&_this->platforms[i].name,&plat)) {
1228                         if(_this->platforms[i].equiv) {
1229                                 return _this->platforms[i].equiv;
1230                         }
1231                         else {
1232                                 return &_this->platforms[i];
1233                         }
1234                 }
1235         }
1236
1237         /* Now try forward compatible platforms */
1238         for(i=0; i < _this->numForwardCompatible; i++) {
1239                 if(Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i],&plat)) {
1240                         break;
1241                 }
1242         }
1243         if(i == _this->numForwardCompatible) {
1244                 return NULL;
1245         }
1246
1247         /* Got a forward compatible name, find the actual platform. */
1248         for(j=0; j < _this->numPlatforms; j++) {
1249                 if(Pk11Install_PlatformName_equal(&_this->platforms[j].name,
1250          &_this->forwardCompatible[i])) {
1251                         if(_this->platforms[j].equiv) {
1252                                 return _this->platforms[j].equiv;
1253                         } else {
1254                                 return &_this->platforms[j];
1255                         }
1256                 }
1257         }
1258
1259         return NULL;
1260 }
1261
1262 /*
1263 //////////////////////////////////////////////////////////////////////////
1264 // Method:              Print
1265 // Class:               Pk11Install_Info
1266 */
1267 void
1268 Pk11Install_Info_Print(Pk11Install_Info* _this, int pad)
1269 {
1270         int i;
1271
1272         PAD(pad); printf("Forward Compatible:\n");
1273         for(i = 0; i < _this->numForwardCompatible; i++) {
1274                 Pk11Install_PlatformName_Print(&_this->forwardCompatible[i],pad+PADINC);
1275                 PAD(pad); printf("-------------------\n");
1276         }
1277         PAD(pad); printf("Platforms:\n");
1278         for( i = 0; i < _this->numPlatforms; i++) {
1279                 Pk11Install_Platform_Print(&_this->platforms[i],pad+PADINC);
1280                 PAD(pad); printf("-------------------\n");
1281         }
1282 }
1283
1284 /*
1285 //////////////////////////////////////////////////////////////////////////
1286 */
1287 static char*
1288 PR_Strdup(const char* str)
1289 {
1290         char *tmp;
1291         tmp = (char*) PR_Malloc((unsigned int)(strlen(str)+1));
1292         strcpy(tmp, str);
1293         return tmp;
1294 }
1295
1296 /* The global value list, the top of the tree */
1297 Pk11Install_ValueList* Pk11Install_valueList=NULL;
1298
1299 /****************************************************************************/
1300 void
1301 Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this,
1302                               Pk11Install_Value *item)
1303 {
1304         _this->numItems++;
1305         if (item->type == STRING_VALUE) {
1306                 _this->numStrings++;
1307         } else {
1308                 _this->numPairs++;
1309         }
1310         item->next = _this->head;
1311         _this->head = item;
1312 }
1313
1314 /****************************************************************************/
1315 Pk11Install_ListIter*
1316 Pk11Install_ListIter_new_default()
1317 {
1318         Pk11Install_ListIter* new_this;
1319         new_this = (Pk11Install_ListIter*)
1320                     PR_Malloc(sizeof(Pk11Install_ListIter));
1321         Pk11Install_ListIter_init(new_this);
1322         return new_this;
1323 }
1324
1325 /****************************************************************************/
1326 void
1327 Pk11Install_ListIter_init(Pk11Install_ListIter* _this)
1328 {
1329         _this->list = NULL;
1330         _this->current = NULL;
1331 }
1332
1333 /****************************************************************************/
1334 Pk11Install_ListIter*
1335 Pk11Install_ListIter_new(const Pk11Install_ValueList *_list)
1336 {
1337         Pk11Install_ListIter* new_this;
1338         new_this = (Pk11Install_ListIter*)
1339                     PR_Malloc(sizeof(Pk11Install_ListIter));
1340         new_this->list = _list;
1341         new_this->current = _list->head;
1342         return new_this;
1343 }
1344
1345 /****************************************************************************/
1346 void
1347 Pk11Install_ListIter_delete(Pk11Install_ListIter* _this)
1348 {
1349         _this->list=NULL;
1350         _this->current=NULL;
1351 }
1352
1353 /****************************************************************************/
1354 void
1355 Pk11Install_ListIter_reset(Pk11Install_ListIter* _this)
1356 {
1357         if(_this->list) {
1358                 _this->current = _this->list->head;
1359         }
1360 }
1361
1362 /*************************************************************************/
1363 Pk11Install_Value*
1364 Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this)
1365 {
1366         if(_this->current) {
1367                 _this->current = _this->current->next;
1368         }
1369
1370         return _this->current;
1371 }
1372
1373 /****************************************************************************/
1374 Pk11Install_ValueList*
1375 Pk11Install_ValueList_new()
1376 {
1377         Pk11Install_ValueList* new_this;
1378         new_this = (Pk11Install_ValueList*)
1379                     PR_Malloc(sizeof(Pk11Install_ValueList));
1380         new_this->numItems = 0;
1381         new_this->numPairs = 0;
1382         new_this->numStrings = 0;
1383         new_this->head = NULL;
1384         return new_this;
1385 }
1386
1387 /****************************************************************************/
1388 void
1389 Pk11Install_ValueList_delete(Pk11Install_ValueList* _this)
1390 {
1391
1392         Pk11Install_Value *tmp;
1393         Pk11Install_Value *list;
1394         list = _this->head;
1395         
1396         while(list != NULL) {
1397                 tmp = list;
1398                 list = list->next;
1399                 PR_Free(tmp);
1400         }
1401         PR_Free(_this);
1402 }
1403
1404 /****************************************************************************/
1405 Pk11Install_Value*
1406 Pk11Install_Value_new_default()
1407 {
1408         Pk11Install_Value* new_this;
1409         new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value));
1410         new_this->type = STRING_VALUE;
1411         new_this->string = NULL;
1412         new_this->pair = NULL;
1413         new_this->next = NULL;
1414         return new_this;
1415 }
1416
1417 /****************************************************************************/
1418 Pk11Install_Value*
1419 Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr)
1420 {
1421         Pk11Install_Value* new_this;
1422         new_this = Pk11Install_Value_new_default();
1423         new_this->type = _type;
1424         if(_type == STRING_VALUE) {
1425                 new_this->pair = NULL;
1426                 new_this->string = ptr.string;
1427         } else {
1428                 new_this->string = NULL;
1429                 new_this->pair = ptr.pair;
1430         }
1431         return new_this;
1432 }
1433
1434 /****************************************************************************/
1435 void
1436 Pk11Install_Value_delete(Pk11Install_Value* _this)
1437 {
1438         if(_this->type == STRING_VALUE) {
1439                 PR_Free(_this->string);
1440         } else {
1441                 PR_Free(_this->pair);
1442         }
1443 }
1444
1445 /****************************************************************************/
1446 Pk11Install_Pair*
1447 Pk11Install_Pair_new_default()
1448 {
1449         return Pk11Install_Pair_new(NULL,NULL);
1450 }
1451
1452 /****************************************************************************/
1453 Pk11Install_Pair*
1454 Pk11Install_Pair_new(char *_key, Pk11Install_ValueList *_list)
1455 {
1456         Pk11Install_Pair* new_this;
1457         new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair));
1458         new_this->key = _key;
1459         new_this->list = _list;
1460         return new_this;
1461 }
1462
1463 /****************************************************************************/
1464 void
1465 Pk11Install_Pair_delete(Pk11Install_Pair* _this)
1466 {
1467         PR_Free(_this->key);
1468         Pk11Install_ValueList_delete(_this->list);
1469         PR_Free(_this->list);
1470 }
1471
1472 /*************************************************************************/
1473 void
1474 Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad)
1475 {
1476         while (_this) {
1477                 /*PAD(pad); printf("**Pair\n");
1478                 PAD(pad); printf("***Key====\n");*/
1479                 PAD(pad); printf("%s {\n", _this->key);
1480                 /*PAD(pad); printf("====\n");*/
1481                 /*PAD(pad); printf("***ValueList\n");*/
1482                 Pk11Install_ValueList_Print(_this->list,pad+PADINC);
1483                 PAD(pad); printf("}\n");
1484         }
1485 }
1486
1487 /*************************************************************************/
1488 void
1489 Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad)
1490 {
1491         Pk11Install_Value *v;
1492
1493         /*PAD(pad);printf("**Value List**\n");*/
1494         for(v = _this->head; v != NULL; v=v->next) {
1495                 Pk11Install_Value_Print(v,pad);
1496         }
1497 }
1498
1499 /*************************************************************************/
1500 void
1501 Pk11Install_Value_Print(Pk11Install_Value* _this, int pad)
1502 {
1503         /*PAD(pad); printf("**Value, type=%s\n",
1504                 type==STRING_VALUE ? "string" : "pair");*/
1505         if(_this->type==STRING_VALUE) {
1506                 /*PAD(pad+PADINC); printf("====\n");*/
1507                 PAD(pad); printf("%s\n", _this->string);
1508                 /*PAD(pad+PADINC); printf("====\n");*/
1509         } else {
1510                 Pk11Install_Pair_Print(_this->pair,pad+PADINC);
1511         }
1512 }