/*
 * +-------------------------------------------------------+
 * |                                                       |
 * |     videogen                                          |
 * |                                                       |
 * |     a simple XFree86 Modeline calculator              |
 * |     (c) 1997-2003, Szabolcs Rumi                      |   
 * |                                                       |
 * |     http://www.dynaweb.hu/opensource/videogen         |
 * |                                                       |
 * |     the videogen package is distributed under the     |
 * |     GNU General Public License Version 2 (GPLv2)      |
 * |                                                       |
 * +-------------------------------------------------------+   
 */





#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"
#include "videogen.h"





arg_opt_t opts[] =
{
			{	"-h",	NULL,	0	},
			{	"-v",	NULL,	0	},
			{	"-q",	NULL,	0	},
			{	"-fb",	NULL,	0	},
			{	"-nfb",	NULL,	0	},
			{	"-nv",	NULL,	0	},
			{	"-nnv",	NULL,	0	},
			{	"-f",	NULL,	0	},
			{	"-m",	NULL,	0	},
			{	"-mdc",	NULL,	0	},
			{	"-mhf", NULL,	0	},
			{	"-mvf",	NULL,	0	},
			{	"-dvf",	NULL,	0	},
			{	"-hv",	NULL,	0	},
			{	"-vv",	NULL,	0	},
			{	"-hfp",	NULL,	0	},
			{	"-hbp",	NULL,	0	},
			{	"-hsp",	NULL,	0	},
			{	"-vfp",	NULL,	0	},
			{	"-vbp",	NULL,	0	},
			{	"-vsp",	NULL,	0	},
			{	NULL,	NULL,	0	}
};





int
arg_action (arg_parse_t *ap)
{
	unsigned int x_uint, y_uint;
	double x_double;

	char *serr = NULL;		/* for using with strtol(), strtod() */



	/*
	fprintf (stdout, "argument %u matches option %u: %s == %s\n",
			ap->aindex, ap->oindex, (*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
	*/

	/*
	 * taking appropriate actions for each argument type
	 */

	switch (ap->oindex)
	{
		case 0:	{
				banner ();
				usage ();
				exit (0);	/* either reading help or using the program... */
				break;
			}

		case 1:	{
				if (commit_verbose (CFG_PREC_CMDLINE, &verbose, 1) == 0)
					pmsg (VL_DEBUG, "[cmdline] arg %u: verbose mode on\n", ap->aindex);
				break;
			}

		case 2:	{
				if (commit_verbose (CFG_PREC_CMDLINE, &verbose, 0) == 0)
					pmsg (VL_DEBUG, "[cmdline] arg %u: verbose mode off\n", ap->aindex);
				break;
			}

		case 3: {
				if (commit_fbset (CFG_PREC_CMDLINE, &fbset, 1) == 0)
                                	pmsg (VL_DEBUG, "[cmdline] arg %u: fbset mode on\n", ap->aindex);
				break;
			}

		case 4: {
				if (commit_fbset (CFG_PREC_CMDLINE, &fbset, 0) == 0)
                                	pmsg (VL_DEBUG, "[cmdline] arg %u: fbset mode off\n", ap->aindex);
				break;
			}

		case 5: {
				if (commit_nvidia (CFG_PREC_CMDLINE, &nvidia, 1) == 0)
                                	pmsg (VL_DEBUG, "[cmdline] arg %u: nvidia compatibility mode on\n", ap->aindex);
				break;
			}

		case 6: {
				if (commit_nvidia (CFG_PREC_CMDLINE, &nvidia, 0) == 0)
                                	pmsg (VL_DEBUG, "[cmdline] arg %u: nvidia compatibility mode off\n", ap->aindex);
				break;
			}

		case 7: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					cfgfile = (*ap->options)[ap->oindex].ao_parameter;
					pmsg (VL_DEBUG, "[cmdline] arg %u: config file set to %s\n", ap->aindex, cfgfile);
				}
				break;
			}

		case 8: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					if (sscanf ((*ap->options)[ap->oindex].ao_parameter, "%ux%u", &x_uint, &y_uint) == 2)
					{
						switch (commit_mode (CFG_PREC_CMDLINE, &modes, &num_modes, x_uint, y_uint))
						{
							case -1: 	break;

							case 0: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: added mode %ux%u\n", ap->aindex, x_uint, y_uint);
									break;
								}

							case 5: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: too many modes, dropping %ux%u\n", ap->aindex, x_uint, y_uint);
									pmsg (VL_VERBOSE, "no more than 256 modes are allowed, dropping %ux%u\n", x_uint, y_uint);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);
				
				break;
			}

		case 9: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_max_dotclk (CFG_PREC_CMDLINE, &max_dotclk, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: max_dotclk = %0.0f MHz\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 10: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_max_hfreq (CFG_PREC_CMDLINE, &max_hfreq, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: max_hfreq = %0.1f kHz\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 11: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_max_vfreq (CFG_PREC_CMDLINE, &max_vfreq, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: max_vfreq = %0.1f Hz\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 12: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_desired_vfreq (CFG_PREC_CMDLINE, &desired_vfreq, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: desired_vfreq = %0.1f Hz\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 13: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_hvisible (CFG_PREC_CMDLINE, &hvisible, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: hvisible = %0.0f %\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 14: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_vvisible (CFG_PREC_CMDLINE, &vvisible, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: vvisible = %0.0f %\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 15: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_hfporch (CFG_PREC_CMDLINE, &hfporch, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: hfporch = %0.0f ticks\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 16: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_hbporch (CFG_PREC_CMDLINE, &hbporch, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: hbporch = %0.0f ticks\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 17: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_hsync (CFG_PREC_CMDLINE, &hsync, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: hsync = %0.1f usec\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 18: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_vfporch (CFG_PREC_CMDLINE, &vfporch, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: vfporch = %0.0f ticks\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 19: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_vbporch (CFG_PREC_CMDLINE, &vbporch, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: vbporch = %0.0f ticks\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		case 20: {
				if ((*ap->options)[ap->oindex].ao_flags & ARG_FOUND_PARM)
				{
					x_double = strtod ((*ap->options)[ap->oindex].ao_parameter, &serr);

					if ((*(*ap->options)[ap->oindex].ao_parameter != '\0') && (*serr == '\0'))
					{
						switch (commit_vsync (CFG_PREC_CMDLINE, &vsync, x_double))
						{
							case -1:	break;

							case 0:	{
									pmsg (VL_DEBUG, "[cmdline] arg %u: vsync = %0.0f usec\n", ap->aindex, x_double);
									break;
								}

							default: {
									pmsg (VL_DEBUG, "[cmdline] arg %u: %s has an invalid parameter \"%s\"\n", ap->aindex,
										(*ap->options)[ap->oindex].ao_option, (*ap->options)[ap->oindex].ao_parameter);
									pmsg (VL_VERBOSE, "argument %u (%s) has an invalid parameter\n", ap->aindex, ap->argv[ap->aindex]);
									return (-1);
								}
						}
					}
					else
						return (-1);
				}
				else
					return (-1);

				break;
			}

		default: {
				pmsg (VL_DEBUG, "[cmdline] arg %u: unrecognized argument \"%s\"\n", ap->aindex, ap->argv[ap->aindex]);
				pmsg (VL_VERBOSE, "invalid argument %u (%s)\n", ap->aindex, ap->argv[ap->aindex]);
				return (-1);
			}
	}

	return (0);
}





int
arg_parse (arg_parse_t *ap, int (*arg_action) (arg_parse_t *))
{
	char *eq;
	int match;



	/*
	 * parse all arguments present on the command line
	 */

	ap->aindex = 1;
	while (ap->aindex < ap->argc)
	{
		ap->oindex = 0;
		match = 0;

		while ((*ap->options)[ap->oindex].ao_option != NULL)
		{
			if ((eq = strchr (ap->argv[ap->aindex], '=')) == NULL)
			{
				/*
				 * argument does not have a parameter
				 */

				if (strcmp ((*ap->options)[ap->oindex].ao_option, ap->argv[ap->aindex]) == 0)
				{
					match++;
					(*ap->options)[ap->oindex].ao_flags |= ARG_FOUND;

					if ((*arg_action) (ap) < 0)
						return (-1);
				}
			}
			else
			{
				/*
				 * argument does have a parameter
				 */
				
				*eq = '\0';	/* temporarily split string at the equal sign */

				if (strcmp ((*ap->options)[ap->oindex].ao_option, ap->argv[ap->aindex]) == 0)
				{
					match++;
					(*ap->options)[ap->oindex].ao_flags |= ARG_FOUND;
					(*ap->options)[ap->oindex].ao_flags |= ARG_FOUND_PARM;
					(*ap->options)[ap->oindex].ao_parameter = eq + 1;

					*eq = '=';	/* restore equal sign */
					if ((*arg_action) (ap) < 0)
						return (-1);
				}
				else
					*eq = '=';	/* restore equal sign */
			}

			ap->oindex++;
		}

		if (((*ap->options)[ap->oindex].ao_option != NULL) && (match == 0))
		{
			ap->oindex = -1;	/* signal unmatched argument */
			if ((*arg_action) (ap) < 0)
				return (-1);
		}

		ap->aindex++;
	}

	return (0);
}





/* EOF */
