Blame IbaTools/opaxmlextract/opaxmlextract.c

Packit 857059
/* BEGIN_ICS_COPYRIGHT7 ****************************************
Packit 857059
Packit 857059
Copyright (c) 2015-2017, Intel Corporation
Packit 857059
Packit 857059
Redistribution and use in source and binary forms, with or without
Packit 857059
modification, are permitted provided that the following conditions are met:
Packit 857059
Packit 857059
    * Redistributions of source code must retain the above copyright notice,
Packit 857059
      this list of conditions and the following disclaimer.
Packit 857059
    * Redistributions in binary form must reproduce the above copyright
Packit 857059
      notice, this list of conditions and the following disclaimer in the
Packit 857059
      documentation and/or other materials provided with the distribution.
Packit 857059
    * Neither the name of Intel Corporation nor the names of its contributors
Packit 857059
      may be used to endorse or promote products derived from this software
Packit 857059
      without specific prior written permission.
Packit 857059
Packit 857059
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 857059
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 857059
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 857059
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
Packit 857059
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 857059
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit 857059
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit 857059
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit 857059
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 857059
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 857059
Packit 857059
** END_ICS_COPYRIGHT7   ****************************************/
Packit 857059
Packit 857059
/* [ICS VERSION STRING: unknown] */
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * File: opaxmlextract.c
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	This file implements the opaxmlextract program.  opaxmlextract takes
Packit 857059
 *	well-formed XML as input, extracts element values as specified by user
Packit 857059
 *	input, and outputs data as lines (records) of data in CSV format.
Packit 857059
 *
Packit 857059
 *	opaxmlextract uses XML Lib to parse the XML.  It uses the folowing library
Packit 857059
 *	functions:
Packit 857059
 *	  IXmlParseFile()
Packit 857059
 *
Packit 857059
 *	opaxmlextract implements the following call-backs (handlers):
Packit 857059
 *	  IXML_START_TAG_FUNC()
Packit 857059
 *	  IXML_END_TAG_FUNC()
Packit 857059
 *
Packit 857059
 *	opaxmlextract takes 2 types of element names as input from the user - elements
Packit 857059
 *	to be extracted, and those for which extraction is to be suppressed.  Both
Packit 857059
 *	types of elements are stored in the Element Table (tbElements[]).  As
Packit 857059
 *	opaxmlextract processes the XML (through the call-backs), it saves the values
Packit 857059
 *	of elements to be extracted.  opaxmlextract outputs a record containing those
Packit 857059
 *	values under the following conditions:
Packit 857059
 *	  1 or more elements being extracted and containing a non-null value go out
Packit 857059
 *	    of scope (the element containing those elements is ended)
Packit 857059
 *	  An element changes value while it is in scope
Packit 857059
 *
Packit 857059
 *	During operation, opaxmlextract maintains the hierarchical "level" at which
Packit 857059
 *	it is extracting (top-most level is 1).  Each nested element increases the
Packit 857059
 *	level by 1.  opaxmlextract performs extraction on a (specified) element
Packit 857059
 *	regardless of the level at which the element is found.
Packit 857059
 *
Packit 857059
 *	When an element is specified for suppression then no extraction will be
Packit 857059
 *	performed during the extent of that element (begin through end).
Packit 857059
 *	Suppression is maintained for elements specified inside the suppressed
Packit 857059
 *	element, even if those elements have extraction specified.  Suppressed
Packit 857059
 *	elements can be nested - opaxmlextract will resume extraction after the
Packit 857059
 *	outermost suppressed element is ended.
Packit 857059
 *
Packit 857059
 *	Element names for extraction or suppression can be made context sensitive
Packit 857059
 *	with an enclosing element name using syntax 'elem1.elem2'.  elem2 will
Packit 857059
 *	be extracted (or extraction will be suppressed) when elem2 is enclosed
Packit 857059
 *	by elem1.  The wildcard handling capability of XML Lib allows '*' to
Packit 857059
 *	be specified as all or part of an element name.  The following are valid:
Packit 857059
 *	        *.elem3  -  elem3 enclosed by any sequence of elements
Packit 857059
 *	                    (elem1.elem3 or elem1.elem2.elem3)
Packit 857059
 *	  elem1.*.elem3  -  elem3 enclosed by elem1 with any number of (but at
Packit 857059
 *	                    least 1) intermediate elements.
Packit 857059
 *
Packit 857059
 *	opaxmlextract prepends any entered element name not containing '*'
Packit 857059
 *	(anywhere) with '*.'.
Packit 857059
 *
Packit 857059
 *	NOTES:
Packit 857059
 *	opaxmlextract performs extraction using XML Lib without maintaining
Packit 857059
 *	its own stack of elements or element values.  Therefore it has the
Packit 857059
 *	following characteristics:
Packit 857059
 *	  Enclosing elements cannot contain values;
Packit 857059
 *
Packit 857059
 *	  If an element name specification is such that the element can be
Packit 857059
 *	  extracted at multiple levels within the same context (enclosing
Packit 857059
 *	  element), then when the inner-most element specification ends,
Packit 857059
 *	  the element value becomes null (it does not revert to the outer
Packit 857059
 *	  value).
Packit 857059
 */
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * INCLUDES
Packit 857059
 */
Packit 857059
Packit 857059
#include <stddef.h>
Packit 857059
#include <stdio.h>
Packit 857059
#include <stdlib.h>
Packit 857059
#include <unistd.h>
Packit 857059
#include <string.h>
Packit 857059
#include <iba/ipublic.h>
Packit 857059
#include <getopt.h>
Packit 857059
#include "ixml.h"
Packit 857059
#include "fnmatch.h"
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * DEFINES
Packit 857059
 */
Packit 857059
#define ALLOW_MULTI_MATCH		1		// allow 1 tag to match mult elements
Packit 857059
#define SUPPRESS_AND_EXTRACT	0		// allow 1 tag to suppress and extract
Packit 857059
										// this option not fully implemented
Packit 857059
										// procElementEnd would need more work
Packit 857059
Packit 857059
#define OK  0
Packit 857059
#define ERROR (-1)
Packit 857059
Packit 857059
#define NAME_PROG  "opaxmlextract"		// Program name
Packit 857059
#define MAX_PARAMS_FILE  512			// Max number of param file parameters
Packit 857059
#define MAX_ELEMENTS  100				// Max number of elements parsable
Packit 857059
#define MAX_LEVEL_PARSE  MAX_ELEMENTS	// Max parsing level
Packit 857059
#define MAX_DELIMIT_CHARS  16			// Max size of delimiter string
Packit 857059
#define MAX_INPUT_BUF  8192				// Max size of input buffer
Packit 857059
#define MAX_PARAM_BUF  8192				// Max size of parameter file
Packit 857059
#define MAX_FILENAME_CHARS  256			// Max size of file name
Packit 857059
#define WHITE_SPACE  " \t\r\n"			// White space characters
Packit 857059
#define OPTION_LEN 2			// string length of an option(eg. -P)
Packit 857059
Packit 857059
// Element table entry, elements selected by user and present parsed value
Packit 857059
typedef struct 
Packit 857059
{
Packit 857059
	char	*pName;						// Element name
Packit 857059
	char	*pAttrName;					// optional Attribute Name
Packit 857059
	char	*pAttrValue;				// optional Attribute Value
Packit 857059
	int		lenValue;					// Length of element value
Packit 857059
										//   < 0 : pValue alloc'd but not in use
Packit 857059
	char	*pValue;					// Element value
Packit 857059
	int		flags;						// Flags (see ELEM_xxx below)
Packit 857059
	int		level;						// Element nesting level (0 - not open)
Packit 857059
} ELEMENT_TABLE_ENTRY;
Packit 857059
Packit 857059
// Element table flags:
Packit 857059
#define ELEM_NAMEPREPEND  0x80			// Data prepended to element name
Packit 857059
Packit 857059
// list of elements which a given tag matched and the attribute value
Packit 857059
// which the element selected.  This is generated by the start tag handler
Packit 857059
// and used by the end tag handler for a given "matched" tag
Packit 857059
typedef struct
Packit 857059
{
Packit 857059
	int		ix;							// element table index
Packit 857059
	int		lenAttrValue;				// length of value
Packit 857059
	char	*pAttrValue;				// value, NULL if not outputting attr
Packit 857059
} ELEMENT_LIST_ENTRY;
Packit 857059
Packit 857059
typedef struct
Packit 857059
{
Packit 857059
	int		numElements;			// number of entrys in list
Packit 857059
	ELEMENT_LIST_ENTRY Elements[1];	// variable length list
Packit 857059
} ELEMENT_LIST;
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * LOCAL FUNCTION PROTOTYPES
Packit 857059
 */
Packit 857059
Packit 857059
int delWsLead(char *pStr);
Packit 857059
int delWsTrail(char *pStr);
Packit 857059
void dispExtractionRecord();
Packit 857059
void dispHeaderRecord(int argc, char ** argv);
Packit 857059
void errUsage(void);
Packit 857059
int findElement(int start, const char *pElement, const char **pAttrib,
Packit 857059
				char **pValue, int *length);
Packit 857059
int findElementDup(const ELEMENT_TABLE_ENTRY *pElement);
Packit 857059
void getRecu_opt( int argc, char ** argv, const char *pOptShort,
Packit 857059
	struct option tbOptLong[] );
Packit 857059
void *procElementBeg(IXmlParserState_t *pParserState, void *pParent, const char **ppAttrib);
Packit 857059
void procElementEnd( IXmlParserState_t *pParserState, const IXML_FIELD *pField,
Packit 857059
	void *pObject, void *pParent, XML_Char *pContent, unsigned length,
Packit 857059
	boolean flValid );
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * GLOBAL VARIABLES
Packit 857059
 */
Packit 857059
Packit 857059
int		g_exitstatus  = 0;
Packit 857059
int		g_verbose  = 0;
Packit 857059
int		g_quiet  = 0;
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * LOCAL VARIABLES
Packit 857059
 */
Packit 857059
Packit 857059
int  levelParse  = 0;					// Parse nesting level
Packit 857059
int  numElementsTable  = 0;				// Number of elements in tbElements[]
Packit 857059
int  numElementsExtract  = 0;			// Number of elements to extract
Packit 857059
int  ctElementsSuppress  = 0;			// Count of suppress elements being parsed
Packit 857059
int  flElementChangeLast = FALSE;		// tbElement[] value change flag (last line)
Packit 857059
int  flElementChange  = FALSE;			// tbElement[] value change flag
Packit 857059
int  flHeaderOutput  = TRUE;			// Header output flag
Packit 857059
XML_Parser  pParser  = NULL;			// Pointer to expat parser object
Packit 857059
Packit 857059
FILE  * hFileInput  = NULL;				// Input file handle (default stdin)
Packit 857059
										// Input file name (default stdin)
Packit 857059
char  nameFileInput[MAX_FILENAME_CHARS + 1]  = "stdin";
Packit 857059
uint32  fvDebugProg  = 0;			// Debug/Trace variable as:
Packit 857059
										//  0MMM MMMM NNNN NNNN  SSSS 21RC SIEB SNEB
Packit 857059
Packit 857059
// Command line option table, each has a short and long flag name
Packit 857059
static const char* tbShortOptions="#vHe:s:X:P:d:Z:";
Packit 857059
struct option tbOptions[] =
Packit 857059
{
Packit 857059
	// Basic controls
Packit 857059
	{ "help", no_argument, NULL, 'h' },
Packit 857059
	{ "verbose", no_argument, NULL, 'v' },
Packit 857059
	{ "extract", required_argument, NULL, 'e' },
Packit 857059
	{ "suppress", required_argument, NULL, 's' },
Packit 857059
	{ "infile", required_argument, NULL, 'X' },
Packit 857059
	{ "pfile", required_argument, NULL, 'P' },
Packit 857059
	{ "delimit", required_argument, NULL, 'd' },
Packit 857059
	{ "noheader", no_argument, NULL, 'H' },
Packit 857059
	{ "debug", required_argument, NULL, 'Z' },
Packit 857059
	{ 0 }
Packit 857059
};
Packit 857059
Packit 857059
// Element table; contains information about each element of interest.
Packit 857059
//  Elements to be extracted are contained at the beginning of the table
Packit 857059
//  (0 - numElementsExtract-1); elements for which extraction is suppressed
Packit 857059
//  are contained at the end of the table
Packit 857059
//  (numElementsExtract - numElementsTable-1).
Packit 857059
ELEMENT_TABLE_ENTRY  tbElements[MAX_ELEMENTS + 1];
Packit 857059
Packit 857059
// IXML_FIELD table; contains information for the XML Lib parser.  For
Packit 857059
// purposes of opaxmlextract, a call-back on every start tag and end tag
Packit 857059
// is required; therefore IXML_FIELD tag is set to "*" and format to 'w'.
Packit 857059
IXML_FIELD  tbFields[] =
Packit 857059
{
Packit 857059
	{tag:"*", format:'w', subfields:tbFields, start_func:procElementBeg,
Packit 857059
		end_func:procElementEnd},
Packit 857059
	{NULL}
Packit 857059
};
Packit 857059
Packit 857059
// Delimiter string buffer
Packit 857059
char  bfDelimit[MAX_DELIMIT_CHARS + 1] = ";";
Packit 857059
Packit 857059
// Input buffer
Packit 857059
char  bfInput[MAX_INPUT_BUF];
Packit 857059
Packit 857059
void *mymalloc(size_t size, const char* desc)
Packit 857059
{
Packit 857059
	void *ret = malloc(size);
Packit 857059
	if (! ret)
Packit 857059
	{
Packit 857059
		fprintf(stderr, NAME_PROG ": Unable to Allocate %s Memory\n", desc);
Packit 857059
		exit(1);
Packit 857059
	}
Packit 857059
	return ret;
Packit 857059
}
Packit 857059
Packit 857059
void *myrealloc(void* ptr, size_t size, const char* desc)
Packit 857059
{
Packit 857059
	void *ret = realloc(ptr, size);
Packit 857059
	if (! ret)
Packit 857059
	{
Packit 857059
		fprintf(stderr, NAME_PROG ": Unable to Re-Allocate %s Memory\n", desc);
Packit 857059
		exit(1);
Packit 857059
	}
Packit 857059
	return ret;
Packit 857059
}
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * delWsLead()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Delete leading white space from a string.  White space is defined by the
Packit 857059
 *	string WHITE_SPACE.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	   pStr - Pointer to string from which to delete leading white space
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	ERROR - pStr NULL
Packit 857059
 *	   OK - white space deleted, no white space to delete
Packit 857059
 */
Packit 857059
int delWsLead(char *pStr)
Packit 857059
{
Packit 857059
	int		nChar;
Packit 857059
	char	*pChar;
Packit 857059
Packit 857059
	if (!pStr)
Packit 857059
		return (ERROR);
Packit 857059
Packit 857059
	nChar = strspn(pStr, WHITE_SPACE);
Packit 857059
	if (nChar != 0)
Packit 857059
	{
Packit 857059
		pChar = pStr + nChar;
Packit 857059
		memmove(pStr, pChar, strlen(pChar) + 1);
Packit 857059
	}
Packit 857059
Packit 857059
	return (OK);
Packit 857059
Packit 857059
}	// End of delWsLead()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * delWsTrail()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Delete trailing white space from a string.  White space is defined by the
Packit 857059
 *	string WHITE_SPACE.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	   pStr - Pointer to string from which to delete trailing white space
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	ERROR - pStr NULL
Packit 857059
 *	   OK - white space deleted, no white space to delete
Packit 857059
 */
Packit 857059
int delWsTrail(char *pStr)
Packit 857059
{
Packit 857059
	int		nChar;
Packit 857059
	char	*pChar;
Packit 857059
Packit 857059
	if (!(pChar = pStr))
Packit 857059
		return (ERROR);					// pStr is NULL
Packit 857059
Packit 857059
	while (TRUE)
Packit 857059
	{
Packit 857059
		// Find next non-white space char
Packit 857059
		nChar = strspn(pChar, WHITE_SPACE);
Packit 857059
		if (pChar[nChar])
Packit 857059
		{
Packit 857059
			// Find next white space char
Packit 857059
			pChar += nChar;
Packit 857059
			pChar += strcspn(pChar, WHITE_SPACE);
Packit 857059
			if (!*pChar)
Packit 857059
				break;				// No trailing white space
Packit 857059
		}
Packit 857059
Packit 857059
		// Found first white space char after last non-white space char
Packit 857059
		else
Packit 857059
		{
Packit 857059
			*pChar = 0;
Packit 857059
			break;
Packit 857059
		}
Packit 857059
Packit 857059
	}	// End of while (TRUE)
Packit 857059
Packit 857059
	return (OK);
Packit 857059
Packit 857059
}	// End of delWsTrail()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * dispExtractionRecord()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Display (output) 1 record of extraction data if element change flag
Packit 857059
 *	indicates an element has changed since the last output.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	none
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	none
Packit 857059
 */
Packit 857059
void dispExtractionRecord()
Packit 857059
{
Packit 857059
	int		ix;							// Loop index
Packit 857059
Packit 857059
	// Check element change flag
Packit 857059
	if (!flElementChangeLast)
Packit 857059
		return;
Packit 857059
Packit 857059
	// Output extraction record: element values
Packit 857059
	for (ix = 0; ix < numElementsExtract; ix++)
Packit 857059
	{
Packit 857059
		(void)delWsTrail(tbElements[ix].pValue);
Packit 857059
Packit 857059
		if (ix > 0)
Packit 857059
			printf("%s", bfDelimit);
Packit 857059
Packit 857059
		printf("%s", tbElements[ix].pValue ? tbElements[ix].pValue : "" );
Packit 857059
	}
Packit 857059
	printf("\n");
Packit 857059
	flElementChangeLast = FALSE;
Packit 857059
Packit 857059
}	// End of dispExtractionRecord()
Packit 857059
Packit 857059
void printElement(FILE *f, ELEMENT_TABLE_ENTRY *pElement, int verbose)
Packit 857059
{
Packit 857059
	// Output complete name string if verbose or name not prepended
Packit 857059
	if (verbose || !(pElement->flags & ELEM_NAMEPREPEND))
Packit 857059
		fprintf(f, "%s", pElement->pName);
Packit 857059
	else
Packit 857059
		fprintf(f, "%s", &pElement->pName[2]);
Packit 857059
	if (pElement->pAttrName)
Packit 857059
	{
Packit 857059
		fprintf(f, ":%s", pElement->pAttrName);
Packit 857059
		if (pElement->pAttrValue)
Packit 857059
			fprintf(f, ":%s", pElement->pAttrValue);
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * dispHeaderRecord()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Display (output) header line containing names of elements extracted.  This
Packit 857059
 *	line preceeds the extraction data.  If verbose is set, preceed the header
Packit 857059
 *	line with a line containing the program name and command line options.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	argc, argv - Inputs to main()
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	none
Packit 857059
 */
Packit 857059
void dispHeaderRecord(int argc, char ** argv)
Packit 857059
{
Packit 857059
	int		ix;							// Loop index
Packit 857059
Packit 857059
	// Output header record only if output enabled
Packit 857059
	if (flHeaderOutput)
Packit 857059
	{
Packit 857059
		// Output element names as a header
Packit 857059
		for (ix = 0; ix < numElementsExtract; ix++)
Packit 857059
		{
Packit 857059
			if (ix > 0)
Packit 857059
				printf("%s", bfDelimit);
Packit 857059
Packit 857059
			printElement(stdout,&tbElements[ix], g_verbose);
Packit 857059
		}
Packit 857059
		printf("\n");
Packit 857059
	}
Packit 857059
Packit 857059
}	// End of dispHeaderRecord()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * errUsage()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Output information about program usage and parameters.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	none
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	none
Packit 857059
 */
Packit 857059
void errUsage(void)
Packit 857059
{
Packit 857059
	fprintf(stderr, "Usage: " NAME_PROG " [-v][-H][-d delimiter][-e element][-s element]\n");
Packit 857059
	fprintf(stderr, "                        [-X input_file] [-P param_file]\n");
Packit 857059
	fprintf(stderr, "  -e/--extract element      - name of an XML element to extract\n");
Packit 857059
	fprintf(stderr, "                              can be used multiple times\n");
Packit 857059
	fprintf(stderr, "                              elements can be nested in any order, but will\n");
Packit 857059
	fprintf(stderr, "                              be output in the order specified\n");
Packit 857059
	fprintf(stderr, "                              optionally an attribute or\n");
Packit 857059
	fprintf(stderr, "                              attribute and value can be specified\n");
Packit 857059
	fprintf(stderr, "                              -e element\n");
Packit 857059
	fprintf(stderr, "                              -e element:attrName\n");
Packit 857059
	fprintf(stderr, "                              -e element:attrName:attrValue\n\n");
Packit 857059
	fprintf(stderr, "                              Note that elements can be compound values\n");
Packit 857059
	fprintf(stderr, "                              separated by a dot. For example,\n");
Packit 857059
	fprintf(stderr, "                              'Switches.Node' is a Node element contained\n"); 
Packit 857059
	fprintf(stderr, "                              within a Switches element.\n\n"); 
Packit 857059
	fprintf(stderr, "                              If its desired to output the attribute value as\n");
Packit 857059
	fprintf(stderr, "                              opposed to the element value, a specification such\n");
Packit 857059
	fprintf(stderr, "                              as '-e FIs.Node:id' can be used, which will return\n");
Packit 857059
	fprintf(stderr, "                              the value of the id attribute of any Node elements\n");
Packit 857059
	fprintf(stderr, "                              within FIs element. If desired a specific element\n");
Packit 857059
	fprintf(stderr, "                              can be selected by its attribute value, such as\n");
Packit 857059
	fprintf(stderr, "                              '-e MulticastFDB.Value:LID:0xc000', which will\n");
Packit 857059
	fprintf(stderr, "                              return the value of the Value element within\n");
Packit 857059
	fprintf(stderr, "                              Multicast FDB element where the Value element has\n");
Packit 857059
	fprintf(stderr, "                              an attribute of LID with a value of 0xc000.\n\n");
Packit 857059
Packit 857059
#if ALLOW_MULTI_MATCH
Packit 857059
	fprintf(stderr, "                              A given element can be specified multiple\n");
Packit 857059
	fprintf(stderr, "                              times each with a different AttrName or attrValue\n");
Packit 857059
#else
Packit 857059
	fprintf(stderr, "                              a given element can be specified only once\n");
Packit 857059
#endif
Packit 857059
	fprintf(stderr, "  -s/--suppress element     - name of XML element to suppress extraction\n");
Packit 857059
	fprintf(stderr, "                              can be used multiple times, order does not matter\n");
Packit 857059
	fprintf(stderr, "                              supports same syntaxes as -e\n");
Packit 857059
	fprintf(stderr, "  -d/--delimit delimiter    - delimiter output between element names and values\n");
Packit 857059
	fprintf(stderr, "                              default is semicolon\n");
Packit 857059
	fprintf(stderr, "  -X/--infile input_file    - parse XML in input_file\n");
Packit 857059
	fprintf(stderr, "  -P/--pfile param_file     - read command parameters from param_file\n");
Packit 857059
	fprintf(stderr, "  -H/--noheader             - do not output element name header record\n");
Packit 857059
	fprintf(stderr, "  -v/--verbose              - verbose output: progress reports during extraction\n");
Packit 857059
	fprintf(stderr, "                              and element name prepended wildcard characters\n");
Packit 857059
	fprintf(stderr, "  --help                    - print this usage text.\n");
Packit 857059
Packit 857059
	if (hFileInput && (hFileInput != stdin))
Packit 857059
		fclose(hFileInput);
Packit 857059
Packit 857059
	exit(2);
Packit 857059
}	// End of errUsage()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * findElement()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Find specified element name in element table using wildcard matching.
Packit 857059
 *	Search suppression elements first by starting search at end of table
Packit 857059
 *	and searching toward beginning.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	start - first element in table to check (end of table)
Packit 857059
 *	pElement - Pointer to element name
Packit 857059
 *	ppAttrib - attribute list from tag being processed
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	Index of element table containing element name, else
Packit 857059
 *	ERROR - Element name not found
Packit 857059
 *
Packit 857059
 *	*pValue, *length - if matched a Name:attrName style specifier, the value of
Packit 857059
 *						the attribute matched.  Otherwise NULL,0
Packit 857059
 *						(caller must free *pValue if non-NULL)
Packit 857059
 */
Packit 857059
int findElement(int start, const char *pElement, const char **ppAttrib,
Packit 857059
				char **pValue, int *length)
Packit 857059
{
Packit 857059
	int		ix;
Packit 857059
Packit 857059
	*pValue = NULL;
Packit 857059
	*length = 0;
Packit 857059
	for (ix = start; ix >= 0; ix--)
Packit 857059
	{
Packit 857059
		ELEMENT_TABLE_ENTRY *p = &tbElements[ix];
Packit 857059
		if (!fnmatch(p->pName, pElement, 0))
Packit 857059
	   	{
Packit 857059
			int i;
Packit 857059
			if (! p->pAttrName)
Packit 857059
				return (ix);	// match only on tag name
Packit 857059
Packit 857059
			// search for matching attribute
Packit 857059
			// even index in ppAttrib is name, odd is corresponding value
Packit 857059
			for (i=0; ppAttrib[i]; i += 2)
Packit 857059
			{
Packit 857059
				if (!fnmatch(p->pAttrName, ppAttrib[i], 0))
Packit 857059
				{
Packit 857059
					if (! p->pAttrValue)
Packit 857059
					{
Packit 857059
						// match on Attr Name and return attr value
Packit 857059
						*length = strlen(ppAttrib[i+1]);
Packit 857059
						*pValue = mymalloc(*length+1, "Attribute Value");
Packit 857059
						strcpy(*pValue, ppAttrib[i+1]);
Packit 857059
						return (ix);
Packit 857059
					}
Packit 857059
					// match on attr value
Packit 857059
					if (! fnmatch(p->pAttrValue, ppAttrib[i+1], 0))
Packit 857059
						return (ix);
Packit 857059
				}
Packit 857059
			}
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	return (ERROR);
Packit 857059
Packit 857059
}	// End of findElement()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * findElementDup()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Find specified element name in element table using duplicate (2-way)
Packit 857059
 *	wildcard matching.  Search element table from beginning to end since
Packit 857059
 *	there is no need to check suppression elements first.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	pElement - Pointer to element name
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	Index of element table containing element name, else
Packit 857059
 *	ERROR - Element name not found
Packit 857059
 */
Packit 857059
int findElementDup(const ELEMENT_TABLE_ENTRY *pElement)
Packit 857059
{
Packit 857059
	int		ix;
Packit 857059
Packit 857059
	for (ix = 0; ix < numElementsTable; ix++)
Packit 857059
	{
Packit 857059
		ELEMENT_TABLE_ENTRY *p = &tbElements[ix];
Packit 857059
		if (0 == fnmatch(p->pName, pElement->pName, 0)
Packit 857059
			|| 0 == fnmatch(pElement->pName, p->pName, 0))
Packit 857059
		{
Packit 857059
#if ALLOW_MULTI_MATCH
Packit 857059
			if ((p->pAttrName == NULL) != (pElement->pAttrName == NULL))
Packit 857059
				continue;
Packit 857059
			if (p->pAttrName && pElement->pAttrName)
Packit 857059
			{
Packit 857059
				if ( 0 == fnmatch(p->pAttrName, pElement->pAttrName, 0) ||
Packit 857059
						0 == fnmatch(pElement->pAttrName, p->pAttrName, 0) )
Packit 857059
				{
Packit 857059
					if ((p->pAttrValue == NULL) != (pElement->pAttrValue == NULL))
Packit 857059
						continue;
Packit 857059
					if ( p->pAttrValue && pElement->pAttrValue &&
Packit 857059
							! ( 0 == fnmatch(p->pAttrValue, pElement->pAttrValue, 0) ||
Packit 857059
							0 == fnmatch(pElement->pAttrValue, p->pAttrValue, 0) ) )
Packit 857059
						continue;
Packit 857059
Packit 857059
					return (ix);
Packit 857059
				}
Packit 857059
Packit 857059
				continue;
Packit 857059
			}
Packit 857059
#else
Packit 857059
			// allow different values for same attr because won't both match
Packit 857059
			// the same tag
Packit 857059
			if (p->pAttrName && pElement->pAttrName
Packit 857059
				&& (0 == fnmatch(p->pAttrName, pElement->pAttrName, 0)
Packit 857059
					|| 0 == fnmatch(pElement->pAttrName, p->pAttrName, 0))
Packit 857059
				&& p->pAttrValue && pElement->pAttrValue
Packit 857059
				&& ! (0 == fnmatch(p->pAttrValue, pElement->pAttrValue, 0)
Packit 857059
						|| 0 == fnmatch(pElement->pAttrValue, p->pAttrValue, 0)))
Packit 857059
					continue;
Packit 857059
#endif
Packit 857059
			return (ix);
Packit 857059
Packit 857059
		}	// End of if (0 == fnmatch(p->pName, pElement->pName, 0)
Packit 857059
Packit 857059
	}	// End of for (ix = 0; ix < numElementsTable; ix++)
Packit 857059
Packit 857059
	return (ERROR);
Packit 857059
Packit 857059
}	// End of findElementDup()
Packit 857059
Packit 857059
void getNextField(const char *arg, int extra, char **field, const char **rest)
Packit 857059
{
Packit 857059
	const char *p = rest?strchr(arg, ':'):NULL;
Packit 857059
	int len;
Packit 857059
Packit 857059
	if (p)
Packit 857059
   	{
Packit 857059
		len = (p-arg);
Packit 857059
		*rest = p+1;
Packit 857059
	} else {
Packit 857059
		len = strlen(arg);
Packit 857059
		if (rest)
Packit 857059
			*rest = NULL;
Packit 857059
	}
Packit 857059
	*field = mymalloc(len+1+extra, "Name");
Packit 857059
	strncpy(*field, arg, len);
Packit 857059
	(*field)[len] = '\0';
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * getRecu_opt()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Get command line options (recursively).  Parses command line options
Packit 857059
 *	using short and long option (parameter) definitions.  Parameters (global
Packit 857059
 *	variables) are updated appropriately.  The parameter '-P param_file' which
Packit 857059
 *	takes command line options from a file is also handled.  The -P parameter
Packit 857059
 *	can be used within a parameter file; in such cases the function will call
Packit 857059
 *	itself recursively.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	     argc - Number of input parameters
Packit 857059
 *	     argv - Array of pointers to input parameters
Packit 857059
 *	pOptShort - Pointer to string of short option definitions
Packit 857059
 *	tbOptLong - Array of long option definitions
Packit 857059
 * 
Packit 857059
 * Outputs:
Packit 857059
 *	none
Packit 857059
 */
Packit 857059
void getRecu_opt( int argc, char ** argv, const char *pOptShort,
Packit 857059
	struct option tbOptLong[] )
Packit 857059
{
Packit 857059
	int		ix;
Packit 857059
	int		cOpt;						// Option parsing char                         
Packit 857059
	int		ixOpt;						// Option parsing index
Packit 857059
	int		lenStr;						// String length
Packit 857059
	char	*pChar;						// Pointer to char
Packit 857059
	ELEMENT_TABLE_ENTRY *pElement1,		// Pointers to element entries
Packit 857059
			*pElement2;
Packit 857059
	int		argc_recu;					// Recursive argc
Packit 857059
	char	*argv_recu[MAX_PARAMS_FILE];  // Recursive argv
Packit 857059
	int		optind_recu;				// Recursive optind
Packit 857059
	char	*optarg_recu;				// Recursive optarg
Packit 857059
Packit 857059
	int		ctCharParam;				// Parameter file char count
Packit 857059
	FILE	*hFileParam = NULL;			// Parameter file handle
Packit 857059
	char	nameFileParam[MAX_FILENAME_CHARS +1];  // Parameter file name
Packit 857059
	char	bfParam[MAX_PARAM_BUF + 1];
Packit 857059
Packit 857059
	// Input command line arguments
Packit 857059
	while ((cOpt = getopt_long(argc, argv, pOptShort, tbOptLong, &ixOpt)) != -1)
Packit 857059
    {
Packit 857059
		lenStr = 0;
Packit 857059
        switch (cOpt)
Packit 857059
        {
Packit 857059
		// Verbose
Packit 857059
		case 'v':
Packit 857059
			g_verbose = 1;
Packit 857059
			break;
Packit 857059
Packit 857059
		// Extract element name specification
Packit 857059
		case 'e':
Packit 857059
		// Suppress element name specification
Packit 857059
		case 's':
Packit 857059
			// syntaxes supported:
Packit 857059
			// Name    - match Tag with given name
Packit 857059
			// Name:attr - select attr field of Tag with given name and attr
Packit 857059
			// Name:attr:value - match Tag with given name and attr value
Packit 857059
			// All three components allow "glob" style patterns
Packit 857059
			if (numElementsTable == MAX_ELEMENTS)
Packit 857059
			{
Packit 857059
				fprintf(stderr, NAME_PROG ": Too many Elements\n");
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			else if (!optarg || ! *optarg)
Packit 857059
			{
Packit 857059
				fprintf(stderr, NAME_PROG ": Missing Element\n");
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			else
Packit 857059
			{
Packit 857059
				ELEMENT_TABLE_ENTRY *pElement = &tbElements[numElementsTable];
Packit 857059
				const char *rest;
Packit 857059
Packit 857059
				// Tag Name
Packit 857059
				getNextField(optarg, 2, &pElement->pName, &rest);
Packit 857059
				if (! strchr(optarg, '*'))
Packit 857059
				{
Packit 857059
					// insert *. before string (extra 2 above allowed space)
Packit 857059
					memmove(pElement->pName+2, pElement->pName, strlen(pElement->pName)+1);
Packit 857059
					pElement->pName[0] = '*'; pElement->pName[1] = '.';
Packit 857059
					pElement->flags |= ELEM_NAMEPREPEND;
Packit 857059
				}
Packit 857059
				if (rest) {
Packit 857059
					// optional AttrName
Packit 857059
					if (! *rest) // trailing colon
Packit 857059
					{
Packit 857059
						fprintf(stderr, NAME_PROG ": Attr Name missing: %s\n", optarg);
Packit 857059
						errUsage();
Packit 857059
					}
Packit 857059
					getNextField(rest, 0, &pElement->pAttrName, &rest);
Packit 857059
					if (rest) {
Packit 857059
						// optional AttrValue
Packit 857059
						if (! *rest) // trailing colon
Packit 857059
						{
Packit 857059
							fprintf(stderr, NAME_PROG ": Attr Value missing: %s\n", optarg);
Packit 857059
							errUsage();
Packit 857059
						}
Packit 857059
						getNextField(rest, 0, &pElement->pAttrValue, NULL);
Packit 857059
					}
Packit 857059
				}
Packit 857059
				if ((ix = findElementDup(&tbElements[numElementsTable])) != ERROR)
Packit 857059
				{
Packit 857059
					fprintf(stderr, NAME_PROG ": Duplicate (matching) Element: %s (matches: ", optarg);
Packit 857059
					printElement(stderr, &tbElements[ix], FALSE);
Packit 857059
					fprintf(stderr, ")\n");
Packit 857059
					errUsage();
Packit 857059
				}
Packit 857059
Packit 857059
			}
Packit 857059
Packit 857059
			// If suppress specification, leave at end of tbElements[]
Packit 857059
			if (cOpt == 's')
Packit 857059
				numElementsTable++;
Packit 857059
Packit 857059
			// If extraction specification w/no suppress elements, leave at
Packit 857059
			//  end of tbElements[]
Packit 857059
			else if ((cOpt == 'e') && (numElementsExtract == numElementsTable))
Packit 857059
			{
Packit 857059
				numElementsTable++;
Packit 857059
				numElementsExtract++;
Packit 857059
			}
Packit 857059
Packit 857059
			// If extraction specification w/suppress elements, move extraction
Packit 857059
			//  to end of other extractions
Packit 857059
			else if ((cOpt == 'e') && (numElementsExtract < numElementsTable))
Packit 857059
			{
Packit 857059
				// Swap last element table entry with first suppress element entry
Packit 857059
				//  (NOTE: lenValue, pValue and level are zero, so no swap needed)
Packit 857059
				pElement1 = &tbElements[numElementsExtract++];
Packit 857059
				pElement2 = &tbElements[numElementsTable++];
Packit 857059
Packit 857059
				pChar = pElement1->pName;
Packit 857059
				pElement1->pName = pElement2->pName;
Packit 857059
				pElement2->pName = pChar;
Packit 857059
Packit 857059
				pChar = pElement1->pAttrName;
Packit 857059
				pElement1->pAttrName = pElement2->pAttrName;
Packit 857059
				pElement2->pAttrName = pChar;
Packit 857059
Packit 857059
				pChar = pElement1->pAttrValue;
Packit 857059
				pElement1->pAttrValue = pElement2->pAttrValue;
Packit 857059
				pElement2->pAttrValue = pChar;
Packit 857059
Packit 857059
				lenStr = pElement1->flags;
Packit 857059
				pElement1->flags = pElement2->flags;
Packit 857059
				pElement2->flags = lenStr;
Packit 857059
			}
Packit 857059
Packit 857059
			break;
Packit 857059
Packit 857059
		// Delimiter string specification
Packit 857059
		case 'd':
Packit 857059
			if ( !optarg || ((lenStr = strlen(optarg)) == 0) ||
Packit 857059
					(lenStr > MAX_DELIMIT_CHARS) )
Packit 857059
			{
Packit 857059
				fprintf(stderr, NAME_PROG ": Invalid delimiter size: %d\n", lenStr);
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			strncpy(bfDelimit, optarg, sizeof(bfDelimit)-1);
Packit 857059
			// Ensure null termination
Packit 857059
			bfDelimit[MAX_DELIMIT_CHARS]=0;
Packit 857059
			break;
Packit 857059
Packit 857059
		// Input file specification
Packit 857059
		case 'X':
Packit 857059
			if ( !optarg || ((lenStr = strlen(optarg)) == 0) ||
Packit 857059
					(lenStr > MAX_FILENAME_CHARS) )
Packit 857059
			{
Packit 857059
				fprintf(stderr, NAME_PROG ": Missing Input File Name.\n");
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			else if (hFileInput != stdin)
Packit 857059
			{
Packit 857059
				fprintf( stderr, NAME_PROG ": Multiple Input Files: %s and %s\n",
Packit 857059
					nameFileInput, optarg );
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			strncpy(nameFileInput, optarg, sizeof(nameFileInput)-1);
Packit 857059
			// Ensure null termination
Packit 857059
			nameFileInput[MAX_FILENAME_CHARS]=0;
Packit 857059
			hFileInput = fopen(nameFileInput, "r");
Packit 857059
Packit 857059
			if (!hFileInput)
Packit 857059
			{
Packit 857059
				fprintf( stderr, NAME_PROG ": Unable to Open Input File: %s\n",
Packit 857059
					nameFileInput );
Packit 857059
				perror("");
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
			break;
Packit 857059
Packit 857059
		// Parameter file specification
Packit 857059
		case 'P':
Packit 857059
			if (!optarg || ((lenStr = strlen(optarg)) == 0) ||
Packit 857059
					(lenStr > MAX_FILENAME_CHARS) )
Packit 857059
			{
Packit 857059
				fprintf(stderr, NAME_PROG ": Missing Parameter File Name.\n");
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			// Open parameter file
Packit 857059
			strncpy(nameFileParam, optarg, sizeof(nameFileParam)-1);
Packit 857059
			// Ensure null termination
Packit 857059
			nameFileParam[MAX_FILENAME_CHARS]=0;
Packit 857059
			hFileParam = fopen(nameFileParam, "r");
Packit 857059
Packit 857059
			if (!hFileParam)
Packit 857059
			{
Packit 857059
				fprintf( stderr, NAME_PROG ": Unable to Open Parameter File: %s\n",
Packit 857059
					nameFileParam );
Packit 857059
				perror("");
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			// Read parameter file
Packit 857059
			if (g_verbose)
Packit 857059
				fprintf(stderr, NAME_PROG ": Reading Param File: %s\n", nameFileParam);
Packit 857059
Packit 857059
			ctCharParam = (int)fread(bfParam, 1, MAX_PARAM_BUF, hFileParam);
Packit 857059
Packit 857059
			if (ferror(hFileParam))
Packit 857059
			{
Packit 857059
				fclose(hFileParam);
Packit 857059
				fprintf(stderr, NAME_PROG ": Read Error: %s\n", nameFileParam);
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			if ((ctCharParam == MAX_PARAM_BUF) && !feof(hFileParam))
Packit 857059
			{
Packit 857059
				fclose(hFileParam);
Packit 857059
				fprintf( stderr, NAME_PROG ": Parameter file (%s) too large (> %d bytes)\n",
Packit 857059
					nameFileParam, MAX_PARAM_BUF );
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
Packit 857059
			// Make sure the buffer is null terminated.
Packit 857059
			bfParam[MAX_PARAM_BUF] = 0;
Packit 857059
Packit 857059
			fclose(hFileParam);
Packit 857059
Packit 857059
			if (ctCharParam > 0)
Packit 857059
			{
Packit 857059
				// Parse parameter file into tokens
Packit 857059
				argc_recu = 2;
Packit 857059
				argv_recu[0] = nameFileParam;
Packit 857059
			
Packit 857059
				for (ix = 1; ; ix++, argc_recu++)
Packit 857059
				{
Packit 857059
					if (ix == MAX_PARAMS_FILE)
Packit 857059
					{
Packit 857059
						fprintf( stderr, NAME_PROG ": Parameter file (%s) has too many parameters (> %d)\n",
Packit 857059
							nameFileParam, MAX_PARAMS_FILE );
Packit 857059
						errUsage();
Packit 857059
					}
Packit 857059
Packit 857059
					if ( (argv_recu[ix] = strtok((ix == 1) ? bfParam : NULL, WHITE_SPACE))
Packit 857059
							== NULL )
Packit 857059
					{
Packit 857059
						argc_recu--;
Packit 857059
						break;
Packit 857059
					}
Packit 857059
Packit 857059
					if (!strncmp(argv_recu[ix], "-P", OPTION_LEN))
Packit 857059
					{
Packit 857059
						fprintf( stderr, NAME_PROG ": Parameter file (%s) cannot contain -P option\n", nameFileParam);
Packit 857059
						errUsage();
Packit 857059
					}
Packit 857059
Packit 857059
					if ( (argv_recu[ix] - bfParam + strlen(argv_recu[ix]) + 1) ==
Packit 857059
							ctCharParam )
Packit 857059
						break;
Packit 857059
				}
Packit 857059
Packit 857059
				// Process parameter file parameters
Packit 857059
				if (argc_recu > 1)
Packit 857059
				{
Packit 857059
					optind_recu = optind;	// Save optind & optarg
Packit 857059
					optarg_recu = optarg;
Packit 857059
					optind = 1;   			// Init optind & optarg
Packit 857059
					optarg = NULL;
Packit 857059
					getRecu_opt(argc_recu, argv_recu, pOptShort, tbOptLong);
Packit 857059
					optind = optind_recu;	// Restore optind & optarg
Packit 857059
					optarg = optarg_recu;
Packit 857059
				}
Packit 857059
Packit 857059
			}	// End of if (ctCharParam > 0)
Packit 857059
Packit 857059
			break;
Packit 857059
Packit 857059
		// No Header
Packit 857059
		case 'H':
Packit 857059
			flHeaderOutput = FALSE;
Packit 857059
			break;
Packit 857059
Packit 857059
		// Debug trace specification
Packit 857059
		case 'Z':
Packit 857059
			if (FSUCCESS != StringToUint32(&fvDebugProg, optarg, NULL, 0, TRUE)) {
Packit 857059
				fprintf(stderr, NAME_PROG ": Invalid Debug Setting: %s\n", optarg);
Packit 857059
				errUsage();
Packit 857059
			}
Packit 857059
			break;
Packit 857059
Packit 857059
		case '#':
Packit 857059
		default:
Packit 857059
			errUsage();
Packit 857059
			break;
Packit 857059
Packit 857059
        }	// End of switch (cOpt)
Packit 857059
Packit 857059
    }	// End of while ( ( cOpt = getopt_long( argc, argv,
Packit 857059
Packit 857059
	// Validate command line arguments
Packit 857059
	if (optind < argc)
Packit 857059
	{
Packit 857059
		fprintf(stderr, "%s: invalid argument %s\n", NAME_PROG, argv[optind]);
Packit 857059
		errUsage();
Packit 857059
	}
Packit 857059
Packit 857059
}	// End of getRecu_opt()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * main()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	main function for program.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	argc - Number of input parameters
Packit 857059
 *	argv - Array of pointers to input parameters
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	Exit status 0 - no errors
Packit 857059
 *	Exit status 2 - error (input parameter, resources, file I/O, XML parsing)
Packit 857059
 */
Packit 857059
int main(int argc, char ** argv)
Packit 857059
{
Packit 857059
	int		ix;							// Loop index
Packit 857059
Packit 857059
	// Initialize for extraction
Packit 857059
	hFileInput = stdin;
Packit 857059
Packit 857059
	for (ix = 0; ix < MAX_ELEMENTS; ix++)
Packit 857059
	{
Packit 857059
		tbElements[ix].pName = NULL;
Packit 857059
		tbElements[ix].pAttrName = NULL;
Packit 857059
		tbElements[ix].pAttrValue = NULL;
Packit 857059
		tbElements[ix].lenValue = 0;
Packit 857059
		tbElements[ix].pValue = NULL;
Packit 857059
		tbElements[ix].flags = 0;
Packit 857059
		tbElements[ix].level = 0;
Packit 857059
	}
Packit 857059
	
Packit 857059
	// Get and validate command line arguments
Packit 857059
	getRecu_opt(argc, argv, tbShortOptions, tbOptions);
Packit 857059
Packit 857059
	dispHeaderRecord(argc, argv);
Packit 857059
Packit 857059
	// Output progress report if g_verbose
Packit 857059
	if (g_verbose)
Packit 857059
		fprintf(stderr, NAME_PROG ": Parsing XML buffer\n");
Packit 857059
Packit 857059
	if ( IXmlParseFile(hFileInput, nameFileInput, IXML_PARSER_FLAG_NONE, tbFields, NULL, NULL, NULL, NULL, NULL, NULL) !=
Packit 857059
			FSUCCESS )
Packit 857059
	{
Packit 857059
		fprintf(stderr, NAME_PROG ": XML Parse error\n");
Packit 857059
		exit(1);
Packit 857059
	}
Packit 857059
Packit 857059
	if (hFileInput && (hFileInput != stdin))
Packit 857059
		fclose(hFileInput);
Packit 857059
Packit 857059
	return (g_exitstatus);
Packit 857059
Packit 857059
}	// End of main()
Packit 857059
Packit 857059
void ProcessMatchedElement( ELEMENT_TABLE_ENTRY *pElement, char *pValue,
Packit 857059
	int length, int level )
Packit 857059
{
Packit 857059
	if (!length)
Packit 857059
	{
Packit 857059
		// Existing element value being replaced by NULL
Packit 857059
		if (pElement->lenValue > 0)
Packit 857059
		{
Packit 857059
			dispExtractionRecord();
Packit 857059
			pElement->pValue[0] = 0;
Packit 857059
			pElement->level = level;
Packit 857059
			flElementChange = TRUE;
Packit 857059
		}
Packit 857059
	}
Packit 857059
	else
Packit 857059
	{
Packit 857059
		// Null element value being replaced by new value
Packit 857059
		if (!pElement->lenValue)
Packit 857059
		{
Packit 857059
			// Allocate block of memory x2
Packit 857059
			pElement->pValue = mymalloc(length + length, "Value");
Packit 857059
			strcpy(pElement->pValue, pValue);
Packit 857059
			pElement->lenValue = length + length;
Packit 857059
			pElement->level = level;
Packit 857059
			flElementChange = TRUE;
Packit 857059
		}
Packit 857059
		else if (pElement->lenValue < 0)
Packit 857059
		{
Packit 857059
			if (-pElement->lenValue <= length)
Packit 857059
			{
Packit 857059
				// Reallocate to larger block of memory x2
Packit 857059
				pElement->pValue =
Packit 857059
						myrealloc(pElement->pValue, length + length, "Value");
Packit 857059
				pElement->lenValue = -(length + length);
Packit 857059
			}
Packit 857059
Packit 857059
			strcpy(pElement->pValue, pValue);
Packit 857059
			pElement->lenValue = -pElement->lenValue;
Packit 857059
			pElement->level = level;
Packit 857059
			flElementChange = TRUE;
Packit 857059
		}
Packit 857059
Packit 857059
		else
Packit 857059
		{
Packit 857059
			// Existing element value being replaced by new (non-equal) value
Packit 857059
			if (strcmp(pElement->pValue, pValue))
Packit 857059
			{
Packit 857059
				dispExtractionRecord();
Packit 857059
				if (pElement->lenValue <= length)
Packit 857059
				{
Packit 857059
					// Reallocate to larger block of memory x2
Packit 857059
					pElement->pValue =
Packit 857059
							myrealloc(pElement->pValue, length + length, "Value");
Packit 857059
					pElement->lenValue = length + length;
Packit 857059
				}
Packit 857059
Packit 857059
				strcpy(pElement->pValue, pValue);
Packit 857059
				pElement->level = level;
Packit 857059
				flElementChange = TRUE;
Packit 857059
Packit 857059
			}	// End of if (strcmp(pElement->pValue, pValue))
Packit 857059
Packit 857059
		}	// End of else (else if (pElement->lenValue < 0))
Packit 857059
Packit 857059
	}	// End of else (!length)
Packit 857059
Packit 857059
}	// End of ProcessMatchedElement()
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * procElementBeg()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Process begin element specification.  Check for whether element suppresses
Packit 857059
 *	extraction.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	pParserState - Pointer to IXml parser state
Packit 857059
 *	     pParent - Pointer to element parent
Packit 857059
 *	    ppAttrib - Pointer to pointer to element attribute data
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	none
Packit 857059
 */
Packit 857059
void *procElementBeg(IXmlParserState_t *pParserState, void *pParent, const char **ppAttrib)
Packit 857059
{
Packit 857059
	int		ix;
Packit 857059
	char	*pNameFull;
Packit 857059
	ELEMENT_LIST* pList = NULL;
Packit 857059
	char *pValue;
Packit 857059
	int length;
Packit 857059
Packit 857059
	if (levelParse++ > MAX_LEVEL_PARSE)
Packit 857059
	{
Packit 857059
		fprintf( stderr, NAME_PROG ": Max Parsing Level (%d) Exceeded\n",
Packit 857059
			MAX_LEVEL_PARSE );
Packit 857059
		exit(1);
Packit 857059
	}
Packit 857059
Packit 857059
	pNameFull = (char *)IXmlParserGetCurrentFullTag(pParserState);
Packit 857059
	ix = numElementsTable - 1;
Packit 857059
	do {
Packit 857059
		if ((ix = findElement(ix, pNameFull, ppAttrib, &pValue, &length)) >= 0)
Packit 857059
		{
Packit 857059
#if ! SUPPRESS_AND_EXTRACT
Packit 857059
			if (pList && ix >= numElementsExtract) // Check for suppression Element
Packit 857059
			{
Packit 857059
				int i;
Packit 857059
Packit 857059
				// discard matched extractions; replace with this suppression (below)
Packit 857059
				for (i=0; i<pList->numElements; i++)
Packit 857059
				{
Packit 857059
					if (pList->Elements[i].pAttrValue)
Packit 857059
						free(pList->Elements[i].pAttrValue);
Packit 857059
				}
Packit 857059
				free(pList);
Packit 857059
				pList=NULL;
Packit 857059
			}
Packit 857059
#endif
Packit 857059
			// Process extraction of attribute value immediately so that value
Packit 857059
			//  is available with (potential) extraction values of nested lines
Packit 857059
			if (pValue && ix < numElementsExtract)
Packit 857059
			{
Packit 857059
				dispExtractionRecord();
Packit 857059
				ProcessMatchedElement( &tbElements[ix], pValue, length,
Packit 857059
					levelParse + 1 );
Packit 857059
				free(pValue);
Packit 857059
			}
Packit 857059
Packit 857059
			// Add to pList: extraction of element value
Packit 857059
			//               extraction of element:attribute:value
Packit 857059
			//               any suppression specification
Packit 857059
			else
Packit 857059
			{
Packit 857059
				if (pList)
Packit 857059
				{
Packit 857059
					// sizeof(*pList) includes 1st element
Packit 857059
					pList = myrealloc(pList, sizeof(*pList)
Packit 857059
											+ pList->numElements
Packit 857059
													* sizeof(pList->Elements[0]),
Packit 857059
											"object list");
Packit 857059
				}
Packit 857059
				else
Packit 857059
				{
Packit 857059
					pList = mymalloc(sizeof(*pList), "object list");
Packit 857059
					pList->numElements = 0;
Packit 857059
				}
Packit 857059
				// findElement has malloced pValue as needed
Packit 857059
				pList->Elements[pList->numElements].ix = ix;
Packit 857059
				pList->Elements[pList->numElements].lenAttrValue = length;
Packit 857059
				pList->Elements[pList->numElements].pAttrValue = pValue;
Packit 857059
				pList->numElements++;
Packit 857059
Packit 857059
				// Check for suppression Element
Packit 857059
				if (ix >= numElementsExtract)
Packit 857059
				{
Packit 857059
					ctElementsSuppress++;
Packit 857059
					break;	// no use going past 1st match of a suppressed
Packit 857059
				}
Packit 857059
			}
Packit 857059
Packit 857059
			ix--;
Packit 857059
Packit 857059
		}	// End of if ((ix = findElement(ix, pNameFull, ppAttrib
Packit 857059
Packit 857059
#if ALLOW_MULTI_MATCH
Packit 857059
	} while (ix >= 0);
Packit 857059
#else	/* just use 1st match, like the old code did */
Packit 857059
	} while (0);
Packit 857059
#endif
Packit 857059
Packit 857059
	// return list of elements matched (NULL if none matched)
Packit 857059
	return (void*)pList;
Packit 857059
Packit 857059
}	// End of procElementBeg()
Packit 857059
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 *
Packit 857059
 * procElementEnd()
Packit 857059
 *
Packit 857059
 * Description:
Packit 857059
 *	Process end element specification.  Check for whether element is being
Packit 857059
 *	extracted, whether element suppresses extraction, or neither.  If the
Packit 857059
 *	element being ended is an extraction element and is the outermost enclosing
Packit 857059
 *	element for a group of extraction elements, output an extraction record.
Packit 857059
 *
Packit 857059
 * Inputs:
Packit 857059
 *	pParserState - Pointer to IXml parser state
Packit 857059
 *	      pField - Pointer to field
Packit 857059
 *	     pObject - Pointer to object
Packit 857059
 *	     pParent - Pointer to element parent
Packit 857059
 *	      pValue - Pointer to element value (NULL terminated)
Packit 857059
 *	      length - Length of value
Packit 857059
 *	    ppAttrib - Pointer to pointer to element attribute data
Packit 857059
 *	     flValid - Valid flag
Packit 857059
 *
Packit 857059
 * Outputs:
Packit 857059
 *	none
Packit 857059
 */
Packit 857059
void procElementEnd( IXmlParserState_t *pParserState, const IXML_FIELD *pField,
Packit 857059
	void *pObject, void *pParent, XML_Char *pValue, unsigned length,
Packit 857059
	boolean flValid )
Packit 857059
{
Packit 857059
	int		ix;
Packit 857059
	ELEMENT_TABLE_ENTRY *pElement = NULL;
Packit 857059
	ELEMENT_LIST* pList = (ELEMENT_LIST*)pObject;
Packit 857059
Packit 857059
	if (pList)
Packit 857059
	{
Packit 857059
		// this tag Matched one or more elements
Packit 857059
		int i;
Packit 857059
		for (i=0; i<pList->numElements; i++)
Packit 857059
		{
Packit 857059
			ix = pList->Elements[i].ix;
Packit 857059
			ASSERT(ix >= 0);
Packit 857059
			pElement = &tbElements[ix];
Packit 857059
Packit 857059
			// Check for extracted element
Packit 857059
			if (ix < numElementsExtract)
Packit 857059
			{
Packit 857059
				// Check for suppression, ignore matches within suppression
Packit 857059
				if (ctElementsSuppress == 0)
Packit 857059
				{
Packit 857059
					// matched extraction element
Packit 857059
					if (!pElement->pAttrName || pElement->pAttrValue)
Packit 857059
					{
Packit 857059
						// operate on element value
Packit 857059
						ProcessMatchedElement( pElement, pValue, length,
Packit 857059
							levelParse );
Packit 857059
					}
Packit 857059
Packit 857059
				}	// End of if (ctElementsSuppress == 0)
Packit 857059
Packit 857059
			}	// End of if (ix < numElementsExtract)
Packit 857059
			else
Packit 857059
			{
Packit 857059
				// Suppress extraction element
Packit 857059
				ctElementsSuppress--;
Packit 857059
			}
Packit 857059
Packit 857059
			if (pList->Elements[i].pAttrValue)
Packit 857059
				free(pList->Elements[i].pAttrValue);
Packit 857059
Packit 857059
		}	// End of for (i=0; i<pList->numElements; i++)
Packit 857059
		free(pList);
Packit 857059
Packit 857059
	}	// End of if (pList)
Packit 857059
Packit 857059
	// Merge current element change flag into last change flag
Packit 857059
	if (!ctElementsSuppress)
Packit 857059
		flElementChangeLast |= flElementChange;
Packit 857059
Packit 857059
	flElementChange = FALSE;
Packit 857059
Packit 857059
	// Check for end of element which encloses extracted element(s)
Packit 857059
	for (ix = 0; ix < numElementsExtract; ix++)
Packit 857059
	{
Packit 857059
		if (tbElements[ix].level > levelParse)
Packit 857059
		{
Packit 857059
			dispExtractionRecord();
Packit 857059
			tbElements[ix].lenValue = -tbElements[ix].lenValue;
Packit 857059
			tbElements[ix].pValue[0] = 0;
Packit 857059
		   	tbElements[ix].level = 0;
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	levelParse--;
Packit 857059
Packit 857059
}	// End of procElementEnd()
Packit 857059
Packit 857059
Packit 857059
// End of file
Packit 857059