PageRenderTime 86ms CodeModel.GetById 12ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/cmd/modutil/install-ds.c

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