/* swi.c -- Posix package decoding. 

  Copyright (C) 2004,2005,2006 Jim Lowe
  All Rights Reserved.
  
  COPYING TERMS AND CONDITIONS:
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, or (at your option)
  any later version.
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "swuser_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "swheader.h"
#include "swheaderline.h"
#include "ugetopt_help.h"
#include "to_oct.h"
#include "tarhdr.h"
#include "swi.h"
#include "swinstall.h"
#include "atomicio.h"
#include "ls_list.h"
#include "swevents.h"
/* #include "swevents_array.h" */

#include "debug_config.h"
#ifdef SWSWINEEDDEBUG
#define SWSWI_E_DEBUG(format) SWBISERROR("SWI DEBUG: ", format)
#define SWSWI_E_DEBUG2(format, arg) SWBISERROR2("SWI DEBUG: ", format, arg)
#define SWSWI_E_DEBUG3(format, arg, arg1) \
			SWBISERROR3("SWI DEBUG: ", format, arg, arg1)
#else
#define SWSWI_E_DEBUG(arg)
#define SWSWI_E_DEBUG2(arg, arg1)
#define SWSWI_E_DEBUG3(arg, arg1, arg2)
#endif 

static 
SWPATH_EX *
swi_get_last_swpath_ex(SWI * swi)
{
	SWPATH_EX * ret;
	CPLOB * list = swi->swi_pkgM->exlistM;
	int index;

	/*
	* The list is always Null Terminated and the null is
	* part of the list therefore the array index of the last
	* useful element is 2 less than the reported nused.
	*/	
	index = cplob_get_nused(list) - 2;
	ret = (SWPATH_EX *)cplob_val(list, index);
	return ret;
}


/**
*  Find a product or fileset by the 'tag'
*/
SWI_BASE *
find_object_by_swsel(void * parent, char * swsel)
{
	int i;
	SWI_PACKAGE * package;
	SWI_BASE * object;
	char * verid_delim;

	package = (SWI_PACKAGE *)(parent);
	for(i=0; i<SWI_MAX_OBJ; i++) {
		object = (SWI_BASE*)(&(package->swi_coM[i]->baseM));
		if (object) {
			/*
			 * FIXME, crudely handle version ids by ignoring them
			 */
			verid_delim = strchr(swsel, ',');
			if (!verid_delim) {
				verid_delim = swsel + strlen(swsel);
			}
			
			if (strncmp(swsel, object->tagM, (size_t)(verid_delim - swsel)) == 0) {
				return object;
			}
		} else {
			return NULL;
		}
	}
	return NULL;
}

static
int
need_new_pfiles(SWI * swi)
{
	SWPATH * swpath = swi->swpathM;
	char * pfiles_dir;
	char * pfiles_attribute;
	char * prod_dir;
	
	pfiles_dir = swpath_get_pfiles(swpath);
	prod_dir = swpath_get_product_control_dir(swpath);
	pfiles_attribute = swi->swi_pkgM->pfiles_attributeM; 

	if (
		(strlen(pfiles_dir) && 
		strcmp(pfiles_attribute,  pfiles_dir)) ||
		(strlen(prod_dir) == 0)
	) {
		/*
		* Sanity check.
		*    Error
		*/
		return -1;
	}

	if (strlen(pfiles_dir) && 
		strcmp(pfiles_attribute,  pfiles_dir) == 0 &&
		strlen(swpath_get_basename(swpath))
	) {
		return 1;
	}
	return 0;
}

void
swi_set_utility_id(SWI * swi, int swc_u_id)
{
	swi->swc_idM = swc_u_id;
}

int
swi_is_definition_file(SWI * swi, char * name, int *swdeffile_type_p)
{
	char * s;
	if ((s=strstr(name, "/" SW_A_INDEX)) && *(s+6) == '\0') {
		if (swi_is_global_index(swi->swpathM, name)) {
			if (swi->swi_pkgM->did_parse_def_fileM) {
				swi_com_fatal_error("loc=index", __LINE__);
			}
			swi->swi_pkgM->did_parse_def_fileM = 1;
			*swdeffile_type_p = SWPARSE_SWDEF_FILETYPE_INDEX;
			return 1;
		} else {
			;
			/*
			 * ignore INDEX files that are not the 
			 * global index file.
			 */
		}
	}
	else if ((s=strstr(name, "/" SW_A_INFO)) && *(s+5) == '\0') {
		if (swi->swi_pkgM->current_xfileM->did_parse_def_fileM) {
			swi_com_fatal_error("loc=info", __LINE__);
		}
		swi->swi_pkgM->current_xfileM->did_parse_def_fileM = 1;
		*swdeffile_type_p = SWPARSE_SWDEF_FILETYPE_INFO;
		return 1;
	}
	*swdeffile_type_p = -1;
	return 0;
}

void
swi_xfile_add_control_script(SWI * swi, SWI_XFILE * xfile, char * name, 
					int fd, char * tag)
{
	SWI_CONTROL_SCRIPT * sc;
	SWI_FILE_MEMBER * s;

	sc = swi_control_script_create();
	/* offset = swi->xformatM->swvarfsM->current_header_offsetM;*/
	s = swi_xfile_construct_file_member(xfile, name, fd,
					swi->xformatM->swvarfsM);
	sc->baseM.tagM = strdup(tag);
	swi_com_check_clean_relative_path(sc->baseM.tagM);
	sc->afileM = s;
	swi_add_script(xfile->swi_scM, sc);
	return;
}

void
swi_xfile_add_file_member(SWI * swi, SWI_XFILE * xfile, char * name, int fd)
{
	SWI_FILE_MEMBER * s;
	/* offset = swi->xformatM->swvarfsM->current_header_offsetM; */
	s = swi_xfile_construct_file_member(xfile, name, fd,
					swi->xformatM->swvarfsM);
	cplob_add_nta(xfile->archive_filesM, (char*)s);
	return;
}

int
swi_get_distribution_attributes(SWI * swi, SWHEADER * swheader)
{
	char * value;
	char * obj;
	
	swi_com_header_manifold_reset(swheader);
	obj = swheader_get_object_by_tag(swheader, SW_A_distribution, "*" );
	if (!obj) {
		return -1;
	}
	value = swheader_get_single_attribute_value(swheader, SW_A_dfiles);
	if (value)
		swi->swi_pkgM->dfiles_attributeM = strdup(value);
	else
		swi->swi_pkgM->dfiles_attributeM = strdup(SW_A_dfiles);

	value = swheader_get_single_attribute_value(swheader, SW_A_pfiles);
	if (value)
		swi->swi_pkgM->pfiles_attributeM = strdup(value);
	else
		swi->swi_pkgM->pfiles_attributeM = strdup(SW_A_pfiles);

	return 0;


	/*
	char * obj;
	char * line;
	char * value;
	
	swi_com_header_manifold_reset(swheader);
	obj = swheader_get_object_by_tag(swheader, SW_A_distribution, "*" );
	line = swheader_get_attribute(swheader, SW_A_dfiles);
	if (line) {
		value = swheaderline_get_value(line, (int*)NULL);
		swi_com_assert_pointer((void*)value, __FILE__, __LINE__);
		swi->swi_pkgM->dfiles_attributeM = strdup(value);
	} else {
		swi->swi_pkgM->dfiles_attributeM = strdup(SW_A_dfiles);
	}
	
	swi_com_header_manifold_reset(swheader);
	obj = swheader_get_object_by_tag(swheader, SW_A_distribution, "*" );
	line = swheader_get_attribute(swheader, SW_A_pfiles);
	if (line) {
		value = swheaderline_get_value(line, (int*)NULL);
		swi_com_assert_pointer((void*)value, __FILE__, __LINE__);
		swi->swi_pkgM->pfiles_attributeM = strdup(value);
	} else {
		swi->swi_pkgM->pfiles_attributeM = strdup(SW_A_pfiles);
	}
	return 0;
	*/
}

void 
swi_package_delete(SWI_PACKAGE * s)
{
	SWPATH_EX * expath;
	int index;
	int i;

	index = 0;
	expath = (SWPATH_EX*)cplob_val(s->exlistM, index++);
	while (expath) {
		swpath_delete_export(expath);
		expath = (SWPATH_EX*)cplob_val(s->exlistM, index++);
	}
	free((void*)(cplob_release(s->exlistM)));	

	/* if (s->prev_swpath_exM) swpath_delete_export(s->prev_swpath_exM); */
	if (s->catalog_entryM != (char*)NULL) free(s->catalog_entryM);
	if (s->target_pathM != (char*)NULL) free(s->target_pathM);
	if (s->target_hostM != (char*)NULL) free(s->target_hostM);
	if (s->installed_software_catalogM != (char*)NULL) {
		 free(s->installed_software_catalogM);
	}
	if (s->dfilesM) swi_xfile_delete(s->dfilesM);
	if (s->baseM.global_headerM) swheader_close(s->baseM.global_headerM);
	if (s->swdef_fdM > 0) uxfio_close(s->swdef_fdM);
	s->swdef_fdM = -1;
	swi_scripts_delete(s->swi_scM);
	for(i=0; i<SWI_MAX_OBJ; i++) {
		if (s->swi_coM[i])
			swi_product_delete(s->swi_coM[i]);
	}
	free(s);
	return; 
}

SWI_PACKAGE *
swi_package_create(void)
{
	SWI_PACKAGE * s = (SWI_PACKAGE *)malloc(sizeof(SWI_PACKAGE));
	SWSWI_E_DEBUG("");
	swi_com_assert_pointer((void*)s, __FILE__, __LINE__);
	swiInitListOfObjects((void**)(s->swi_coM));
	swi_vbase_init(s, SWI_I_TYPE_PACKAGE, NULL, NULL);
	s->swi_scM = swi_scripts_create();
	s->exlistM = cplob_open(1);
	s->baseM.global_headerM = NULL;
	s->swdef_fdM = -1;
	s->current_productM = NULL;
	s->dfilesM = NULL;
	s->current_xfileM = NULL;
	s->did_parse_def_fileM = 0;
	s->prev_swpath_exM = NULL; 
	s->catalog_lengthM = 0;
	s->catalog_entryM = (char*)NULL;
	s->target_pathM = (char*)NULL;
	s->target_hostM = (char*)NULL;
	s->installed_software_catalogM = (char*)NULL;
	return s;
}

void
swi_delete(SWI * s)
{
	close(s->nullfdM);
	swi_package_delete(s->swi_pkgM);
	swicol_delete(s->swicolM);
	if (s->distdataM) swi_distdata_delete(s->distdataM);
	free(s);
}

SWI * swi_create(void)
{
	SWI * swi;

	SWSWI_E_DEBUG("");
	swi = (SWI*)malloc(sizeof(SWI));
	swi_com_assert_pointer((void*)swi, __FILE__, __LINE__);
	swi->xformatM = NULL;
	swi->swvarfsM = NULL;
	swi->uinformatM = NULL;
	swi->swpathM = NULL;
	swi->swi_pkgM = swi_package_create();
	swi->nullfdM = open("/dev/null", O_RDWR);
	memset(swi->tarbufM, '\0', sizeof(swi->tarbufM));
	swi->distdataM = NULL;
	swi->sh_dash_sM = (char*)NULL;
	swi->dash_rM = 0;
	swi->swicolM = swicol_create();
	swi->exported_catalog_prefixM = NULL;
	swi->verboseM = 0;
	swi->debug_eventsM = 0;
	swi->version_idM = swverid_open("HOST", NULL);
	return swi;
}

void
swi_product_delete(SWI_PRODUCT * s)
{
	int i;
	if (s->baseM.tagM) free(s->baseM.tagM);
	if (s->package_pathM) free(s->package_pathM);
	if (s->control_dirM) free(s->control_dirM);

	if (s->filesetsM) strar_close(s->filesetsM);

	if (s->pfilesM) swi_xfile_delete(s->pfilesM);
	
	for(i=0; i<SWI_MAX_OBJ; i++) {
		if (s->swi_coM[i])
			swi_xfile_delete(s->swi_coM[i]);
	}
	free(s);
}

SWI_PRODUCT *
swi_product_create(SWHEADER * global_index_header, SWPATH_EX * current)
{
	SWI_PRODUCT * s = (SWI_PRODUCT *)malloc(sizeof(SWI_PRODUCT));
	SWSWI_E_DEBUG("");
	swi_com_assert_pointer((void*)s, __FILE__, __LINE__);

        #ifdef SWSWINEEDDEBUG
                {
                STROB * tmp = strob_open(100);
                fprintf(stderr, "%s", 
                        swpath_ex_print(current, tmp, "swi_product_create"));                            
                strob_close(tmp);
                }
        #endif

	swi_vbase_init(s, SWI_I_TYPE_PROD, global_index_header, current);

	s->package_pathM = (char*)NULL;
	s->control_dirM = (char*)NULL;
	s->filesetsM = (STRAR*)NULL;
	swiInitListOfObjects((void**)(s->swi_coM));
	s->pfilesM = NULL;
	s->is_selectedM = 1;
	return s;
}

void
swi_product_add_fileset(SWI_PRODUCT * thisis, SWI_XFILE * v)
{
	SWSWI_E_DEBUG("ENTERING");
	swiAddObjectToList((void **)(thisis->swi_coM), (void *)v);
	SWSWI_E_DEBUG("LEAVING");
}

void
swi_package_add_product(SWI_PACKAGE * thisis, SWI_PRODUCT * v)
{
	SWSWI_E_DEBUG("ENTERING");
	swiAddObjectToList((void **)(thisis->swi_coM), (void *)v);
	SWSWI_E_DEBUG("LEAVING");
}

int
swi_store_file(SWI * swi, char * name, SWI_XFILE * current_xfile) {
	int fd;
	char * tag;
	XFORMAT * xformat = swi->xformatM;
	
	SWSWI_E_DEBUG("ENTERING");
	swi_com_assert_pointer((void*)current_xfile, __FILE__, __LINE__);
	
	fd = xformat_u_open_file(xformat, name);
	swi_com_assert_value(fd >= 0, __FILE__, __LINE__);

	if (swi_afile_is_ieee_control_script(name)) {
		tag = swlib_basename(NULL, name);
		swi_xfile_add_control_script(swi, current_xfile,
			name, fd, tag);
	} else {
		swi_xfile_add_file_member(swi, current_xfile, name, fd);
	}
	xformat_u_close_file(xformat, fd);
	SWSWI_E_DEBUG("LEAVING");
	return 0;
}

int
swi_expand_shared_file_control_sripts(SWI * swi, SWI_XFILE * xfile)
{
	SWHEADER * swheader = xfile->info_headerM;
	SWI_CONTROL_SCRIPT * script;
	SWI_CONTROL_SCRIPT * new_script;
	SWI_FILE_MEMBER * afile;
	char * next_line;
	char * path_attr;
	char * path_value;
	char * tag_attr;
	char * tag_value;

	SWSWI_E_DEBUG("ENTERING");
	swheader_reset(swheader);
	swheader_set_current_offset_p_value(swheader, 0);

	next_line = swheader_get_next_object(swheader, 
		(int)UCHAR_MAX, (int)UCHAR_MAX);
	while (next_line){
		swheader_goto_next_line((void *)swheader, 
			swheader_get_current_offset_p(swheader), 
				SWHEADER_PEEK_NEXT);
		path_attr = swheader_get_attribute(swheader,
			SW_A_path);
		tag_attr = swheader_get_attribute(swheader,
			SW_A_tag);

		/*
		 * Now search the control scripts to see if this
		 * tag is present.
		 */
		swi_com_assert_value(tag_attr != NULL, __FILE__, __LINE__);
		tag_value = swheaderline_get_value(tag_attr, NULL);
		path_value = swheaderline_get_value(path_attr, NULL);

		if (swi_afile_is_ieee_control_script(tag_value)) {
			script = swi_xfile_get_control_script_by_tag(xfile,
				tag_value);
			if (script == NULL) {
				/*
				 * Not found, need to make it.
				 * This happens when control_files share the
				 * same script.
				 */

				/* fprintf(stderr, "tag=[%s] Not Found\n", tag_attr ? swheaderline_get_value(tag_attr, NULL) : "null"); */
				/* swi_xfile_add_control_script(swi, xfile, name, int fd, tag); */

				swi_com_assert_value(path_value != NULL, __FILE__, __LINE__);
				script = swi_xfile_get_control_script_by_path(xfile, path_value);
				/* BUG ME swi_com_assert_value(source_script != NULL, __FILE__, __LINE__); */

				/*
				 * Now we need to make a new (SWI_CONTROL_SCRIPT *) object.
				 */
				if (script) {
					afile = script->afileM;
				}  else {
					afile = swi_xfile_get_control_file_by_path(xfile, path_value);
				}		
		
				SWLIB_ASSERT(afile != NULL);
					
				new_script = swi_control_script_create();
				new_script->baseM.tagM = strdup(tag_value);
				swi_com_check_clean_relative_path(new_script->baseM.tagM);
				new_script->afileM = afile;
				(afile->refcountM)++;
				swi_add_script(xfile->swi_scM, new_script);
			}
		} else {
			;	
		}
		next_line = swheader_get_next_object(swheader, 
			(int)UCHAR_MAX, (int)UCHAR_MAX);
	}
	return 0;
}

int
swi_parse_file(
		SWI * swi, 
		char * name, 
		int swdeffile_type)
{
	XFORMAT * xformat = swi->xformatM;
	char * base;
	char * newbase;
	SWHEADER * swheader;
	SWPATH * swpath = swi->swpathM;
	int ret;
	int ufd;
	int curfd = swlib_open_memfd();
	int ofd = swlib_open_memfd();
	int len;

	SWSWI_E_DEBUG("ENTERING");
	ufd = xformat_u_open_file(xformat, name);
	if (ufd < 0) {
		swi_com_fatal_error( __FILE__, __LINE__);
	}	

	swlib_pipe_pump(curfd, ufd);
	xformat_u_close_file(xformat, ufd);

	uxfio_lseek(curfd, (off_t)0, SEEK_SET);
	
	ret = sw_yyparse(curfd, ofd, name, 0, SWPARSE_FORM_MKUP_LEN);
	if (ret) {
		fprintf(stderr,
		"%s: error parsing %s\n", swlib_utilname_get(), name);
		swi_com_fatal_error( __FILE__, __LINE__);
	}
	uxfio_write(ofd, "\x00", 1);
	base = swi_com_get_fd_mem(ofd, &len);
	newbase = (char*)malloc(len);
	swi_com_assert_pointer((void*)(newbase), __FILE__, __LINE__);
	memcpy(newbase, base, len);
	swi_com_close_memfd(ofd);

	swheader = swheader_open((char *(*)(void *, int *, int))(NULL), NULL);
	swheader_set_image_head(swheader, newbase);	
	/* swheader_set_image_length(swheader, len); */	
	uxfio_lseek(curfd, (off_t)0, SEEK_SET);

	swi_com_assert_pointer((void*)(swi->swi_pkgM), __FILE__, __LINE__);
	switch(swdeffile_type) {
		case SWPARSE_SWDEF_FILETYPE_INFO:
			SWSWI_E_DEBUG("case");
			swi_com_assert_pointer(
				(void*)(swi->swi_pkgM->current_xfileM),
					__FILE__, __LINE__);
			swi->swi_pkgM->current_xfileM->info_headerM = swheader;
			swi->swi_pkgM->current_xfileM->INFO_header_indexM = 0;
			swi->swi_pkgM->current_xfileM->swdef_fdM = curfd;
			swi->swi_pkgM->current_xfileM->did_parse_def_fileM = 1;
		
			swheader_set_current_offset_p(swheader, 
			&(swi->swi_pkgM->current_xfileM->INFO_header_indexM));
			swheader_set_current_offset_p_value(swheader, 0);
			swheader_reset(swheader);
			swheader_goto_next_line(swheader, 
				swheader_get_current_offset_p(swheader),
				SWHEADER_GET_NEXT);
			break;
		case SWPARSE_SWDEF_FILETYPE_INDEX:
			SWSWI_E_DEBUG("case");
			swi->swi_pkgM->baseM.global_headerM = swheader;
			swi->swi_pkgM->baseM.header_indexM = 0;
			swi->swi_pkgM->swdef_fdM = curfd;
			swi->swi_pkgM->did_parse_def_fileM = 1;
			
			swheader_set_current_offset_p(swheader, 
					&(swi->swi_pkgM->baseM.header_indexM));
			swheader_set_current_offset_p_value(swheader, 0);
			swheader_reset(swheader);
			swheader_goto_next_line(swheader,
				swheader_get_current_offset_p(swheader),
				SWHEADER_GET_NEXT);
			
			if (swi_get_distribution_attributes(swi, swheader) != 0)
				swi_com_fatal_error( __FILE__, __LINE__);
			swpath_set_dfiles(swpath, 
					swi->swi_pkgM->dfiles_attributeM);
			swpath_set_pfiles(swpath, 
					swi->swi_pkgM->pfiles_attributeM);
			break;
		default:
			swi_com_fatal_error( __FILE__ ":invalid case", __LINE__);
			break;	
	}
	SWSWI_E_DEBUG("LEAVING");
	return ret;
}

int
swi_update_current_context(SWI * swi, SWPATH_EX * swpath_ex)
{
	return 0;
}

int
swi_add_swpath_ex(SWI * swi)
{
	CPLOB * list = swi->swi_pkgM->exlistM;
	SWPATH * swpath = swi->swpathM;
	SWPATH_EX * swpath_ex;

	SWSWI_E_DEBUG("ENTERING");
	swi->swi_pkgM->prev_swpath_exM = swi_get_last_swpath_ex(swi);

	swpath_ex = swpath_create_export(swpath);
	swi_com_assert_pointer((void*)swpath_ex, __FILE__, __LINE__);

	cplob_add_nta(list, (char*)(swpath_ex));
	SWSWI_E_DEBUG("LEAVING");
	return 0;	
}

int
swi_handle_control_transition(SWI * swi)
{
	SWI_PACKAGE * package = swi->swi_pkgM;
	SWPATH_EX * current;
	SWPATH_EX * previous;
	SWI_XFILE * fileset;
	SWI_XFILE * pfiles;
	int tret;
	int detect;
	int found_edge = 0;	

	SWSWI_E_DEBUG("ENTERING");
	previous = swi->swi_pkgM->prev_swpath_exM;
	current = swi_get_last_swpath_ex(swi);
	
	SWSWI_E_DEBUG("ENTERING");

        #ifdef SWSWINEEDDEBUG
	{
                STROB * tmp = strob_open(100);
		SWSWI_E_DEBUG2("Previous SWPATH_EX:\n %s\n",
			swpath_ex_print(previous, tmp, "previous"));
		SWSWI_E_DEBUG2("Current  SWPATH_EX:\n %s\n",
			swpath_ex_print(current, tmp, "current"));
                strob_close(tmp);
	}
	#endif

	/* SWPATH_EX
	 * int is_catalog;	
	 * int ctl_depth;
	 * char * pkgpathname;
	 * char * prepath;
	 * char * dfiles;
	 * char * pfiles;
	 * char * product_control_dir;
	 * char * fileset_control_dir;
	 * char * pathname;	
	 * char * basename;
	 */

	if (!previous) {
		/*
		* FIXME, Free this.
		*/
		previous = swpath_create_export((SWPATH*)NULL);
	}

	detect = swi_com_field_edge_detect(current->dfiles,  previous->dfiles);
	if (found_edge == 0 && detect) {
		/*
		 * New dfiles.
		 */
		SWSWI_E_DEBUG("New dfiles");
		package->dfilesM = swi_xfile_create(SWI_XFILE_TYPE_DFILES,
					SWI_INDEX_HEADER(swi), current);
		package->current_xfileM = package->dfilesM;
		package->dfilesM->package_pathM = strdup(current->pkgpathname);
		SWSWI_E_DEBUG2("Setting Current XFILE (dfiles) [%p]",
					(void*)(package->current_xfileM));
		found_edge = 1;
	}

	detect = swi_com_field_edge_detect(current->product_control_dir, 
					previous->product_control_dir);
	if (found_edge == 0 && detect) {
		/*
		 * New product.
		 */
		SWSWI_E_DEBUG("New Product");
		package->current_productM = swi_product_create(SWI_INDEX_HEADER(swi), current);
		swi_package_add_product(package, package->current_productM);
		package->current_xfileM = NULL;
		package->current_productM->package_pathM = 
					strdup(current->pkgpathname);
		if ((tret=need_new_pfiles(swi)) > 0) {
			/*
			 * This happens in packages without directories in 
			 * the archive.
			 * e.g.
			 *	...
			 *	catalog/dfiles/INFO
			 *	catalog/prod1/pfiles/INFO
			 *	...
			 */
			pfiles = swi_xfile_create(SWI_XFILE_TYPE_FILESET, SWI_INDEX_HEADER(swi), current);
			pfiles->package_pathM = strdup(current->pkgpathname);
			package->current_productM->pfilesM = pfiles;
			package->current_xfileM = pfiles;
		} else if (tret < 0) {
			SWI_internal_error();
			return -1;
		} else {
			;
		}
		SWSWI_E_DEBUG2("Setting Current Product [%p]",
				(void*)(package->current_productM));
		SWSWI_E_DEBUG2("Setting Current XFILE (NULL) [%p]",
					(void*)(package->current_xfileM));
		found_edge = 1;
	}

	detect = swi_com_field_edge_detect_fileset(current, previous);
	if (found_edge == 0 && detect) {
		/*
		 * New fileset.
		 */
		SWSWI_E_DEBUG("New Fileset");
		fileset = swi_xfile_create(SWI_XFILE_TYPE_FILESET, SWI_INDEX_HEADER(swi), current);
		swi_product_add_fileset(package->current_productM, fileset);
		package->current_xfileM = fileset;
		package->current_xfileM->package_pathM = 
						strdup(current->pkgpathname);
		SWSWI_E_DEBUG2("        Current Product [%p]",
				(void*)(package->current_productM));
		SWSWI_E_DEBUG2("Setting Current XFILE (fileset) [%p]",
					(void*)(package->current_xfileM));
		found_edge = 1;
	}

	detect = swi_com_field_edge_detect(current->pfiles, previous->pfiles);
	if (found_edge == 0 && detect) {
		/*
		 * New pfiles.
		 */
		SWSWI_E_DEBUG("New pfiles");
		pfiles = swi_xfile_create(SWI_XFILE_TYPE_PFILES, SWI_INDEX_HEADER(swi), current);
		if (package->current_productM == NULL) {
			/*
			 * This happens for minimal package layout.
			 */
			package->current_productM = swi_product_create(SWI_INDEX_HEADER(swi), current);
			swi_package_add_product(package, 
						package->current_productM);
			package->current_xfileM = NULL;
		}
		pfiles->package_pathM = strdup(current->pkgpathname);
		package->current_productM->pfilesM = pfiles;
		package->current_xfileM = pfiles;
		SWSWI_E_DEBUG2("   Current Product [%p]",
				(void*)(package->current_productM));
		SWSWI_E_DEBUG2("Setting Current XFILE (pfiles) [%p]",
					(void*)(package->current_xfileM));
		found_edge = 1;
	}

	SWSWI_E_DEBUG2("LEAVING return value = [%d]", found_edge);
	return found_edge;
}

int
swi_decode_catalog(SWI * swi)
{
	XFORMAT * xformat = swi->xformatM;
	SWPATH * swpath = swi->swpathM;

	STROB * tmp = strob_open(24);
	struct stat st;
	int nullfd;
	int copyret = 0;
	int ret;
	int handle_ret;
	int swpath_ret;
	int retval = -99;
	int is_catalog;
	char * name;
	int header_bytes;
	int swdef_ret = 0;
	int swdeffile_type;
	int ifd;
	int offset = 0;
	int oldoffset = 0;
	int catalog_start_offset = -1;
	int catalog_end_offset = 0;

	nullfd = swi->nullfdM;
	if (nullfd < 0) return -22;		

	ifd = xformat_get_ifd(xformat);
	name = xformat_get_next_dirent(xformat, &st);
	if (ifd >= 0) {
		offset = uxfio_lseek(ifd, (off_t)0, SEEK_CUR);	
	}

	while(name) {
		header_bytes = ret;
		SWSWI_E_DEBUG("");
		if (xformat_is_end_of_archive(xformat)){
			/* 
			 * error 
			 */
			retval = -1;
			break;
		}

		/*
		 * Check for absolute path, and for shell metacharacters
		 * characters in the pathname.
		 */
		swi_com_check_clean_relative_path(name);

		swpath_ret = swpath_parse_path(swpath, name);
		if (swpath_ret < 0) {
			SWSWI_E_DEBUG("");
			fprintf(stderr, "%s: error parsing pathname [%s]\n", swlib_utilname_get(), name);
			retval = -2;
			break;
		}

		is_catalog = swpath_get_is_catalog(swpath);
		if (is_catalog != SWPATH_CTYPE_STORE) {
			/*
			 * Either -1 leading dir, or 1 catalog.
			 */
			if (is_catalog == 1 && catalog_start_offset < 0) {
				SWSWI_E_DEBUG("");
				catalog_start_offset = offset;
				swi->swi_pkgM->catalog_start_offsetM = offset;
				/*
				fprintf(stderr,
				"eraseme START ---OFFSET=%d %d\n",
					offset,
				xformat->swvarfsM->current_header_offsetM); 
				*/
			}
			
			if (swi->exported_catalog_prefixM == NULL && is_catalog == 1) {
				/*
				 * fill in the swi->exported_catalog_prefixM  member.
				 * This is how the catalog directory is
				 * specified when being unpacked (by tar)
				 * and deleted.
				 */
				SWSWI_E_DEBUG("");
				strob_strcpy(tmp, swpath_get_prepath(swpath));
				swlib_unix_dircat(tmp, SW_CATALOG);
				swi->exported_catalog_prefixM = strdup(strob_str(tmp));
				swi_com_check_clean_relative_path(strob_str(tmp));
			}

			swi_add_swpath_ex(swi);
			
			handle_ret = swi_handle_control_transition(swi);
			if (handle_ret < 0) {	
				/*
				 * error
				 */	
				SWSWI_E_DEBUG("");
				swi_com_assert_pointer((void*)NULL, 
						__FILE__, __LINE__);
			}
 
			if (swi_is_definition_file(swi, name, 
							&swdeffile_type)) 
			{
				/*
				 * parse the IEEE 1387.2 software definition file
				 */
				SWSWI_E_DEBUG("");
				swdef_ret = swi_parse_file(swi, name, 
							swdeffile_type);
				if (swdef_ret) {
					fprintf(stderr, "error parsing %s\n",
							name);
					retval = -3;
					break;
				}
				copyret = 0;	
			} else if (xformat_file_has_data(xformat)) {
				/*
				 * Store the file data.
				 */
				SWSWI_E_DEBUG("");
				swi_store_file(swi, name,
					swi->swi_pkgM->current_xfileM);
			} else {
				/*
				 * No data
				 */
				SWSWI_E_DEBUG("");
				copyret = 0;	
				;
			}
			if (copyret < 0) {
				/*
				 * error
				 */
				SWSWI_E_DEBUG("");
				SWI_internal_error();
				retval = -4;
				break;
			}
			SWSWI_E_DEBUG("");
			catalog_end_offset = uxfio_lseek(ifd, (off_t)0, SEEK_CUR);	
			swi->swi_pkgM->catalog_end_offsetM = catalog_end_offset;
		} else {
			/*
			 * Good.
			 * Finished, read past catalog section
			 */
			SWSWI_E_DEBUG("");
			if (catalog_start_offset < 0) {
				catalog_start_offset = 0;
				fprintf(stderr, "internal error: %s:%d\n",
					__FILE__, __LINE__);
			}
			swi->swi_pkgM->catalog_lengthM = 
				catalog_end_offset - catalog_start_offset; 
	
			/*
			 * Now fix-up the control scripts that share
			 * a common control file.
			 */
			ret = swi_expand_shared_file_control_sripts(swi, swi->swi_pkgM->swi_coM[0]->pfilesM);
			swi_com_assert_value(ret == 0, __FILE__, __LINE__);

			{
				/*
				 * Test area
				 */

			}
			retval = 0;
			SWSWI_E_DEBUG("");
			break;
		}
		SWSWI_E_DEBUG("");
		oldoffset = offset;
		name = xformat_get_next_dirent(xformat, &st);
		offset = uxfio_lseek(ifd, (off_t)0, SEEK_CUR);
		SWSWI_E_DEBUG("");
	}

	SWSWI_E_DEBUG("");

	swi_recurse_swi_tree(swi, (char *)(NULL), swi_vbase_set_verbose_level, (void*)(&(swi->verboseM)));
	swi_recurse_swi_tree(swi, (char *)(NULL), swi_vbase_update, NULL);
	ret = swi_recurse_swi_tree(swi, (char *)(NULL), swi_vbase_generate_swverid, NULL);
	if (ret) {
		if (retval == 0) retval = -1;
	}
	swi->swi_pkgM->is_minimal_layoutM = swpath_get_is_minimal_layout(swpath);
	strob_close(tmp);
	return retval;
}

SWI_PRODUCT *
swi_package_get_product(SWI_PACKAGE * swi_pkg, int index)
{
	SWI_PRODUCT * ret;
	ret = swi_pkg->swi_coM[index];
	return ret;
}


SWI_XFILE *
swi_product_get_fileset(SWI_PRODUCT * swi_prod, int index)
{
	SWI_XFILE * ret;
	ret = swi_prod->swi_coM[index];
	return ret;
}

int
swi_product_has_control_file(SWI_PRODUCT * swi_prod, char * control_file_name)
{
	int ret;
	ret = swi_xfile_has_posix_control_file(swi_prod->pfilesM,
		control_file_name);
	return ret;
}

SWI_CONTROL_SCRIPT *
swi_product_get_control_script_by_tag(SWI_PRODUCT * prod, char * tag)
{
	SWI_CONTROL_SCRIPT * ret; 
	ret = swi_xfile_get_control_script_by_tag(prod->pfilesM, tag);
	return ret;
}

SWI_CONTROL_SCRIPT *
swi_get_control_script_by_swsel(SWI * swi, char * swsel, char * script_tag)
{
	/*
	 * 'swsel' *      is software selection
	 */



	return NULL;
}

int
swi_recurse_swi_tree(SWI * swi, char * sw_selections, int (*payload)(void*, void*), void * uptr)
{
	int i;
	int j;
	SWI_PACKAGE * package;
	SWI_PRODUCT * product;
	SWI_XFILE * fileset;
	int ret;
	int retval = 0;

	package = swi->swi_pkgM;
	for(i=0; i<SWI_MAX_OBJ; i++) {
		product = package->swi_coM[i];
		if (product) {
			if (payload) {
				ret = (*payload)((void*)(product), uptr);
				if (ret) retval++;
			}
			for(j=0; j<SWI_MAX_OBJ; j++) {
				fileset = product->swi_coM[j];
				if (fileset) {
					if (payload) {
						ret = (*payload)((void*)(fileset), uptr);
						if (ret) retval++;
					}
				} else break;
			}
		} else break;
	}
	return retval;
}

SWI_PRODUCT *
swi_find_product_by_swsel(SWI_PACKAGE * parent, char * swsel)
{
	SWI_BASE * base;
	base = find_object_by_swsel(parent, swsel);
	if (!base) return (SWI_PRODUCT*)base;
	swi_base_assert(base);
	SWLIB_ASSERT(base->type_idM == SWI_I_TYPE_PROD); 	
	return (SWI_PRODUCT*)(base);
}

SWI_XFILE *
swi_find_fileset_by_swsel(SWI_PRODUCT *  parent, char * swsel)
{
	SWI_BASE * base;
	base = find_object_by_swsel(parent, swsel);
	if (!base) return (SWI_XFILE*)base;
	swi_base_assert(base);
	SWLIB_ASSERT(base->type_idM == SWI_I_TYPE_XFILE); 	
	SWLIB_ASSERT(((SWI_XFILE*)base)->typeM == SWI_XFILE_TYPE_FILESET); 	
	return (SWI_XFILE*)(base);
}

void
swi_get_uts_attributes_from_current(SWI * swi, SWUTS * uts, SWHEADER * swheader)
{
	char * value;	

	value = swheader_get_single_attribute_value(swheader, SW_A_os_name);
	if (value) {
		swuts_store_value(uts, uts->sysnameM, value);
	} else {
		swuts_store_value(uts, uts->sysnameM, "*");
	}	

	value = swheader_get_single_attribute_value(swheader, SW_A_os_version);
	if (value) {
		swuts_store_value(uts, uts->versionM, value);
	} else {
		swuts_store_value(uts, uts->versionM, "*");
	}	

	value = swheader_get_single_attribute_value(swheader, SW_A_os_release);
	if (value) {
		swuts_store_value(uts, uts->releaseM, value);
	} else {
		swuts_store_value(uts, uts->releaseM, "*");
	}	

	value = swheader_get_single_attribute_value(swheader, SW_A_machine_type);
	if (value) {
		swuts_store_value(uts, uts->machineM, value);
	} else {
		swuts_store_value(uts, uts->machineM, "*");
	}	
	return;
}

int
swi_do_decode(SWI * swi, SWUTIL * swutil,
	int target_fd1,
	int source_fd0,
	char * target_path,
	char * source_path,
	VPLOB * swspecs,
	char * target_host,
	struct extendedOptions * opta,
	int is_seekable,
	int do_debug_events,
	int verboseG,
	struct sw_logspec * g_logspec,
	int uinfile_open_flags
	)
{
	int ret;
	int ifd;
	int retval;
	XFORMAT * xformat;
	SWPATH * swpath;
	UINFORMAT * uinformat;
	SWVARFS * swvarfs;
	char * rpm_newname;
	int format;
	int flags;

	SWLIB_ASSERT(source_fd0 >= 0);
	swlib_doif_writef(verboseG, SWC_VERBOSE_IDB,
					g_logspec, swutil->swu_efdM, 
					"run audit: start setup_xformat\n");

	format = arf_ustar;

	/* Create the xformat object */
        xformat = xformat_open( -1 /* STDIN_FILENO */, -1 /* target_fd1 */, format);

	/* FIXME  the open policy described by flags may should be
	   forced up a level so the top level utility can
	   control the policy */

	if (uinfile_open_flags < 0) {
		flags = UINFILE_DETECT_FORCEUXFIOFD |
			UINFILE_DETECT_UNCPIO |
			UINFILE_DETECT_IEEE;
	} else {
		flags = uinfile_open_flags;
	}
	
	/* Now, open the package */

	xformat = swutil_setup_xformat(swutil,
			xformat,
			source_fd0,
			source_path,
			opta,
			is_seekable,
			verboseG,
			g_logspec,
			flags);

	if (xformat == (XFORMAT*)NULL) {
		return -1;
	}
	
	/* The package is now opened and partially decoded */

	swlib_doif_writef(verboseG, SWC_VERBOSE_IDB2, g_logspec, swutil->swu_efdM, 
				"run audit: finished setup_xformat\n");

	xformat_set_ofd(xformat, target_fd1);

	swlib_doif_writef(verboseG, SWC_VERBOSE_IDB2, g_logspec, swutil->swu_efdM, 
			"run audit: starting swlib_audit_distribution\n");

	swvarfs = xformat_get_swvarfs(xformat);
	uinformat = swvarfs_get_uinformat(swvarfs);
	swpath = uinfile_get_swpath(uinformat);
        swpath_reset(swpath);

	xformat_set_tarheader_flag(xformat, TARU_TAR_FRAGILE_FORMAT, 1);
	xformat_set_tarheader_flag(xformat, TARU_TAR_RETAIN_HEADER_IDS, 1);

	/*
	 * If translating an RPM, don't install the RPMFILE_CONFIG files
	 */
	if (uinfile_get_ztype(uinformat) == UINFILE_COMPRESSED_RPM) {
		/*
		 * we'er installing an RPM, yeah!!! ;)
		 */
		set_opta(opta, SW_E_swbis_install_volatile, "true");
		rpm_newname = get_opta(opta, SW_E_swbis_volatile_newname);
		if (
			swextopt_is_option_set(SW_E_swbis_volatile_newname, opta) == 0 &&
			(!rpm_newname || !strlen(rpm_newname))
		) {
			set_opta(opta, SW_E_swbis_volatile_newname, ".rpmnew");
		} else {
			;
			/*
			 * Use the one the user set.
			 */
		}
	}

	swi->xformatM = xformat; 
	swi->swvarfsM = swvarfs; 
	swi->uinformatM = uinformat;
	swi->swpathM = swpath;   
	swi->verboseM = verboseG;
	if (target_host) {
		swi->swi_pkgM->target_hostM = strdup(target_host);
	} else {
		swi->swi_pkgM->target_hostM = strdup("localhost");
	}	
	ifd = xformat_get_ifd(xformat);	
	swi->optaM = (void*)opta;
	/* swi->swc_idM = SWC_U_I; */
	swi->debug_eventsM = do_debug_events;
	
	/*
	 * Decode the catalog section.
	 */
	ret = swi_decode_catalog(swi);

	/*
	 * Set the auto disable of the memory cache.
	 * This will turn off memory cache as soon as the
	 * file advances beyond the previous farthest point
	 */
	swvarfs_uxfio_fcntl(swvarfs, UXFIO_F_ARM_AUTO_DISABLE, 1);

	/*
	 * Now seek back to the beginning of the package.
	 */
	if (uxfio_lseek(ifd, 0, SEEK_SET) != 0) {
		fprintf(stderr, "uxfio_lseek error: %s : %d\n", __FILE__, __LINE__);
		exit(1);
	}

        swpath_reset(swpath);
	if (ret) {
		/*
		* error, swi_decode_catalog failed
		*/
		retval = -1;
		swi = (SWI*)(NULL);
	} else {
		retval = 0;
	}
	return retval;
}
