New exercise from K&R, a program that sorts input lines in lexicographical order. It also allows a couple of flags that affect the comparing and the sorting part of the program.
It's an exercise that supposedly shows the usefulness of function pointers.
C code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINES 100
#define MAXLEN 1000
int main(argc, argv)
int argc;
char *argv[];
{
char *lineptr[MAXLINES];
int nlines;
int strcomp(), numcomp(), dictcomp(), foldcomp(), dfcomp(), swap(), linesort(), revsort();
int (*cmpfunc)() = strcomp, (*sortfunc)() = linesort;
char *flag;
int fold = 0, dict = 0;
while (--argc > 0 && (*++argv)[0] == '-')
for (flag = argv[0] + 1; *flag != '\0'; flag++)
switch (*flag){
case 'n':
cmpfunc = numcomp;
break;
case 'r':
sortfunc = revsort;
break;
case 'f':
fold = 1;
break;
case 'd':
dict = 1;
break;
default:
printf ("Illegal option: -%c.\n", *flag);
break;
}
if (dict || fold){
if (dict && fold) cmpfunc = dfcomp;
else if (dict) cmpfunc = dictcomp;
else cmpfunc = foldcomp;
}
if ((nlines = readlines (lineptr, MAXLINES)) >= 0){
(*sortfunc) (lineptr, nlines, cmpfunc, swap);
writelines (lineptr, nlines);
}
else if (nlines == -1) printf ("Input too big to sort: too many lines.\n");
else if (nlines == -2) printf ("Input too big to sort: not enough room in allocbuf.\n");
else printf ("Input too big to sort - line too long.\n");
return 0;
}
That's the main part of the program (the whole thing is quite a bit longer due to the number of functions required).
The flags are as follows:
-n : Program sorts lines in numerical order from the lowest number to the highest. This flag was added in the book already, the rest were incorporated by me as a part of the exercise.
-r : Program sorts lines in reverse. This flag has to work in conjunction with any of the other flags.
-f : Program folds upper and lower case together.
-d : Program sorts lines in dictionary order (makes comparisons only on letters, numbers and blanks). It has to work with the -f flag.
The functions are:
strcomp() compares two lines and returns 0 if they are the same, a positive int if the first one is lexicographically larger (ie. if it comes after the second one in the alphabet), and a negative int if the first one is lexicographically smaller.
This function's pointer is passed as an argument to sortfunc if no flags that would change the comparison process are in effect.
numcomp() compares two lines numerically and returns 0 if the two numbers are the same, 1 if the first number is larger, and -1 if the second number is larger.
This function's pointer is passed as an argument to sortfunc if -n flag is in effect.
dictcomp() compares two lines lexicographically, but based only on numbers, letters and blanks, and returns the same as strcomp().
This function's pointer is passed as an argument to sortfunc if -d flag is in effect.
foldcomp() compares two lines lexicographically, but it doesn't make distinctions between upper and lower case letters, so that a and A appear adjacent, returning the same as strcomp().
This function's pointer is passed as an argument to sortfunc if -f flag is in effect.
dfcomp() combines dictcomp() and foldcomp(), returning the same as strcomp().
This function's pointer is passed as an argument to sortfunc if -df (or -d -f) flags are in effect.
linesort() sorts lines by comparing two lines, using the comparison function, the pointer to which was passed to it as an argument, and sorting them with shellsort from lowest to highest.
This function is used as sortfunc if no flags that would change the sorting process are in effect.
revsort() sorts lines in the same way as linesort(), except that it sorts them from highest to lowest.
This function is used as sortfunc if -r flag is in effect.
readlines() records the lines into allocbuf, using alloc() (also a function from K&R) and returns the number of lines (or a negative int if there is an error).
writelines() outputs the lines, after they have been sorted with sortfunc.
Now the program as I made it, works as it should, but I think it's way too complicated. It has way too many functions, and the fact that I had to make a whole new function just to incorporate support for a combination of two already existing flags (-d and -f), bothers me a bit.
I'd rather just use a few external variables (dict, num, rev, fold), initialize them to 0, and set them to 1 if their respective flags were used. Then I'd just use one comparison function and one sorting function, and change the proper parts of them to behave appropriately if any of the above external variables were non-zero.
Or is there some reason why using so many functions and passing them via pointers is a good idea?
...and that's the bottom line because Mate de Vita said so.