Click here to Skip to main content
15,064,026 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
My school assignment is a bank account program that can run in two modes, interactive and bash mode. Right now I'm working on bash mode and need to accept command line arguments to open a database account (just a text file with info for different accounts, like names, account numbers, passwords, and balance) and perform actions like deposit, transfer funds, etc. However, we have to be able to accept these commands in any order the user passes. For instance, if you wanted to deposit something, you would run something like ./bankacct /OTestDB.txt /A12bw3 /Pabc123 /D300.00 where /O opens the database file that stores user info, /A and /P check the account number and password as a way of "signing in", and /D deposits 300 dollars to the account. We've yet to learn classes, and the program is mostly based in using pointers and structures. Additionally, we're only allowed to use c-strings, no string class, but I don't think that has a bearing on this part. So my problem is trying to figure out how to get ./bankacct /OTestDB.txt /A12bw3 /Pabc123 /D300.00 in the same way as ./bankacct /D300.00 /Pabc123 /A12bw3 /OTestDB.txt

What I have tried:

My first approach to this problem was to set a switch statement that would call the relevant function and just run it through a for loop to cover every argument. But if a user doesn't open the database file first, then I don't have the arguments to pass to a function to "log in" and choose the account. So with my current approach, it seems like the order of command line arguments would need to be constant. So any tips on where to get started would be great, as right now I'm imagining having a set order in which I take arguments and just reading through my argument array with a for loop for each argument until I get to the argument I need. Here's some of my relevant functions:

C++
/* -----------------------------------------------------------------------------
 FILE NAME:         bankacct_v4.cpp
 DESCRIPTION:       A program that allows manipulation of a bank account database
 USAGE:             ./bankacct_v4
 COMPILER:          GNU g++ compiler on Linux
 NOTES:
 ----------------------------------------------------------------------------- */

#include "bankacct_v4.h"

/* -----------------------------------------------------------------------------
 FUNCTION:          main()
 DESCRIPTION:       controller for the code I guess ADD MORE LATER
 RETURNS:           0
 NOTES:				if statement to switch between command line and interactive
 					int argc                //number of parameters on command line
                    char *argv[]            //an array of pointers to C-strings
 ------------------------------------------------------------------------------- */
int main(int argc, char * argv[])
{
	bool flag = true;
	int num_acct = 0;	//This is what you will access with output so you don't print a bajillion blank accounts
    account* user = new account[100];

	if (argc > 1)
	{
		for (int i = 0; i < argc; ++i)
	{
		cout << "Argument " << i << " : " << left << setw(16) <<  argv[i] << endl;
		if (i) commands(argv[i], i);
		else cout << endl;
	}
	}
	else
		{
                    cout << endl;
		}

	delete[] user;
	
    cout << endl;
    cout << "Programmed by: " << PROGRAMMER_NAME << " -- ";
    cout << __DATE__ << "  " __TIME__ << endl;
    cout << endl;
    
    return 0;
}
/*-----------------------------------------------------------------------------

FUNCTION NAME:     void read_file
PURPOSE:           read in file as designated by command line
RETURNS:           nothing
NOTES:             
----------------------------------------------------------------------------- */
void read_file(char* file, account* user, int &num_accts)
{
	ifstream infile(file);

	if (!infile)
		cout << "\nError opening file: " << file << "\n\n";
	else
	{
		cout << "Input file: " << file << endl;
		while(infile)	//won't proceed if end of file WHY DOES THIS WORK
		{
		create(user, cout, infile, 0, num_accts); 
		}
		infile.close();
	}

}
/* -----------------------------------------------------------------------------
FUNCTION:          check_arg()
DESCRIPTION:       checks command line args
RETURNS:           Nothing
NOTES:
----------------------------------------------------------------------------- */
char check_arg(char arg[])
{	
	char buf[100];
	const char SLASH = '/';
	char valid_options[] = "?ACDFILMNOPRSTW";
	char *p = valid_options;

	bool first_char = arg[0] == SLASH; 	//Test 1st argument's first character

	bool second_char = false;

	for (; *p != 0; ++p) 				//Test 1st arg's 2nd character
	{
		second_char = arg[1] == *p;
		if (second_char == true) break;
	}

	if (!first_char || !second_char)
		cout << "Invalid argument" << endl;

	else
	{
	cout << "Option: " << *p;

	if (arg[2] != 0)
	{
	strcpy(buf, arg+2);
	cout << " Value: " << buf;
	}
	cout << endl;
	}
	return *p;
}

/* -----------------------------------------------------------------------------
 FUNCTION:          void create()
 DESCRIPTION:       creates a bank account
 RETURNS:           Nothing
 NOTES:             Use ostream object instead of cout/cin
 					Can I use a loop instead of asking for each individual input?
 					Array of structures
 ------------------------------------------------------------------------------- */

void create(account* user, ostream &out, istream &in, bool mode, int &num_acct)
{
    if (mode) out << "Last Name? ";
    in >> user[num_acct].lname;	
    if (mode) out << "\nFirst Name? ";
    in >> user[num_acct].fname;
    if (mode) out << "\nMiddle Initial? ";
    in >> user[num_acct].mi;
    if (mode) out << "\nSocial Security Number? ";
    in >> user[num_acct].ssn;
    if (mode) out << "\nPhone Number? ";
    in >> user[num_acct].phone;
    if (mode) out << "\nBalance? ";
    in >> user[num_acct].bal;
    if (mode) out << "\nAccount Number? ";
    in >> user[num_acct].acctnum;
    if (mode) out << "\nPassword? ";
    in >> user[num_acct].acctpass;
    num_acct++;
}
/* -----------------------------------------------------------------------------
 FUNCTION:          void display()
 DESCRIPTION:       displays account info
 RETURNS:           Nothing
 NOTES:             Use ostream object instead of cout/cin
 					Does this one really need pass by ref? Copy should be fine.
 ------------------------------------------------------------------------------- */

void display(account* user, ostream &out, int num_acct)
{
    out << user[num_acct].lname << endl;
    out << user[num_acct].fname << endl;
    out << user[num_acct].mi << endl;
    out << user[num_acct].ssn << endl;
    out << user[num_acct].phone << endl;
    out << user[num_acct].bal << endl;
    out << user[num_acct].acctnum << endl;
    out << user[num_acct].acctpass << endl;
    out << endl;

}
/* -----------------------------------------------------------------------------
 FUNCTION:          void output()
 DESCRIPTION:       puts array of structures to output file
 RETURNS:           Nothing
 NOTES:             
 ------------------------------------------------------------------------------- */
 void output(account* user, int num_acct)
 {
 	ofstream outfile;
 	outfile.open("output.txt");
 	for (int i = 0; i < num_acct; i++)
 	{
 		display(user, outfile, i);
 	}
 	outfile.close();
 }
 /*-----------------------------------------------------------------------------

FUNCTION NAME:     void commands()
PURPOSE:           
RETURNS:           Nothing (void function)
NOTES:             ?ACDFILMNOPRSTW are valid. stuff ilke /F and /L could probably just be lines like user[i].fname = "value passed". How to take any order?
----------------------------------------------------------------------------- */
void commands(char argv[], int i)
{
	switch (check_arg(argv[i]))
		{
		case '?':
			//helpmenu();
			break;
		case 'A':
			//readaccountnumber(); ? or set var acctnum to this value?
			break;
		case 'C':
			//createpass();
			break;
		case 'D':
			//deposit();
			break;
		case 'F':
			//firstname(); assigns value of first name when creating new account
			break;
		case 'I':
			//output(); for displaying account info
			break;
		case 'L':
			//lastname(); assigns last name
			break;
		case 'M':
			//initial(); assigns middle initial
			break;
		case 'N':
			//phonenum(); assigns phone number
			break;
		case 'O':
			//read_file(char* file, account* user, int &num_accts); reads file info to array of structures
			break;
		case 'P':
			//readpassword(); as a part of "sign in" process
			break;
		case 'R':
			//reportfile(); prints database in form of report file
			break;
		case 'S':
			//ssn(); assigns social security number
			break;
		case 'T':
			//transfer(); (requires two /A and /P)
			break;
		case 'W':
			//withdraw(); 
			break;
}


I'm also aware that I'm not passing the right arguments to check_arg when I call it in commands. The function works if I call it instead of commands in main, but I don't know how check_arg would know what to actually do with the commands, as it just says what the commands were.
Posted
Updated 4-Mar-18 5:27am
Comments
PIEBALDconsult 3-Mar-18 22:22pm
   
(Didn't read your code.)
Unsure I'd use pointers -- more likely simple integer offsets -- but if that's the assignment requirement, then it's hardly more difficult.
If you allow only one of any particular type of argument (O, A, P, etc.) then try using strstr to find each possible argument and (if present) assign its address to a pointer to it.
http://www.cplusplus.com/reference/cstring/strstr/
Something like:
char *argA = strstr ( cmdline , "/A" ) ;

This type of issue is why the Operating System should never try to parse the command line and always allow the program to do it itself.
If you're using Windows, try using the GetCommandLine function to get the actual command line.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156(v=vs.85).aspx

The way I'd do it is to parse the commands twice: first parse separates out the "files" from the "switches", and verifies the basics: one and only one file plus a number of switches.
Then it's simple: open your file, and process the swiches.
   
I would use what GNU provides (Parsing Program Arguments (The GNU C Library)[^]). Since yours is an assignment it could not be a viable alternative.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900