/* generic argument parsing code */
/* all options with arguments work both as -ffoo and -f foo */

#include "ArgParse.h"

/* return pointer to CmdOptions struct that matches the 
** second (string) argument
** return NULL if there is none
*/
struct CmdOptions * OptionMatch( struct CmdOptions **arglist, char * string ){
    struct CmdOptions *CmdList;
    char * CmdOptPtr;

    if(arglist == NULL || string == NULL) return NULL;

    CmdList = arglist;
    CmdOptPtr = CmdList->OptString;
    while( CmdOptPtr != NULL ){
	if(strncmp(CmdListOptPtr,string, strlen(CmdListOptPtr)) ==0){
		return CmdList;
	}
	CmdList++;
	CmdOptPointer = CmdList->OptString;
    }
    return NULL;
}

/* returns number of argv options parsed.
*/
int ParseOptions( struct CmdOptions **arglist, int pargc, char **pargv){
    void * numptr;
    int numsize;
    char * strptr;
    char ** strargptr;
    int OptionalArg;
    int NumParsed = 0;

    if(DDebug)printf("DoingOptions...\n");

    pargv++; /* skip argv[0] == program name! */
    while(*pargv != NULL){
        if(**pargv == '-'){
	    char swchar;
	    numptr = NULL;
	    numsize = sizeof(int);  /* assume numptrs are int sizes */
	    strargptr = NULL;
	    OptionalArg = 0;
	    swchar = *((*pargv)+1);
	    if(DDebug) 
	    	printf("Checking switch character \"%c\"...\n",swchar);
	    switch(swchar){
	        case 'X': /* set MANUAL mode */
			if(DDebug) printf("DialOut set.\n");
			DialOut = 1; break;
	        case 'a': /* set autoanswer mode */
			if(DDebug) printf("AutoAnswer set.\n");
			AutoAnswer = 1; break;
	        case '8': /* set 8-bit mode */
			if(DDebug) printf("Master8 set.\n");
			Master8 = 1; break;
	        case 'd': /* set debug mode on : -d or -dnum */
			if(DDebug) printf("setting Debug mode\n");
			DDebug = 1;
			numptr = &DDebug; 
			numsize = sizeof(DDebug);
			OptionalArg = 1;
			break;
	        case 'p': /* set packet debug mode on */
			if(DDebug) printf("Packet Debug set.\n");
			PDebug = 1; break;
	        case 'h': /* set enable Carrier Checking */
			if(DDebug) printf("Carrier Checking set.\n");
			AutoHangup = 1; break;
	        case 'F': /* set enable Carrier Checking */
			if(DDebug) printf("Fast8 set.\n");
			Fast8 = 1; break;

		/* string argument options */
	        case 's': /* set autostartup client mode -sclient */
			if(DDebug) printf("setting autoclient\n");
			strargptr = &autoclient; break;
	        case 'n': /* set hostname mode -nhostname*/
			if(DDebug) printf("setting hostname\n");
			strargptr = &HostName; break;
	        case 'D': /* set device -DDevice */
			if(DDebug) printf("setting netdevice\n");
			strargptr = &netdevice; break;

		/* numeric argument options */
	        case 'b': /* set baudrate mode  -bbaud */
			if(DDebug) printf("setting baud\n");
			numptr = &baud; break;
	        case 'B': /* set baudrate -Bbaud  */
			if(DDebug) printf("setting TOBaud\n");
			numptr = &TOBaud; break;
	        case 'U': /* set unit number -u# */
			if(DDebug) printf("setting netunit\n");
			numptr = &netunit; break;    
	        case 'N': /* set network id# -N# */
			if(DDebug) printf("setting networknum\n");
			numptr = &NetworkNum; 
			numsize = sizeof(NetworkNum);
			break; 
	        case 'm': /* set 8bit/7bit packet mode -m0/-m1 */
			if(DDebug) printf("setting Mode7\n");
			numptr = &Mode7; break;  /* ubyte */
	        case 'P': /* set MANUAL mode -P# */
			if(DDebug) printf("setting Protocol\n");
			numptr = &Protocol; 
			numsize = sizeof(Protocol);
			break;  
	        case 'Z': /* set MANUAL mode -Z# */
			if(DDebug) printf("setting Parity\n");
			numptr = &Parity; 
			numsize = sizeof(Parity);
			break; /* (uword) */
		default:
		    printf("%s:invalid argument\n", *pargv);
		    return -1;
	    }
	    NumParsed ++;
	    if(numptr != NULL ){
		/* pointer to character after argument switch character */
		strptr = (*pargv)+2;

		if(DDebug)
			printf("checking numeric arg for %s\n", *pargv );

		/* check for switch arg: -fbar */
		if( *strptr == '\0'){
		    strptr = NULL;

		    /* No? how bout for switch arg -f bar */
		    if(*(pargv+1) != NULL){
		    	strptr = *(pargv+1);
			/* make sure it's not -f -bar */
			if( *strptr == '-'){
			    strptr = NULL;
			} else {
			    /* it was -f bar ; have to skip that extra arg */
			    pargv++;
			}
		    }
		}

		/* if an arg was found, strptr points to it */
		if(strptr){
		    switch(numsize){
			case sizeof(short):
			    *((short *)numptr) = (short) atoi( strptr ); 
			    break;
			case sizeof(char):
			    *((char *)numptr) = (char) atoi( strptr ); 
			    break;
		    	case sizeof(int):
			default:
			    *((int *)numptr) = atoi( strptr ); 
		    }
		} else {
		    if(!OptionalArg){
			printf("Requires argument: %s\n", *pargv);
			return -1;
		    }
		}
	    }  else if(strargptr) {
		/* pointer to character after argument switch character */
		strptr = (*pargv)+2;

		/* check for switch arg: -fbar */
		if( *strptr == '\0'){
		    strptr = NULL;

		    /* No? how bout for switch arg -f bar */
		    if(*(pargv+1) != NULL){
		    	strptr = *(pargv+1);
			/* make sure it's not -f -bar */
			if( *strptr == '-'){
			    strptr = NULL;
			} else {
			    /* it was -f bar need to skip that extra arg bar */
			    pargv++;
			}
		    }
		}

		/* if an arg was found, strptr points to it */
		if(strptr){
		    *strargptr = strptr;
		} else {
		    printf("Requires argument: %s\n", *pargv);
		    return -1;
		}
	    }
	} else {
	    printf("Invalid Option: %s\n", *pargv);
	    return -1;
	}
	pargv++;
    }
    if(DDebug){
    	printf("After DoOptions() settings are:\n");
	printf("DialOut: %d\tAutoAnswer %d\n", DialOut, AutoAnswer);
	printf("Master8: %d\tDDebug %d\n", Master8, DDebug);
	printf("PDebug: %d\tAutoHangup %d\n", PDebug, AutoHangup);

	printf("autoclient: \"%s\"\tHostName:\"%s\"\n", autoclient, HostName);
	printf("netdevice: \"%s\"\n", netdevice );

	printf("baud: %d\tTOBaud %d\n", baud, TOBaud);
	printf("netunit: %d\tNetworkNum %d\n", netunit, NetworkNum);
	printf("Mode7: %d\tProtocol %d\n", Mode7, Protocol);
	printf("Parity: %d\n", Parity);

    }
    return NumParsed;
}
