Exercise 5.17 - Sorting with options#

Question#

Add a field-searching capability, so sorting may bee done on fields within lines, each field sorted according to an independent set of options. (The index for this book was sorted with -df for the index category and -n for the page numbers.)

/* Add a field handling capablity, so sorting may be done on the fields within lines, 
    each field sorted according to an independent set of options. ( The index for the KnR Book was sorted with -df for the index category and -n for page number */

#include<stdio.h>
#include<ctype.h>

#define NUMERIC  1  /* numeric sort */
#define DECR    2   /* sort in decreasing order */
#define FOLD    4   /* fold upper and lower case */
#define MDIR    8   /* directory order */
#define LINES   100 /* maximum number of lines to be sorted */

int charcmp(char *,char *);
void error(char *);
int numcmp(char *,char *);
void readargs(int argc,char *argv[]);
int readlines(char *lineptr[],int maxlines);
void mqsort(void *v[],int left,int right,int (*comp)(void *,void *));
void writelines(char *lineptr[],int nlines,int order);

int option = 0;

int pos1 = 0;   /* field begining with pos 1 */
int pos2 = 0;   /* ending just before pos 2 */


/* Sort input line */

int main(int argc,char *argv[])
{
    char *lineptr[LINES];   /* pointer to text lines */
    int nlines;     /* number of input lines read */
    int rc = 0;

    readargs(argc,argv);

    if((nlines = readlines(lineptr,LINES))>0)
    {
        if(option & NUMERIC)
            myqsort((void **)lineptr,0,nlines-1,(int (*)(void *,void *))numcmp);
        else
            myqsort((void **)lineptr,0,nlines-1,(int (*)(void *,void *))charcmp);

        writelines(lineptr,nlines,option & DECR);
    }
    else
    {
        printf("input too big to sort \n");
        rc = -1;
    }
    
    return rc;
}

/* readargs: read programs argument */

void readargs(int argc,char *argv[])
{
    int c;
    int atoi(char *);
    
    while(--argc > 0 && (c=(*++argv)[0])=='-' || c == '+')
    {
        if( c == '-' && !isdigit(*(argv[0]+1)))
            while( c = *++argv[0])
                switch(c)
                {
                case 'd':   /* directory order */
                    option |= MDIR;
                    break;
                case 'f':
                        /* fold upper and lower */
                    option |= FOLD;
                    break;
                case 'n':
                        /* numeric sort */
                    option |= NUMERIC;
                    break;
                case 'r':
                    option |= DECR;
                    break;
                default:
                    printf("sort: illegal option %c \n",c);
                    error("Usage: sort -dfnr [+pos1] [-pos2]");
                    break;
                }
        else if( c == '-')
            pos2 = atoi(argv[0]+1);
        else if((pos1 = atoi(argv[0]+1))<0)
            error("Usage: sort -dfnr [+pos1][-pos2]");
    }

    if(argc || pos1 > pos2)
        error("Usage: sort -dfnr [+pos1] [-pos2]");
}

/* The source file numcmp.c */

#include<math.h>
#include<ctype.h>
#include<string.h>
#define MAXSTR 100

void substr(char *s,char *t,int maxstr);

/* numcmp: compare s1 and s2 numerically */

int numcmp(char *s1,char *s2)
{
    double v1,v2;
    char str[MAXSTR];

    substr(s1,str,MAXSTR);
    v1 = atof(str);

    substr(s2,str,MAXSTR);
    v2 = atof(str);

    if(v1 < v2)
        return -1;
    else if ( v1 > v2)
        return 1;
    else
        return 0;
}

#define FOLD    4   /* fold upper and lower cases */
#define MDIR    8   /* directory order */

/* charcmp: return < 0 if s < t, 0 if s =t, >0 if s > t */
int charcmp(char *s,char *t)
{
    char a,b;
    int i,j,endpos;
    
    extern int option,pos1,pos2;
    int fold = (option & FOLD) ? 1 : 0;
    int dir = (option & MDIR) ? 1 : 0;

    i=j=pos1;

    if (pos2 > 0)
        endpos = pos2;
    else if ((endpos = strlen(s)) > strlen(t))
        endpos = strlen(t);

    do
    {
        if(dir)
        {
            while(i < endpos && !isalnum(s[i]) && s[i] != ' ' && s[i] !='\0')
                s[i] != ' ' && s[i] != '\0';
                    i++;
            while(j < endpos && !isalnum(t[j]) && t[j] != ' ' && t[j] != '\0')
                t[j] != ' ' && t[j] != '\0';
                    j++;
        }
        if(i < endpos && j < endpos)
        {
            a = fold ? tolower(s[i]):s[i];
            i++;
            b = fold ? tolower(t[j]):t[j];
            j++;
        
            if(a==b && a == '\0')
                return 0;
        }
    }while(a == b && i < endpos && j < endpos);

    return a - b;
}

/* The source file substr.c */

#include<string.h>
void error(char *);

/* substr: get a substring of S and put in str */

void substr(char *s,char *str)
{
    int i,j,len;
    extern int pos1,pos2;

    len = strlen(s);
        
    if( pos2 > 0 && len > pos2)
        len = pos2;
    else if ( pos2 > 0 && len < pos2)
        error("substr: string too short");
    for( j =0, i = pos1; i< len;i++,j++)
        str[j] = str[i];
    str[j] = '\0';
}

/* error: print error message and exit */

void error(char *s)
{
    printf("%s \n",s);
    exit(1);
}

        
void swap(void *v[],int i,int j)
{
    void *temp;
    
    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}

/* myqsort: sort v[left] ... v[right] into increasing order */

void myqsort(void *v[],int left,int right,int (*comp)(void *,void *))
{
    int i,last;
    void swap(void *v[],int,int);

    if(left >= right)       /* do nothing if array contains */
        return;
    
    swap(v,left,(left+right)/2);
    last = left;
        
    for(i = left + 1; i <=right; i++)
        if((*comp)(v[i],v[left])<0)
            swap(v,++last,i);
    swap(v,left,last);

    myqsort(v,left,last-1,comp);
    myqsort(v,last+1,right,comp);
}


#define MAXLEN  1000        /* max length of any input line  */
int mgetline(char *,int);
char *alloc(int);

/* readlines: read input lines */
int readlines(char *lineptr[],int maxlines)
{
    int len,nlines;
    char *p,line[MAXLEN];
    
    nlines=0;
    while((len=mgetline(line,MAXLEN))>0)
        if(nlines >= maxlines || (p = alloc(len)) == NULL)
            return -1;
        else
        {
            line[len-1] = '\0'; /* delete newline */
            strcpy(p,line);
            lineptr[nlines++]=p;
        }
    return nlines;
}

/* writelines: write output lines */
void writelines(char *lineptr[],int nlines)
{
    int i;
    
    for(i = 0;i <nlines;i++)
        printf("%s\n",lineptr[i]);
}


#define ALLOCSIZE 10000         /* size of available space */

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

char *alloc(int n)          /* return pointer to n characters */
{
    if ( allocbuf + ALLOCSIZE - allocp >= n)
    {
        allocp += n;
        return allocp - n;  /* old p */
    }
    else                /* not enough room */
        return 0;
}

void afree(char *p)     /* free storage pointed to by p */
{
    if(p >= allocbuf && p < allocbuf + ALLOCSIZE)
    allocp = p;
}
 

/* mgetline: read a line into s,return length */

int mgetline(char s[],int lim)
{
    int c,i;

    for(i=0;i<lim-1 && (c=getchar())!=EOF c!='\n';++i)
        s[i] = c;
    if(c == '\n')
    {
        s[i] = c;
        ++i;
    }

    s[i] = '\0';
    return i;
}
            

Explanation#