Exercise 5-16 (dlines - Directory order sort option)

Chapter_5     Exercise_5-15 Exercise_5-17







Exercise 5-16     K&R, p. 121


Exercise 5-16. Add the -d ("directory order") option, which makes comparisons only on letters, numbers, and blanks. Make sure it works in conjunction with -f.




dlines.c         download


#include <stdio.h> // for getchar(), printf(), EOF, NULL, FILE, fopen(), fclose()
#include <string.h> // for strcat(), strcpy(), strcmp()

#define MAXLINES 20000 // max no of lines to be sorted
#define MAXLEN 100 // max line length
#define MAXFNLEN 100 // max file name length

int readlines (char *lineptr[], int nlines);
void writelines (char *lineptr[], int nlines, char *filename);

void qSort(void *lineptr[], int left, int right, // qsort() is declared in stdlib.h
int (*comp)(void*, void*)); // comparison function,
// strcmp(), strfcmp(), strdcmp(), or strfdcmp()

int strfcmp(char*, char*); // case insensitive comparison (fold upper and lowercase)
int strdcmp(char*, char*); // directory order comparison
int strfdcmp(char*, char*); // case insensitive, directory order

int main(int argc, char *argv[])
{
int ci = 0; // 1 if case insensitive sort
int dirord = 0; // 1 if directory order sort
int c;

while (--argc > 0 && (*++argv)[0] == '-') // optional arguments
{
while (c = *++argv[0]) // -f, -d, -f -d, -df, -fdf, etc.
{
switch(c)
{
case 'f' :
ci = 1;
break;
case 'd' :
dirord = 1;
break;
default:
printf("Illegal option: '%c'\n", c);
printf("Usage : ./dlines -f -d\n");
printf("Optional arguments:\n");
printf("\"-f\" - case insensitive sort (fold upper and lowercase)\n");
printf("\"-d\" - directory order sort (letters, numbers, blanks)\n");

return 1; // end program, signalling error
}
}
}

if (argc) // if (argc > 0)
{
printf("Usage : ./dlines -f -d\n");
printf("Optional arguments:\n");
printf("\"-f\" - case insensitive sort (fold upper and lowercase)\n");
printf("\"-d\" - directory order sort (letters, numbers, blanks)\n");

return 1; // end program, signalling error
}

char *lineptr[MAXLINES];
int nlines; // no of input lines read

char filename[MAXFNLEN];
int i = 0;
if (ci) // case insensitive sort
{filename[i++] = 'f';}
if (dirord) // directory order sort
{filename[i++] = 'd';}
filename[i] = '\0';
strcat(filename, "sort.txt");

int (*comp)(void*, void*);

if ((nlines = readlines(lineptr, MAXLINES)) >= 0)
{// casts are necessary to avoid error or warning of pointer type mismatch:
if (ci && dirord) // case insensitive, directory order
{comp = (int (*)(void*, void*))strfdcmp;}
else if (ci)
{comp = (int (*)(void*, void*))strfcmp;}
else if (dirord)
{comp = (int (*)(void*, void*))strdcmp;}
else {comp = (int (*)(void*, void*))strcmp;}

{qSort((void**)lineptr, 0, nlines-1, comp);}

writelines(lineptr, nlines, filename);
}
else
{
printf("Error: input too big to sort\n");
return 1; // exit program, signalling error
}

return 0;
}

int getLine(char *, int); // getline() is declared in stdio.h
char* alloc(int); // allocate storage

int readlines (char *lineptr[], int maxlines) // read input lines
{
int len; // length of line
int nlines; // no of input lines read

char *p, line[MAXLEN];

nlines = 0;
while ((len = getLine(line, MAXLEN)) > 0)
{
if(nlines >= maxlines || (p = alloc(len+1)) == NULL)
{return -1;} // len+1 for ending '\0'
else
{
strcpy(p, line);
lineptr[nlines++] = p;
}
}

return nlines;
}

int getLine(char *s, int lim)
{
int c = EOF; // initialize
char *p;
// getchar() is only executed if ((p-s) < (lim-1)):
for (p = s; (p-s) < (lim-1) && (c = getchar()) != EOF && c != '\n'; p++)
{ // from 0 to lim-2; s[lim-2]='\n', s[lim-1]='\0'
*p = c;
}
if (c == '\n')
{*p++ = c;}

*p = '\0'; // the null character ends a string

return p-s; // max(p-s) == (lim-1)
}

#define ALLOCSIZE (MAXLINES * MAXLEN)

static char allocbuf[ALLOCSIZE]; // storage for alloc()
static char *allocp = allocbuf; // next free position

char* alloc(int n) // return pointer to n chars
{
if (allocbuf + ALLOCSIZE - allocp >= n) // it fits
{
allocp += n;
return allocp-n; // old pointer
}
else {return 0;} // null pointer
}
void afree(char *p) // free storage pointed to by p
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
{allocp = p;}
}

void writelines (char *lineptr[], int nlines, char *filename) // write output lines
{
FILE *f = fopen(filename, "w"); // open for writing

while (nlines-- > 0)
{fprintf(f, "%s", *lineptr++);}

fclose(f);
}

void swap(void *v[], int i, int j); // interchange v[i], v[j]

// sort v[left] ... v[right]
void qSort(void *v[], int left, int right, // qsort() is declared in stdlib.h
int (*comp)(void*, void*)) // comparison function,
{ // lexicographic or numeric
int i, last;

if (left >= right) // do nothing if array contains fewer than 2 elements
{return;} // stopping condition for recursion

swap(v, left, (left + right) / 2); // move partition element to v[left]
last = left; // start moving elements to last position
for (i = left + 1; i <= right; i++)
{
if (comp(v[i], v[left]) < 0) // v[i] < v[left]
{swap(v, ++last, i);} // smaller to the left, bigger to the right
}

swap(v, left, last); // return partition element to the middle position
qSort(v, left, last-1, comp); // sort smaller elements
qSort(v, last+1, right, comp); // sort bigger elements
}

#include <ctype.h> // for isalpha(), isupper(), islower(), isalnum(), isdigit()

int strfcmp(char *s1, char *s2) // case insensitive comparison
{ // (fold uppercase and lowercase together)
int i1, i2;

for ( ; *s1 && *s2; s1++, s2++) // (*s1 != '\0') && (*s2 != '\0')
{
if (*s1 != *s2)
{
if (isalpha(*s1) && isalpha(*s2))
{
if (isupper(*s1) && isupper(*s2) || islower(*s1) && islower(*s2))
{return *s1 - *s2;}
i1 = *s1 - (isupper(*s1) ? 'A' : 'a'); // here one of *s1, *s2 is upper,
i2 = *s2 - (isupper(*s2) ? 'A' : 'a'); // the other is lower
if (i1 != i2) {return i1 - i2;} // else continue;
}
else {return *s1 - *s2;}
} // else continue;
} // *s1 == '\0', *s2 == '\0', or both

return *s1 - *s2;
}

int strdcmp(char *s1, char *s2) // directory order comparison
{
for ( ; *s1 && *s2; s1++, s2++) // (*s1 != '\0') && (*s2 != '\0')
{ // compare only letters, numbers, blanks
while (*s1 && *s1 != ' ' && !isalnum(*s1)) {s1++;}
while (*s2 && *s2 != ' ' && !isalnum(*s2)) {s2++;}

if (*s1 != *s2)
{ // space is ASCII 32 < digits, letters (alphanumeric)
return *s1 - *s2;
} // else continue;
}

return *s1 - *s2; // *s1 == '\0', *s2 == '\0', or both
}

int strfdcmp(char *s1, char *s2) // case insensitive, directory order
{
int i1, i2;

for ( ; *s1 && *s2; s1++, s2++) // (*s1 != '\0') && (*s2 != '\0')
{ // compare only letters, numbers, blanks
while (*s1 && *s1 != ' ' && !isalnum(*s1)) {s1++;}
while (*s2 && *s2 != ' ' && !isalnum(*s2)) {s2++;}

if (*s1 != *s2)
{ // space is ASCII 32 < digits, letters (alphanumeric)
if (!isalpha(*s1) || !isalpha(*s2) ||
isupper(*s1) && isupper(*s2) || islower(*s1) && islower(*s2))
{return *s1 - *s2;}
i1 = *s1 - (isupper(*s1) ? 'A' : 'a'); // here one of *s1, *s2 is upper,
i2 = *s2 - (isupper(*s2) ? 'A' : 'a'); // the other is lower
if (i1 != i2) {return i1 - i2;} // else continue;
} // else continue;
}

return *s1 - *s2; // *s1 == '\0', *s2 == '\0', or both
}

void swap(void *v[], int i, int j) // interchange v[i], v[j]
{
void *temp;

temp = v[i]; // swap pointers
v[i] = v[j];
v[j] = temp;
}

/*
gcc dlines.c -o dlines
./dlines < me.txt // created file "sort.txt"

./dlines f
Usage : ./dlines -f -d
Optional arguments:
"-f" - case insensitive sort (fold upper and lowercase)
"-d" - directory order sort (letters, numbers, blanks)

./dlines -c
Illegal option: 'c'
Usage : ./dlines -f -d
Optional arguments:
"-f" - case insensitive sort (fold upper and lowercase)
"-d" - directory order sort (letters, numbers, blanks)

./dlines -fdc
Illegal option: 'c'
Usage : ./dlines -f -d
Optional arguments:
"-f" - case insensitive sort (fold upper and lowercase)
"-d" - directory order sort (letters, numbers, blanks)

./dlines -f < me.txt // created file "fsort.txt"

./dlines -d < me.txt // created file "dsort.txt"

./dlines -f -d -df < me.txt // created file "fdsort.txt"

rm *sort.txt // clean
*/





Notes:

For the contents of text file me.txt see Martin_Eden on Project_Gutenberg.
Redefine MAXLINES and MAXLEN if you use other input file.









Chapter_5     Exercise_5-15 BACK_TO_TOP Exercise_5-17



Comments

Popular posts from this blog

Contents

Blogger Page Margins in Contempo