Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* See declaration of auth users[] in main() for user/pass for program
- * RxRefill is a simple text menu app with separate functions responsible
- * for displaying current drug quantities, refill and dispensing the
- * medication. The code demonstrates how to gracefully handle the user
- * cancelling input by generating a manual EOF (ctrl + d, or ctrl + z windows)
- * at any input.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- /* if you need a constant, #define one (or more) */
- #define MAXNM 64 /* max characters in user, pass & drug name */
- #define MAXC 256 /* max characters in temp buffer for user input */
- struct drug { /* struct to hold drug name and quantity */
- char name[MAXNM];
- size_t qty;
- };
- typedef struct drug drug; /* create typedef to refer to type "struct drug"
- * as simply "drug" where needed. can be same,
- * typedef name space and struct tag name space
- * are separate and do not conflict.
- */
- typedef struct auth { /* typedef included as part of struct declaration */
- char user[MAXNM];
- char pw[MAXNM];
- } auth;
- /* chkauth takes array of users, no. of users and user that was input,
- * and loops over array of users comparing user.name & user.pass to each
- * element in the users array. If user.name and user.pass match an element
- * in the users array, return index to valid user on success, -1 if no
- * match of was found in the users array.
- */
- int chkauth (auth *users, size_t n, auth *user)
- {
- for (size_t i = 0; i < n; i++) { /* loop over all users */
- if (strcmp (users[i].user, user->user) == 0 && /* username match? */
- strcmp (users[i].pw, user->pw) == 0) { /* password match? */
- return i; /* return index to user in users array */
- }
- }
- return -1; /* user/password not found */
- }
- /* login takes the array of users and then number of users, reads and
- * validates both the username and password into a temporary auth stuct
- * 'user'. any error during input results in the return of -2 (user
- * canceled input by generating a manual EOF end-of-file, with Ctrl+d on
- * Linux or Ctrl+z on windows), or -1 for general input error. on successful
- * input of both username and password, login() passes the users array, the
- * number of users and the temp stuct user to chkauth(). the funciton returns
- * the direct return from chkauth to indicate success/failure of login.
- */
- int login (auth *users, size_t n)
- {
- auth user = { "", "" }; /* struct to hold user-input of name/pass */
- char buf[MAXC] = ""; /* temp buffer, initialized all zero */
- size_t len = 0; /* length of input, initialized zero */
- fputs ("Enter Username: ", stdout); /* prompt or username */
- if (fgets (buf, MAXC, stdin) == NULL) { /* read up to MAXC char into buf */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- /* validate username input */
- len = strlen (buf); /* get length of input */
- if (len && buf[len-1] == '\n') /* last char is '\n'?, overwrite with 0 */
- buf[--len] = 0;
- else if (len == MAXC - 1) {
- fputs ("error: input exceeds MAXC chars.\n", stderr);
- while (fgets (buf, MAXC, stdin)) {} /* read discard extra chars */
- return -1;
- }
- else if (len > MAXNM - 1) { /* > MAXNM-1 chars? (saves room for nul-char) */
- fputs ("error: username exceeds MAXNM chars.\n", stderr);
- return -1;
- }
- memcpy (&user.user, buf, len + 1); /* copy buf to user.name, +1 for
- * nul-terminating character.
- */
- fputs ("Enter Password: ", stdout); /* prompt or password */
- if (fgets (buf, MAXC, stdin) == NULL) { /* read up to MAXC char into buf */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- /* validate password input (same thing as with username) */
- len = strlen (buf); /* get length of input */
- if (len && buf[len-1] == '\n') /* last char is '\n'?, overwrite with 0 */
- buf[--len] = 0;
- else if (len == MAXC - 1) {
- fputs ("error: input exceeds MAXC chars.\n", stderr);
- while (fgets (buf, MAXC, stdin)) {} /* read discard extra chars */
- return -1;
- }
- else if (len > MAXNM - 1) { /* > MAXNM-1 chars? (saves room for nul-char) */
- fputs ("error: password exceeds MAXNM chars.\n", stderr);
- return -1;
- }
- memcpy (&user.pw, buf, len + 1); /* copy buf to user.name, +1 for
- * nul-terminating character.
- */
- return chkauth (users, n, &user); /* &user passes pointer to struct */
- }
- /* check drug quantity menu */
- void drugqtymenu (drug *drugs, size_t ndrugs)
- {
- /* display heading */
- fputs ("\n\tCurrent Quantities\n\n", stdout);
- /* display each drug (12-char lt. justified) and quantity */
- for (size_t i = 0; i < ndrugs; i++)
- printf ("%-12s %zu\n", drugs[i].name, drugs[i].qty);
- putchar('\n');
- }
- /* refill menu */
- int refillmenu (drug *drugs, size_t ndrugs)
- {
- size_t index, /* drugs[index] of selected drug */
- qty; /* quantity of selected drug to refill */
- /* display heading */
- fputs ("\nRefill which drug\n\n", stdout);
- /* display each drug in menu (I would add space between) */
- for (size_t i = 0; i < ndrugs; i++)
- printf ("%zu. %s\n", i + 1, drugs[i].name);
- fputs ("\nSelect drug number : ", stdout); /* prompt for drug */
- for (;;) { /* loop continually until valid drug selected */
- char buf[MAXC]; /* temporary buffer for user input */
- if (!fgets (buf, MAXC, stdin)) { /* if user cancels input */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- index = *buf - '0' - 1; /* convert from ASCII value to decimal */
- if (isdigit (*buf) && index < ndrugs) /* valid index? */
- break;
- fputs ("\nerror: invalid selection\n", stderr);
- }
- fputs ("Enter refill amount : ", stdout); /* prompt for quantity */
- for (;;) { /* loop continually until valid quantity entered */
- char buf[MAXC]; /* temporary buffer for user input */
- int result; /* variable to capture return of sscanf */
- if (!fgets (buf, MAXC, stdin)) { /* if user cancels input */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- result = sscanf (buf, "%zu", &qty);
- if (result == 1)
- break; /* valid quantity entered */
- }
- drugs[index].qty += qty; /* add refill quantity to drug */
- return 1; /* return success */
- }
- /* dispense menu */
- int dispensemenu (drug *drugs, size_t ndrugs)
- {
- size_t index, /* drugs[index] of selected drug */
- qty; /* quantity of selected drug to refill */
- /* display heading */
- fputs ("\nDispense which drug\n\n", stdout);
- /* display each drug in menu (I would add space between) */
- for (size_t i = 0; i < ndrugs; i++)
- printf ("%zu. %s\n", i + 1, drugs[i].name);
- fputs ("\nSelect drug number : ", stdout); /* prompt for drug */
- for (;;) { /* loop continually until valid drug selected */
- char buf[MAXC]; /* temporary buffer for user input */
- if (!fgets (buf, MAXC, stdin)) { /* if user cancels input */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- index = *buf - '0' - 1; /* convert from ASCII value to decimal */
- if (isdigit (*buf) && index < ndrugs) /* valid index? */
- break;
- fputs ("\nerror: invalid selection\n", stderr);
- }
- for (;;) { /* loop continually until quantity < drug quantity entered */
- char buf[MAXC]; /* temporary buffer for user input */
- fputs ("Enter dispense amount : ", stdout); /* prompt for quantity */
- for (;;) { /* loop continually until valid quantity entered */
- int result; /* variable to capture return of sscanf */
- if (!fgets (buf, MAXC, stdin)) { /* if user cancels input */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- result = sscanf (buf, "%zu", &qty);
- if (result == 1)
- break; /* valid number entered */
- }
- if (qty > drugs[index].qty) { /* is that more than we have? */
- fputs ("Not enough quantity\nRedispense? y or n\n", stdout);
- if (!fgets (buf, MAXC, stdin)) { /* if user cancels input */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- if (*buf == 'y') /* if 1st char in buf is 'y', try again */
- continue; /* iterate outer loop again */
- return 0; /* otherwise, does not want to dispense */
- }
- break; /* if we get here - valid quantity entered */
- }
- drugs[index].qty -= qty; /* subtract dispense qty from drug */
- return 1; /* return success */
- }
- int mainmenu (drug *drugs, size_t ndrugs)
- {
- for (;;) { /* loop continually displaying menu until return */
- char buf[MAXC]; /* temporary buffer for user input */
- fputs ( "\n\tDrug Inventory\n\n" /* -- display menu -- */
- "1. Check Quantity\n" /* all individual strings "..." */
- "2. Refill\n" /* are concantenated */
- "3. Dispense\n" /* so only 1 call to an output */
- "4. Quit\n\n" /* function is required */
- "Select Option: ", stdout);
- /* read input into buf */
- if (!fgets (buf, MAXC, stdin)) { /* test if user canceled (EOF) */
- fputs ("(user canceled input)\n", stderr);
- return -2;
- }
- /* use 1st character in buf to control next action. you can use buf[0]
- * to access the 1st char (using array index notation) or simply
- * dereference the pointer (e.g. *buf) using pointer notation. they are
- * equivalent, e.g. buf[0] = *(buf + 0) which is just *buf.
- */
- switch (*buf) {
- case '1': drugqtymenu (drugs, ndrugs);
- break; /* otherwise just break from switch */
- case '2': if (refillmenu (drugs, ndrugs) == -2)
- return -2; /* if user canceled, return -2 */
- break;
- case '3': if (dispensemenu (drugs, ndrugs) == -2)
- return -2; /* if user canceled, return -2 */
- break;
- case '4': return 1;
- default: fputs ("error: invalid selection.\n", stderr); break;
- }
- }
- }
- int main (void) {
- drug drugs[] = {{ "Amoxil", 100 }, /* initialize array of struct drug */
- { "Vicodin", 20 },
- { "Tylenol", 90 },
- { "Zestril", 50 }};
- auth users[] = {{ "Admin", "LetMeIn" }};
- size_t ndrugs = sizeof drugs / sizeof *drugs, /* no. of drugs in array */
- nusers = sizeof users / sizeof *users; /* no. of users in array */
- int result; /* varible to capture result of login */
- for (;;) { /* loop continually until valid login (or user cancels) */
- result = login (users, nusers); /* diplay login, get result */
- if (result == -2) /* result -2, user canceled input */
- exit (EXIT_FAILURE);
- else if (result >= 0) /* result >= 0 (valid login) */
- break; /* break loop and continue with program */
- /* otherwise, login attemp failed, output error, try again */
- fputs ("\nIncorrect username or password\n\n", stderr);
- }
- printf ("\nWelcome: %s\n", users[result].user);
- mainmenu (drugs, ndrugs); /* run main menu */
- }
Add Comment
Please, Sign In to add comment