/*
 * (c) Copyright IBM Corp. 2005 All Rights Reserved
 *
 * Physical Memory Information Module
 *
 * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/**
 * @file parsers.c
 *
 * @brief Basic support for multiple parsers / analyzers of the input data.
 *
 * This part provides the source for the management of the parser functions.
 * The parsers are in a different file, as this only provides the
 * infrastructure to support them. This includes a simple menu interface
 * and the generic menu functions for option selection.
 *
 * @author International Business Machines
 * @author Paul Movall <movall@us.ibm.com>
 *
 * @version Current Version: 1.0
 *
 * @date Current Date: 01/2005
 *
 * @version 0.1, 11/2003: File created by Paul Movall <movall@us.ibm.com>
 * @version 1.0, 01/2005: Miscellaneous cleanup for publish
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>

/** @def PARSERS_C Definition to allow static table of parses to be built
 * and initialized in the parsers.h file. */
#define PARSERS_C
#include "td.h"
#include "parsers.h"

/** @def PARSER_ADDR_MODE Menu selection value to change address analysis
 * between virtual and physical analysis. */
#define PARSER_ADDR_MODE	96

/** @def PARSER_TERSE_MODE Menu selection value to change terse mode
 * between verbose (human readable) and terse (CSV) modes. */
#define PARSER_TERSE_MODE	97

/** @def PARSER_OUT_FILE Menu selection value to change output file. */
#define PARSER_OUT_FILE		98

/** @def PARSER_EXIT Menu selection value to exit the pareser selection. */
#define PARSER_EXIT		99

/**
 * @brief Print out menu help text.
 *
 * This function is only used in interactive mode if an invalid menu
 * selection is made.
 *
 * @param outf Not used.
 *
 * @return None
 *
 * @note The help text is written to stderr.
 */
void print_help(FILE *outf) {
	fprintf(stderr,
		"\nInvalid Selection. Please use one of the numbers above\n");
	fprintf(stderr,
		"or \"99\" to exit.\n");
}

/**
 * @brief Function to change the output file.
 *
 * @return The file pointer to the new output file.
 *
 * @note The input value of "stdout" is checked before opening the
 * output file to insure that if the user wants it to go to stdout
 * it will end up there instead of in a file in the working directory
 * named "stdout".
 */
FILE *change_outfile() {
	char newfilenm[PATH_MAX];
	char *retp;
	FILE *outfp;

	printf("\n\n\nPlease enter new file name: \n");
	retp = fgets(newfilenm, PATH_MAX, stdin);
	/* remove trailing \n */
	newfilenm[strlen(retp) - 1] = '\0';

	if (!strcmp(retp, "stdout")) {
		outfp = stdout;
		strcpy(outfile, "stdout");
	} else {
		outfp = fopen(retp, "w");
		if (outfp < 0) {
			fprintf(stderr, "Error opening output file [%s]. "
				"Using stdout instead.\n",
				retp);
			outfp = stdout;
			strcpy(outfile, "stdout");
		} else {
			strcpy(outfile, retp);
		}
	}

	return(outfp);
}

/**
 * @brief Print the menu of parser selections.
 *
 * @return None
 *
 * @note The menu is written to stdout.
 */
void print_options(void) {
	int i;

	printf("\n\nWorking on file \"%s\"\n\n", infile);

	for (i = 0; i < MAX_PARSERS; i++) {
		printf("\t%2d. %s\n",
		       i, parsers[i].name);
	}
	printf("\n");
	printf("\t%d. Change addressing mode (current is %s)\n",
	       PARSER_ADDR_MODE,
	       virtual ? "virtual" : "physical");
	printf("\t%d. Change terse mode (current is %s)\n",
	       PARSER_TERSE_MODE,
	       terse ? "terse" : "verbose");
	printf("\t%d. Change output file (current is %s)\n",
	       PARSER_OUT_FILE,
	       outfile);
	printf("\t%d. Exit\n",
	       PARSER_EXIT);
	printf("Please enter input: ");
}

/**
 * @brief Manage the selection of which data parsers to run against the data.
 *
 * This function is the main driver of calling the basic data parsers. It is
 * dependent upon the various parser functions and parser selection functions.
 *
 * @param outf The file structure pointer to the output file.
 * @param i_sel Input from user on command line of which parser to run.
 *
 * @return None.
 *
 * @note If the input selection is valid, then the menu is not used and only
 * the selected parser is executed.
 */
void parse_data(FILE *outf, int i_sel) {
	int selection = 0;
	char inbuf[256];
	char *retp;

	if ((i_sel >= 0) &&
	    (i_sel < MAX_PARSERS) ) {
		parsers[i_sel].func(outf);
	} else {

		do {
			print_options();
			retp = fgets(inbuf, 256, stdin);

			selection = atoi(retp);

			if ( (selection >= 0) &&
			     (selection < MAX_PARSERS) ) {
				parsers[selection].func(outf);
			} else if (selection == PARSER_ADDR_MODE) {
				virtual = !virtual;
			} else if (selection == PARSER_TERSE_MODE) {
				terse = !terse;
			} else if (selection == PARSER_OUT_FILE) {
				outf = change_outfile();
			} else if (selection != PARSER_EXIT) {
				print_help(stderr);
			}
		} while (selection != 99);
	}
}

#undef PARSERS_C
