Small Correction to K&R Exercise 1-22 Solution on CLC-Wiki

M

Mike S

Hi all,

I noticed a very slight logic error in the solution to K&R Exercise
1-22 on the the CLC-Wiki, located at

http://www.clc-wiki.net/wiki/KR2_Exercise_1-22

The exercise reads as follows:

"Write a program to 'fold' long input lines into two or more shorter
lines after the last non-blank character that occurs before the n-th
column of input. Make sure your program does something intelligent with
very long lines, and if there are no blanks or tabs before the
specified column."

And this is the solution provided on the clc-wiki, due to Rick Dearman
(note that I changed FOLDLENGTH to 25, in order to better show the
algorithm's effect):

/******************************************************
KnR 1-22
--------
Write a program that wraps very long lines of input
into two or more shorter lines.

Author: Rick Dearman
email: (e-mail address removed)

******************************************************/
#include <stdio.h>

#define MAXLINE 1000 /* max input line size */

char line[MAXLINE]; /*current input line*/

int getline(void); /* taken from the KnR book. */


int
main()
{
int t,len;
int location,spaceholder;
const int FOLDLENGTH=25; /* The max length of a line */

while (( len = getline()) > 0 )
{
if( len < FOLDLENGTH )
{
}
else
{
/* if this is an extra long line then we
** loop through it replacing a space nearest
** to the foldarea with a newline.
*/
t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}
}
printf ( "%s", line);
}
return 0;
}


/* getline: specialized version */
int getline(void)
{
int c, i;
extern char line[];

for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '\n'; ++i)
line = c;
if(c == '\n')
{
line = c;
++i;
}
line = '\0';
return i;

}

Suppose this program is compiled and given the following text as input
(in the form of a single long line):

/ The computing world has undergone a revolution since the publication
of The C Programming Language in 1978. /

The program output given this input is shown below, using a FOLDLENGTH
of 25 and '*' column markers to visually indicate where the "fold"
margin is located:

************************* <-- characterss should not go past this
column
The computing world has
undergone a revolution
since the publication of The
C Programming Language
in 1978.

Problem: The word "The" trails beyond the right margin that the program
is supposed to be enforcing. The offending code is in the body the
inner-most loop in main:

t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}

Synopsis: if the program is in the middle of a word and
location==FOLDLENGTH becomes true, then 'spaceholder' contains the
location (in line) of the space character immediately preceding the
word. This space will be replaced by a newline, causing the program to
break the line before the word appears, which is correct behavior.
However, 'location' is set to zero relative to the current location in
the line, 't'. This location is not necessarily the location where the
newline was inserted. This causes the the value of 'location' to be off
by a few characters in situations where the newline is inserted in the
line before the current index 't'.

Remedy: 'location' should be reset relative to where the newline was
inserted, not relative to the current character being processed in
line. That is, the program should be looking for the condition
location==FOLDLENGTH relative to the beginning of the last line, not
the last character processed. Changing the line

location = 0;

to

location = t - spaceholder;

corrects this shortcoming.

Mike S
 
C

CBFalconer

Mike said:
I noticed a very slight logic error in the solution to K&R Exercise
1-22 on the the CLC-Wiki, located at

http://www.clc-wiki.net/wiki/KR2_Exercise_1-22

The exercise reads as follows:

"Write a program to 'fold' long input lines into two or more shorter
lines after the last non-blank character that occurs before the n-th
column of input. Make sure your program does something intelligent with
very long lines, and if there are no blanks or tabs before the
specified column."

And this is the solution provided on the clc-wiki, due to Rick Dearman
(note that I changed FOLDLENGTH to 25, in order to better show the
algorithm's effect):
.... snip ...

Good for you. However, another approach to the problem is embedded
in the following, which I first published quite a while ago. Note
that a negative linelength parameter causes ragged right operation,
which is exactly the effect needed by the above exercize.

/* ----- justify.c -----
Filter text file, right justifying by inserting
spaces between words. Words are anything separated
by blanks, tabs, newlines, formfeeds, bell, etc.

The single (optional) parameter is the output line
length, and defaults to 65. Execution without any
input redirections causes a help message.

This is a quick and dirty utility.
Released to public domain by:
<mailto:[email protected]>
*/

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

#define RHDEFAULT 65
#define RHMIN 20

static int rhcol; /* right hand column limit */
static int ragged; /* No rh justification, 0 init */

/* ------------------- */

/* This is very likely to be non-portable */
/* DOES NOT check fp open for reading */
/* NULL fp is considered a keyboard here! */
static int akeyboard(FILE *fp)
{
#ifndef __TURBOC__
# ifdef __STDC__
/* This dirty operation allows gcc -ansi -pedantic */
extern int fileno(FILE *fp);
extern int isatty(int fn);
# endif
#endif
return ((fp != NULL) && isatty(fileno(fp)));
} /* akeyboard */

/* ------------------- */

static void help(char *phrase1, char *phrase2)
{
if (phrase1) fprintf(stderr, "%s", phrase1);
if (phrase2) fprintf(stderr, "%s", phrase2);
fprintf(stderr, "\n"
"Usage: justify [rightmargin] <infile >outfile\n"
" The default rightmargin is 65\n"
" and values less than 20 are rejected\n"
"\n"
"A large value of rightmargin will effectively\n"
"convert all paragraphs into single lines\n"
"\n"
"A negative rightmargin causes ragged right\n"
"\n"
"A blank line delimits paragraphs\n");
} /* help */

/* ------------------- */

static int initialize(int argc, char *argv[])
{
long rightcol;
char *err;

if (akeyboard(stdin) || (argc > 2)) {
help(NULL, NULL);
return 0;
}
rhcol = RHDEFAULT;
if (2 == argc) {
rightcol = strtol(argv[1], &err, 10);
if (rightcol < 0) {
rightcol = -rightcol;
ragged = 1;
}
if ((err == argv[1]) || (rightcol < RHMIN)) {
help("Bad argument: ", argv[1]);
return 0;
}
else rhcol = rightcol;
}
return 1;
} /* initialize */

/* ------------------- */

static void cleanup(void)
{
} /* cleanup */

/* ------------------- */

/* ================================== */
/* Routines for text input and output */
/* ================================== */

static void skipblanks(FILE *f)
{
int ch;

while ( (' ' == (ch = getc(f))) || ('\t' == ch) ||
('\v' == ch) || ('\f' == ch) || ('\a' == ch) )
continue;
ungetc(ch, f);
} /* skipblanks */

/* ------------------- */

/* The file is assumed to hold no control chars */
/* other than \n \t \v \a and \f. A blank line */
/* marks a paragraph ending word */
static int nextword(FILE *f, char *buffer, int max)
{
int i, ch;

skipblanks(f);
if (EOF == (ch = getc(f))) return 0;

/* Detect paragraph endings as \n\n */
if ('\n' == ch) {
skipblanks(f); ch = getc(f);
if ('\n' == ch) { /* paragraph ending */
buffer[0] = buffer[1] = ch; /* wd = "\n\n" */
buffer[2] = '\0';
/* now we have to absorb any more blank lines */
do {
skipblanks(f); ch = getc(f);
} while ('\n' == ch);
ungetc(ch, f);
return 1;
}
}
/* now ch holds the first non-blank. Use all printable */
if (EOF == ch) return 0;
if (!isgraph(ch)) {
fprintf(stderr, "'%c', 0x%x WARN: Invalid character\n",
ch, (unsigned)ch);
}

i = 0;
do {
buffer[i++] = ch;
if (i >= max) { /* truncate over long words */
i--;
break; /* leaving ch for next word */
}
ch = getc(f);
} while (isgraph(ch));

ungetc(ch, f); /* save for next word, may be \n */
buffer = '\0'; /* terminate string */
return 1;
} /* nextword */

/* ------------------- */

static void justify(char *ln, int wdgaps, int xtra, FILE *out)
{
int insert, i;
static int oddln = 0; /* for rt left blank insertion */
char ch;

#ifdef DEBUG
fprintf(out, "%2d %2d ", wdgaps, xtra);
#endif
insert = 0; oddln = !oddln;
if (wdgaps)
while (xtra > wdgaps) {
insert++; xtra -= wdgaps;
}
while ((ch = *ln++)) {
putc(ch, out);
if (' ' == ch) {
if (xtra) {
xtra--;
putc(' ', out);
}
for (i = insert; i; i--) putc(' ', out);
}
}
putc('\n', out);
} /* justify */

/* ------------------- */

static int filter(FILE *in, FILE *out)
{
char *buf;
char *ln;
int wdcount, lnlgh, wdlgh;
char *eop = "\n\n"; /* end of paragraph */
int done, endpar;

if (!(buf = malloc(rhcol+1))) exit(EXIT_FAILURE);
if (!(ln = malloc(rhcol+1))) exit(EXIT_FAILURE);

done = !nextword(in, buf, rhcol + 1);
endpar = !strcmp(buf, eop);

while (!endpar && !done) {
/* form paragraph */
wdlgh = strlen(buf);
wdcount = 0;
*ln = '\0'; lnlgh = 0;

while ((((lnlgh + wdlgh) < rhcol) || !lnlgh)
&& !done && !endpar) {
/* form a line */
if (lnlgh) ln[lnlgh++] = ' ';
strcpy(ln + lnlgh, buf);
lnlgh += wdlgh;
wdcount++;

done = !nextword(in, buf, rhcol + 1);
endpar = !strcmp(buf, eop);
wdlgh = strlen(buf);
}

/* dump the line, wdcount words */
if (endpar || done) lnlgh = rhcol;
if (ragged) fprintf(out, "%s\n", ln);
else justify(ln, wdcount-1, rhcol-lnlgh, out);

if (endpar) {
fputc('\n', out);
done = !nextword(in, buf, rhcol + 1);
endpar = !strcmp(buf, eop);
}
}
return 0;
} /* filter */

/* ------------------- */

int main(int argc, char *argv[])
{
if (!initialize(argc, argv)) return EXIT_FAILURE;
else {
(void)filter(stdin, stdout);
cleanup();
}
return 0;
} /* main */
 
M

Mike S

CBFalconer said:
... snip ...

Good for you. However, another approach to the problem is embedded
in the following, which I first published quite a while ago. Note
that a negative linelength parameter causes ragged right operation,
which is exactly the effect needed by the above exercize.

<snip>

For a "quick and dirty" program, your solution is pretty cool, and I
noticed it wraps long unbroken lines (no blanks or tabs) correctly.
I'll have to do a more thourough read-through of the code to get a good
handle on how you managed to pull it off ;-)

Mike S
 
N

Netocrat

Mike said:
Hi all,

I noticed a very slight logic error in the solution to K&R Exercise 1-22
on the the CLC-Wiki, located at

http://www.clc-wiki.net/wiki/KR2_Exercise_1-22

Your fix looks correct to me at least. How about you edit the code on the
wiki and add your analysis to the discussion page?

I've spotted another bug that I won't point out in case readers would like
to find it for themselves.
The exercise reads as follows:

"Write a program to 'fold' long input lines into two or more shorter lines
after the last non-blank character that occurs before the n-th column of
input. Make sure your program does something intelligent with very long
lines, and if there are no blanks or tabs before the specified column."

Aside from that, I don't think that overwriting the n-th character with a
newline when a line contains no spaces before the n-th character conforms
to the spirit or the letter of the exercise.

So, a small challenge for c.l.c readers: what's the smallest possible change
that could be made to this code that would preserve all input characters in
the output for over-length words without breaking the code's existing
conformance to the exercise's wording?

To fully complete the challenge, the adjustment should retain the fix
suggested by Mike S as well as fix the other unidentified bug.

Extra info: the existing code is already classified "category 1", meaning
that "it uses aspects of C which may not have been covered at the point in
the book at which the exercise appears", so use of pointer and dereference
operators is allowed.

[rest of post quoted unmodified aside from some whitespace reformatting of the
code]
And this is the solution provided on the clc-wiki, due to Rick Dearman
(note that I changed FOLDLENGTH to 25, in order to better show the
algorithm's effect):

/******************************************************
KnR 1-22
--------
Write a program that wraps very long lines of input
into two or more shorter lines.

Author: Rick Dearman
email: (e-mail address removed)

******************************************************/
#include <stdio.h>

#define MAXLINE 1000 /* max input line size */

char line[MAXLINE]; /*current input line*/

int getline(void); /* taken from the KnR book. */


int
main()
{
int t,len;
int location,spaceholder;
const int FOLDLENGTH=25; /* The max length of a line */

while (( len = getline()) > 0 )
{
if( len < FOLDLENGTH )
{
}
else
{
/* if this is an extra long line then we
** loop through it replacing a space nearest
** to the foldarea with a newline.
*/
t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}
}
printf ( "%s", line);
}
return 0;
}


/* getline: specialized version */
int getline(void)
{
int c, i;
extern char line[];

for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '\n'; ++i)
line = c;
if(c == '\n')
{
line = c;
++i;
}
line = '\0';
return i;

}

Suppose this program is compiled and given the following text as input
(in the form of a single long line):

/ The computing world has undergone a revolution since the publication
of The C Programming Language in 1978. /

The program output given this input is shown below, using a FOLDLENGTH
of 25 and '*' column markers to visually indicate where the "fold"
margin is located:

************************* <-- characterss should not go past this column
The computing world has
undergone a revolution
since the publication of The
C Programming Language
in 1978.

Problem: The word "The" trails beyond the right margin that the program
is supposed to be enforcing. The offending code is in the body the
inner-most loop in main:

t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}

Synopsis: if the program is in the middle of a word and
location==FOLDLENGTH becomes true, then 'spaceholder' contains the
location (in line) of the space character immediately preceding the
word. This space will be replaced by a newline, causing the program to
break the line before the word appears, which is correct behavior.
However, 'location' is set to zero relative to the current location in
the line, 't'. This location is not necessarily the location where the
newline was inserted. This causes the the value of 'location' to be off
by a few characters in situations where the newline is inserted in the
line before the current index 't'.

Remedy: 'location' should be reset relative to where the newline was
inserted, not relative to the current character being processed in line.
That is, the program should be looking for the condition
location==FOLDLENGTH relative to the beginning of the last line, not the
last character processed. Changing the line

location = 0;

to

location = t - spaceholder;

corrects this shortcoming.
 
N

Netocrat

Mike said:
Hi all,

I noticed a very slight logic error in the solution to K&R Exercise 1-22
on the the CLC-Wiki, located at

http://www.clc-wiki.net/wiki/KR2_Exercise_1-22

Your fix looks correct to me at least. How about you edit the code on the
wiki and add your analysis to the discussion page?

I've spotted another bug that I won't point out in case readers would like
to find it for themselves.
The exercise reads as follows:

"Write a program to 'fold' long input lines into two or more shorter lines
after the last non-blank character that occurs before the n-th column of
input. Make sure your program does something intelligent with very long
lines, and if there are no blanks or tabs before the specified column."

Aside from that, I don't think that overwriting the n-th character with a
newline when a line contains no spaces before the n-th character conforms
to the spirit or the letter of the exercise.

So, a small challenge for c.l.c readers: what's the smallest possible change
that could be made to this code that would preserve all input characters in
the output for over-length words without breaking the code's existing
conformance to the exercise's wording?

To fully complete the challenge, the adjustment should retain the fix
suggested by Mike S as well as fix the other unidentified bug.

Extra info: the existing code is already classified "category 1", meaning
that "it uses aspects of C which may not have been covered at the point in
the book at which the exercise appears", so use of pointer and dereference
operators is allowed.

[rest of post quoted unmodified aside from some whitespace reformatting of the
code]
And this is the solution provided on the clc-wiki, due to Rick Dearman
(note that I changed FOLDLENGTH to 25, in order to better show the
algorithm's effect):

/******************************************************
KnR 1-22
--------
Write a program that wraps very long lines of input
into two or more shorter lines.

Author: Rick Dearman
email: (e-mail address removed)

******************************************************/
#include <stdio.h>

#define MAXLINE 1000 /* max input line size */

char line[MAXLINE]; /*current input line*/

int getline(void); /* taken from the KnR book. */


int
main()
{
int t,len;
int location,spaceholder;
const int FOLDLENGTH=25; /* The max length of a line */

while (( len = getline()) > 0 )
{
if( len < FOLDLENGTH )
{
}
else
{
/* if this is an extra long line then we
** loop through it replacing a space nearest
** to the foldarea with a newline.
*/
t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}
}
printf ( "%s", line);
}
return 0;
}


/* getline: specialized version */
int getline(void)
{
int c, i;
extern char line[];

for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '\n'; ++i)
line = c;
if(c == '\n')
{
line = c;
++i;
}
line = '\0';
return i;

}

Suppose this program is compiled and given the following text as input
(in the form of a single long line):

/ The computing world has undergone a revolution since the publication
of The C Programming Language in 1978. /

The program output given this input is shown below, using a FOLDLENGTH
of 25 and '*' column markers to visually indicate where the "fold"
margin is located:

************************* <-- characterss should not go past this column
The computing world has
undergone a revolution
since the publication of The
C Programming Language
in 1978.

Problem: The word "The" trails beyond the right margin that the program
is supposed to be enforcing. The offending code is in the body the
inner-most loop in main:

t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}

Synopsis: if the program is in the middle of a word and
location==FOLDLENGTH becomes true, then 'spaceholder' contains the
location (in line) of the space character immediately preceding the
word. This space will be replaced by a newline, causing the program to
break the line before the word appears, which is correct behavior.
However, 'location' is set to zero relative to the current location in
the line, 't'. This location is not necessarily the location where the
newline was inserted. This causes the the value of 'location' to be off
by a few characters in situations where the newline is inserted in the
line before the current index 't'.

Remedy: 'location' should be reset relative to where the newline was
inserted, not relative to the current character being processed in line.
That is, the program should be looking for the condition
location==FOLDLENGTH relative to the beginning of the last line, not the
last character processed. Changing the line

location = 0;

to

location = t - spaceholder;

corrects this shortcoming.
 
M

Mike S

Netocrat said:
Your fix looks correct to me at least. How about you edit the code on the
wiki and add your analysis to the discussion page?

I'm wondering now if it would be much benefit to change the Wiki -- I
found the other bug that you mentioned and am debating whether it's
worth posting my fix if it's still an incomplete solution. Or is it OK
to post incremental changes to the WIki?
I've spotted another bug that I won't point out in case readers would like
to find it for themselves.


Aside from that, I don't think that overwriting the n-th character with a
newline when a line contains no spaces before the n-th character conforms
to the spirit or the letter of the exercise.

Agreed. As I hinted above, I think I know what the other bug is, but
I'll keep the guessing game going for the other readers :)
So, a small challenge for c.l.c readers: what's the smallest possible change
that could be made to this code that would preserve all input characters in
the output for over-length words without breaking the code's existing
conformance to the exercise's wording?

To fully complete the challenge, the adjustment should retain the fix
suggested by Mike S as well as fix the other unidentified bug.

Extra info: the existing code is already classified "category 1", meaning
that "it uses aspects of C which may not have been covered at the point in
the book at which the exercise appears", so use of pointer and dereference
operators is allowed.

[rest of post quoted unmodified aside from some whitespace reformatting of the
code]
And this is the solution provided on the clc-wiki, due to Rick Dearman
(note that I changed FOLDLENGTH to 25, in order to better show the
algorithm's effect):

/******************************************************
KnR 1-22
--------
Write a program that wraps very long lines of input
into two or more shorter lines.

Author: Rick Dearman
email: (e-mail address removed)

******************************************************/
#include <stdio.h>

#define MAXLINE 1000 /* max input line size */

char line[MAXLINE]; /*current input line*/

int getline(void); /* taken from the KnR book. */


int
main()
{
int t,len;
int location,spaceholder;
const int FOLDLENGTH=25; /* The max length of a line */

while (( len = getline()) > 0 )
{
if( len < FOLDLENGTH )
{
}
else
{
/* if this is an extra long line then we
** loop through it replacing a space nearest
** to the foldarea with a newline.
*/
t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}
}
printf ( "%s", line);
}
return 0;
}


/* getline: specialized version */
int getline(void)
{
int c, i;
extern char line[];

for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '\n'; ++i)
line = c;
if(c == '\n')
{
line = c;
++i;
}
line = '\0';
return i;

}

Suppose this program is compiled and given the following text as input
(in the form of a single long line):

/ The computing world has undergone a revolution since the publication
of The C Programming Language in 1978. /

The program output given this input is shown below, using a FOLDLENGTH
of 25 and '*' column markers to visually indicate where the "fold"
margin is located:

************************* <-- characterss should not go past this column
The computing world has
undergone a revolution
since the publication of The
C Programming Language
in 1978.

Problem: The word "The" trails beyond the right margin that the program
is supposed to be enforcing. The offending code is in the body the
inner-most loop in main:

t = 0;
location = 0;
while(t<len)
{
if(line[t] == ' ')
spaceholder = t;

if(location==FOLDLENGTH)
{
line[spaceholder] = '\n';
location = 0;
}
location++;
t++;
}

Synopsis: if the program is in the middle of a word and
location==FOLDLENGTH becomes true, then 'spaceholder' contains the
location (in line) of the space character immediately preceding the
word. This space will be replaced by a newline, causing the program to
break the line before the word appears, which is correct behavior.
However, 'location' is set to zero relative to the current location in
the line, 't'. This location is not necessarily the location where the
newline was inserted. This causes the the value of 'location' to be off
by a few characters in situations where the newline is inserted in the
line before the current index 't'.

Remedy: 'location' should be reset relative to where the newline was
inserted, not relative to the current character being processed in line.
That is, the program should be looking for the condition
location==FOLDLENGTH relative to the beginning of the last line, not the
last character processed. Changing the line

location = 0;

to

location = t - spaceholder;

corrects this shortcoming.

 
F

Flash Gordon

Mike said:
I'm wondering now if it would be much benefit to change the Wiki -- I
found the other bug that you mentioned and am debating whether it's
worth posting my fix if it's still an incomplete solution. Or is it OK
to post incremental changes to the WIki?

Incremental changes are fine. We did not get everything up there in one
fell swoop and we don't have everything we want yet.

However, this is not really the place to discuss policy on editing the Wiki.
 
M

Mike S

My fix is now reflected at the above address.
Your fix looks correct to me at least. How about you edit the code on the
wiki and add your analysis to the discussion page?

I've spotted another bug that I won't point out in case readers would like
to find it for themselves.


Aside from that, I don't think that overwriting the n-th character with a
newline when a line contains no spaces before the n-th character conforms
to the spirit or the letter of the exercise.

So, a small challenge for c.l.c readers: what's the smallest possible change
that could be made to this code that would preserve all input characters in
the output for over-length words without breaking the code's existing
conformance to the exercise's wording?

To fully complete the challenge, the adjustment should retain the fix
suggested by Mike S as well as fix the other unidentified bug.

Here is my answer to the challenge, though it is only guaranteed to
work if the input is 7-bits-packed-in-8-bits ASCII, because I take
advantage of the sign bit in order to fit the notion of a printable
char and a line-break into one array location when no spaces occur in a
line. The reasoning behind this design choice was that I didn't want to
go through the trouble (and the extra code) of making room in the array
for the line break in this case, so I thought why not squeeze it into a
single char location by letting a set sign bit indicate that a line
break is needed? I also added a line or two to handle tabs correctly;
it assumes a tabstop of 8 (as the "de facto" tabstop, it's good enough
for me...). All the changes I made are confined to main(); I left the
rest of the code alone. I also made a conscious effort not to define
any new variables in my version, so, all in all, I'd say my solution
makes only a minimal change, but I won't claim it's the smallest
possible change. I'm hoping other clc readers will submit their
solutions to the challenge. It's always interesting to see how
different people attack the same problem.

/******************************************************
Answer to Netocrat's challenge (K&R 1-22)
Author: Mike S, adapted from code by Rick Dearman
******************************************************/
#include <stdio.h>

#define MAXLINE 1000 /* max input line size */

char line[MAXLINE]; /*current input line*/

int getline(void); /* taken from the KnR book. */

int main()
{
int t,len;
int location,spaceholder;
const int FOLDLENGTH=25; /* The max length of a line: set to 25 to
make it really obvious that the program is working */

spaceholder = 0;
while ((len = getline()) > 0)
{

t = 0;
location = 0;
while (t < len)
{
if (line[t] == ' ' || line[t] == '\t')
{
spaceholder = t;
}
if (location >= FOLDLENGTH)
{
if (line[spaceholder] == ' ' || line[spaceholder] == '\t')
{
line[spaceholder] = '\n';
location = t - spaceholder;
}
else /* no spaces or tabs found in this line */
{
line[t] = -line[t]; /* negative is as our
out-of-bound signal
for 'print this char
and insert a line-break' */
location = 0;
}
}
if (line[t] == '\t')
{
location = (location & ~7) + 8; /* handle tabs correctly
(assumes tabstop is
every 8 columns) */
}
else
{
location++;
}

t++; /* check next char */
}
/* print the line,
* negative chars are converted
* to '\n' + positive version
* of the char
*/
t = 0;
while (line[t])
{
if (line[t] < 0)
{
line[t] = -line[t];
putchar('\n');
}
putchar(line[t]);
t++;
}
}
return 0;
}


/* getline: specialized version */
int getline(void)
{
int c, i;
extern char line[];

for (i = 0; i<MAXLINE-1 && (c=getchar()) != EOF && c != '\n'; ++i)
line = c;
if (c == '\n')
{
line = c;
++i;
}
line = '\0';
return i;
}
 
N

Netocrat

[excuse the previous double-posting - a glitch in the initial posting
combined with my unfamiliarity with a new test version of the newsreader
that I use led me to believe that the initial post failed and I didn't
wait long enough to check for its non-appearance to confirm this]
My fix is now reflected at the above address.

Are you going to add your analysis too?

Your code answering the challenge includes the obvious fix for this bug -
partial confirmation that you have, as you wrote in your previous post,
found the same bug.
Here is my answer to the challenge, though it is only guaranteed to work
if the input is 7-bits-packed-in-8-bits ASCII, because I take advantage
of the sign bit in order to fit the notion of a printable char and a
line-break into one array location when no spaces occur in a line. The
reasoning behind this design choice was that I didn't want to go through
the trouble (and the extra code) of making room in the array for the
line break in this case, so I thought why not squeeze it into a single
char location by letting a set sign bit indicate that a line break is
needed?

Here's an insight that could be used to avoid both choices: nothing in the
exercise requires output to occur in one final step.
I also added a line or two to handle tabs correctly; it assumes a
tabstop of 8 (as the "de facto" tabstop, it's good enough for me...).

That change goes beyond the challenge, but it seems sensible. It would be
useful to make tab width configurable through a macro though.

[...(including code)...]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top