/* --------------------------------------------------------------------- ** Figures 22.6 Using qsort() and a functional parameter. ** 22.3 Decoding command-line arguments, setup(). ** 20.15: Input into an array. ** 20.16: Output from an array. ** 22.5: Two comparison functions for qsort(). ** --------------------------------------------------------------------- */ #include "tools.h" typedef enum { ascend, descend } order_t; string labels[] = { "ascending", "descending" }; typedef struct { float* data; int n; int max; order_t order; } data_pack; void setup( int argc, string argv[], stream* inp, stream* outp, data_pack* sortp ); void get_data( data_pack* sort, stream instream ); void print_data( data_pack sort, stream outstream ); void sort_data( data_pack sort ); int sort_up(const void* fp1, const void* fp2); int sort_down(const void* fp1, const void* fp2); /* ------------------------------------------------------------------------- */ void main( int argc, string argv[] ) { stream in_str, out_str; /* Streams for input and output. */ data_pack sort; /* Pointer to array of numbers. */ int (*compare)( const void*, const void* ); /* A function pointer. */ say( "\n Qsort program." ); setup( argc, argv, &in_str, &out_str, &sort ); get_data( &sort, in_str ); say( " %i data items read; sorting in %s order.", sort.n, labels[sort.order] ); if (sort.order == ascend) compare = sort_up; else compare = sort_down; qsort( (void*)sort.data, sort.n, sizeof(float), compare ); say( " Data sorted; writing to file %s.", argv[argc-1] ); print_data( sort, out_str ); bye(); } /* ---------------------------------------------------------------------------- ** Decode and process the command-line arguments. */ void setup( int argc, string argv[], stream* inp, stream* outp, data_pack* sortp ) { char* last; /* To test for proper number conversion. */ long int n; /* Number of data items. */ int start = argc-3; /* First required argument. */ if (argc < 4 || argc > 5) fatal( "\n Usage: %s [-ad] num infile outfile \n", argv[0] ); /* -------------------------------------------------------- Open streams */ *inp = fopen( argv[start + 1], "r" ); if (*inp == NULL) fatal( "\n Cannot open %s for reading.", argv[start + 1] ); *outp = fopen( argv[start + 2], "w" ); if (*outp == NULL) fatal( "\n Cannot open %s for writing.", argv[start + 2] ); /* ----- Convert size from string to numeric format and allocate memory. */ n = strtol( argv[start], &last, 10 ); if (*last != '\0') fatal( "\n Error: %s is not an integer.", argv[start] ); if (n < 2) fatal( "\n Error: %i is too few items to sort.", n ); sortp->max = n; sortp->data = malloc( n * sizeof(float) ); if (sortp->data == NULL) fatal( "\n Too little memory for %i floats.", n ); /* ------------------ Pick up and check sort order (optional parameter). */ if (argc == 5) { if (strequal( argv[1], "-d" ) ) sortp->order = descend; else if (strequal( argv[1], "-a")) sortp->order = ascend; else fatal( "\n Sort order %s undefined.", argv[1] ); } else sortp->order = ascend; /* Default if switch is omitted. */ } /* --------------------------------------------------------------------- ** Read max data values from instream and store in ary. ---------------- */ void get_data( data_pack* sortp, stream instream ) { int stream_status; float* cursor = sortp->data; float const* end = cursor + sortp->max; /* off-board sentinel */ for( ; cursorn = cursor-sortp->data; /* Actual # of items read. */ } /* --------------------------------------------------------------------- ** Print array values, one per line, to selected stream. --------------- */ void print_data( data_pack sort, stream outstream ) { float* cursor = sort.data; const float* end = cursor + sort.n; /* an off-board sentinel */ for( ; cursor < end; ++cursor) { fprintf( outstream, " %.7g\n", *cursor ); } } /* ------------------------------------------------------------------------- ** Compare two floats for the qsort() function, for ascending order. */ int sort_up( const void* fp1, const void* fp2 ) { float f1 = *(float*)fp1; /* Cast argument to correct type of pointer */ float f2 = *(float*)fp2; /* ...then dereference to get a float. */ if (f1 < f2) return -1; else if (f1 == f2) return 0; else return 1; } /* ------------------------------------------------------------------------- ** Compare two floats for the qsort() function, for descending order. */ int sort_down(const void* fp1, const void* fp2) { float f1 = *(float*)fp1; /* Cast argument to correct type of pointer */ float f2 = *(float*)fp2; /* ...then dereference to get a float. */ if (f1 > f2) return -1; else if (f1 == f2) return 0; else return 1; }