# Exercise 5-17 k&R

This is a discussion on Exercise 5-17 k&R within the C Programming forums, part of the General Programming Boards category; Add a field-searching capability, so sorting may bee done on fields within lines, each field sorted according to an independent ...

1. ## Exercise 5-17 k&R

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.)
This is the code i was following (Tondo's Book)
Code:
```//main.c
#include <stdio.h>
#include <ctype.h>

#define NUMERIC 1
#define DECR 2
#define FOLD 4
#define DIR 8
#define LINES 100

int charcmp(char *, char *);
void error(char *);
int numcmp(char *, char *);
void qusort(void *v[],int left, int right,int (*comp)(void *, void *));
void writelines(char *lineptr[], int nlines, int decr);

char option = 0;
int pos1 = 0;
int pos2 = 0;
int main(int argc, char *argv[])
{
char *lineptr[LINES];
int nlines;
int rc = 0;

if((nlines = readlines(lineptr, LINES)) > 0 ) {
if (option & NUMERIC)
qusort((void **) lineptr, 0 , nlines - 1,
(int (*) (void *, void *)) numcmp);
else
qusort((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;
}

{
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':
option |= DIR;
break;
case 'f':
option |= FOLD;
break;
case 'n':
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]");
}

void writelines(char *lineptr[], int nlines, int decr)
{
int i;
if(decr)
for(i = nlines - 1; i >=0; i--)
printf("%s\n",lineptr[i]);
else
for(i = 0;i <nlines; i++)
printf("%s\n",lineptr[i]);
}

#include <string.h>
#define MAXLEN 1000
int getline(char *, int);
char *alloc(int);
{
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
if (nlines >= maxlines || (p = alloc(len+1)) == NULL)
return -1;
else {
line[len] = '\0'; /* delete newline */
strcpy(p, line);
lineptr[nlines++] = p;
}
return nlines;
}

int getline(char *s, int lim)
{
int c;
char *t = s;
while(--lim > 0 && (c = getchar()) != EOF && c != '\n')
*s++ = c;
*s = '\0';
return s - t;
}

#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)
{ /* it fits */
allocp += n;
return allocp - n; /* old p */
}
else /* not enough room */
return 0;
}

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

if(left >= right)
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);
qusort(v, left, last - 1, comp);
qusort(v, last + 1, right, comp);
}

void swap(void *v[], int i, int j)
{
void *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
//numcmp.c
#include <math.h>
#include <ctype.h>
#include <string.h>

#define MAXSTR 100

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

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
#define DIR        8
int charcmp(char *s, char *t)
{
char a, b;
int i, j, endpos;
extern char option;
extern int pos1, pos2;
int fold = (option & FOLD) ? 1 : 0;
int dir = (option & DIR) ? 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')
i++;
while(j < endpos && !isalnum(t[j]) && 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;
}
//substr.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

void error(char *);

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] = s[i];
str[j] = '\0';
}
void error(char *s)
{
printf("%s \n", s);
exit(1);
}```
gcc main.c numcmp.c substr.c -Wall -Werror -pedantic -g -o SortFields.exe
no errors on compilation.

My problem lies on how to use the arguments on locating the position of the field to be sorted. I am following this link c - K&R Task Exercise 5.17 - Stack Overflow but it doesn't discuss what argument to use to sort the second field.

The instruction "Usage: sort -dfnr [+pos1] [-pos2]" - i don't know how to use this, I only know -dfnr since i have done the previous exercises.The problem lies with what pos1 and pos2 is and use this to sort any field position i want. I think you should look at the readargs() function because i think that's where the problem lies.

2. Originally Posted by BinaryProgamer
gcc main.c numcmp.c substr.c -Wall -Werror -pedantic -g -o SortFields.exe
no errors on compilation.
You should get at least a warning that atof() isn't declared properly in numcmp.c.

And this also looks strange:
Code:
```//numcmp.c
void substr(char *s, char *t, int maxstr);
...
//substr.c
void substr(char *s, char *str)```
Isn't there a parameter to much in numcmp.c?

Anyways, if I fix that I get:
Code:
```\$ cat test.txt
apple  9 3
pear   2 8
orange 6 4
banana 1 4
\$ ./foo -n +7 -8 < test.txt
banana 1 4
pear   2 8
orange 6 4
apple  9 3
\$ ./foo -n +9 -10 < test.txt
apple  9 3
banana 1 4
orange 6 4
pear   2 8```
So, "pos1" is the start of the field and "pos2" one past the end which should also be obvious after reading charcmp() and substr().

Bye, Andreas