Node:Example programs, Next:A note from the original author, Previous:Debugging, Up:Top
The aim of this section is to provide a substantial example of C
programming, using input from and output to disk, GNU-style long
options, and the linked list data structure (including insertion,
deletion, and sorting of nodes).
#include <stdio.h> #include <string.h> #include <argp.h> #define NAME_LEN 100 #define ADDR_LEN 500 const char *argp_program_version = "bigex 1.0"; const char *argp_program_bug_address = "<bug-gnu-utilsgnu.org>"; /* This structure is used by main to communicate with parse_opt. */ struct arguments { char *args[1]; /* No arguments to this function */ int verbose; /* The -v flag */ char *infile; /* Argument for -i */ char *outfile; /* Argument for -o */ }; struct personal_data { char name[NAME_LEN]; char address[ADDR_LEN]; struct personal_data *next; }; /* OPTIONS. Field 1 in ARGP. Order of fields: {NAME, KEY, ARG, FLAGS, DOC}. */ static struct argp_option options[] = { {"verbose", 'v', 0, 0, "Produce verbose output"}, {"input", 'i', "INFILE", 0, "Read addresses from INFILE"}, {"output", 'o', "OUTFILE", 0, "Output to OUTFILE instead of to standard output"}, {0} }; /* PARSER. Field 2 in ARGP. Order of parameters: KEY, ARG, STATE. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { case 'v': arguments->verbose = 1; break; case 'i': arguments->infile = arg; break; case 'o': arguments->outfile = arg; break; case ARGP_KEY_ARG: if (state->arg_num >= 1) { argp_usage(state); } arguments->args[state->arg_num] = arg; break; case ARGP_KEY_END: if (state->arg_num < 1) { argp_usage (state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } /* ARGS_DOC. Field 3 in ARGP. A description of the non-option command-line arguments that we accept. */ static char args_doc[] = "ARG"; /* DOC. Field 4 in ARGP. Program documentation. */ static char doc[] = "bigex -- Add ARG new names to an address book file.\vThe largest code example in the GNU C Tutorial."; /* The ARGP structure itself. */ static struct argp argp = {options, parse_opt, args_doc, doc}; struct personal_data * new_empty_node() { struct personal_data *new_node; new_node = (struct personal_data*) malloc (sizeof (struct personal_data)); strcpy (new_node->name, ""); strcpy (new_node->address, ""); new_node->next = NULL; return new_node; } struct personal_data * create_node() { int bytes_read; int nbytes; struct personal_data *current_node; char *name; char *address; current_node = new_empty_node(); puts ("Name?"); nbytes = NAME_LEN; name = (char *) malloc (nbytes + 1); bytes_read = getline (&name, &nbytes, stdin); if (bytes_read == -1) { puts ("ERROR!"); } else { strncpy (current_node->name, name, NAME_LEN); free (name); } puts ("Address?"); nbytes = ADDR_LEN; address = (char *) malloc (nbytes + 1); bytes_read = getline (&address, &nbytes, stdin); if (bytes_read == -1) { puts ("ERROR!"); } else { strncpy (current_node->address, address, ADDR_LEN); free (address); } printf("\n"); return current_node; } struct personal_data * find_end_node (struct personal_data *current_node) { if (current_node->next == NULL) { return current_node; } else { return find_end_node (current_node->next); } } int list_length (struct personal_data *root) { struct personal_data *current_node; int count = 0; current_node = root; while (current_node->next != NULL) { current_node = current_node->next; count++; } return count; } struct personal_data * find_node (struct personal_data *root, int node_wanted) { struct personal_data *current_node; int index = 0; current_node = root; while ((index < node_wanted) && (current_node->next != NULL)) { current_node = current_node->next; index++; } return current_node; } delete_node (struct personal_data *root, int location) { struct personal_data *previous_node; struct personal_data *current_node; previous_node = find_node (root, location - 1); current_node = find_node (root, location); previous_node->next = current_node->next; } insert_node (struct personal_data *root, struct personal_data *new_node, int location) { struct personal_data *temp_ptr; struct personal_data *previous_node; previous_node = find_node (root, location - 1); temp_ptr = previous_node->next; previous_node->next = new_node; new_node->next = temp_ptr; } swap_nodes (struct personal_data *root, int a, int b) { int temp; struct personal_data *node_a; struct personal_data *node_b; struct personal_data *temp_node; if (a > b) { temp = a; a = b; b = temp; } node_b = find_node (root, b); delete_node (root, b); node_a = find_node (root, a); delete_node (root, a); insert_node (root, node_b, a); insert_node (root, node_a, b); } sort_list (struct personal_data *root) { int i, j, list_len, diff; list_len = list_length (root); for (i=2; i<=list_len; i++) { j = i; while (strcmp ( (find_node(root, j))->name, (find_node(root, j-1))->name) < 0) { swap_nodes (root, j, j-1); j--; } } } print_node (struct personal_data *current_node, FILE *save_stream) { fprintf (save_stream, "%s%s", current_node->name, current_node->address); } print_list (struct personal_data *current_node, FILE *save_stream) { print_node (current_node, save_stream); if (current_node->next != NULL) { print_list (current_node->next, save_stream); } } struct personal_data * read_node (FILE *instream) { int bytes_read; int nbytes; struct personal_data *current_node; char *name; char *address; char *blankline; int read_err = 0; current_node = new_empty_node(); nbytes = NAME_LEN; name = (char *) malloc (nbytes + 1); bytes_read = getline (&name, &nbytes, instream); if (bytes_read == -1) { read_err = 1; } else { puts (name); strncpy (current_node->name, name, NAME_LEN); free (name); } nbytes = ADDR_LEN; address = (char *) malloc (nbytes + 1); bytes_read = getline (&address, &nbytes, instream); if (bytes_read == -1) { read_err = 1; } else { puts (address); strncpy (current_node->address, address, ADDR_LEN); free (address); } if (read_err) { return NULL; } else { return current_node; } } struct personal_data * read_file (char *infile) { FILE *input_stream = NULL; struct personal_data *root; struct personal_data *end_node; struct personal_data *current_node; root = new_empty_node(); end_node = root; input_stream = fopen (infile, "r"); if (input_stream) { while (current_node = read_node (input_stream)) { end_node->next = current_node; end_node = current_node; end_node->next = NULL; } } return root; } /* The main function. Notice how now the only function call needed to process all command-line options and arguments nicely is argp_parse. */ int main (int argc, char **argv) { struct arguments arguments; struct personal_data *root; struct personal_data *end_node; struct personal_data *current_node; int i, newnum; FILE *save_stream; /* Set argument defaults */ arguments.infile = NULL; arguments.outfile = NULL; arguments.verbose = 0; /* Where the magic happens */ argp_parse (&argp, argc, argv, 0, 0, &arguments); if (arguments.infile) { root = read_file (arguments.infile); end_node = find_end_node (root); } else { root = new_empty_node(); end_node = root; } /* Where do we send output? */ if (arguments.outfile) save_stream = fopen (arguments.outfile, "w"); else save_stream = stdout; newnum = atoi (arguments.args[0]); for (i = 1; i <= newnum; i++) { current_node = create_node(); end_node->next = current_node; end_node = current_node; end_node->next = NULL; } sort_list (root); print_list (root->next, save_stream); /* Close stream; skip error-checking for brevity of example */ fclose (save_stream); /* If in verbose mode, print song stanza */ if (arguments.verbose) {}; return 0; }