Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 1.22 on page 34

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.



Solution by Rick Dearman

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

   Author: Rick Dearman
   email: rick@ricken.demon.co.uk

******************************************************/
#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=70; /* 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[i] = c;
  if(c == '\n') 
    {
      line[i] = c;
      ++i;
    }
  line[i] = '\0';
  return i;

}

Solution by Pilcrow

/*********************************************************************
Mr Dearman's code assumes that there will be at least one blank before
the 'Fold-point".  Since this assumption is unfounded, his code will
fail on the first long line.  In addition, he fails to initialize a
variable 'spaceholder' that he subsequently uses as an array index.
I hope this is a better algorithm.
-- Pilcrow
*********************************************************************/
#include <stdio.h>

#define MAXLINE 1000        /* input line max */
#define LINEFOLD 70          /* fold point max */

char line[MAXLINE+1];
char fold_segment[MAXLINE+1];

int getline(void);

int main(void)
{
    int space_spot, f_move, col, lapse;
    int len; /* len is len of input line or segment still unfolded */
    int last_space;  /* index of rightmost space before fold point */

    while((len = getline()) > 0) {
        while(len){
            if(len > LINEFOLD) {  /* folding needed */
                last_space = LINEFOLD-1; /* fold here if no spaces */

                /* find last space (if any) before LINEFOLD */
                for(space_spot = LINEFOLD-1; space_spot > 0; space_spot--) {
                    if(line[space_spot] == ' ') {
                        last_space = space_spot;
                        break;
                    }
                }

                /* format & print segment before last_space */
                for(f_move=0; f_move <= last_space; ++f_move)
                    fold_segment[f_move] = line[f_move];
                fold_segment[f_move] = '\0';/* terminate new line */
                puts(fold_segment);              /* and output it */

                /* collapse input line to eliminate segment printed */
                for(col=0, lapse = f_move; lapse <= len; ++col, ++lapse)
                    line[col] = line[lapse];

                len -= last_space;  /* adjust remaining line length */
            }else{
                int l;
                for(l=0; line[l] != '\0'; l++); /* homegrown strlen */
                if(l > 0)puts(line);/* short segment out */
                len = 0;                  /* force more input */
            }
        }
    }
    return 0;
}

int getline(void)
{
    int c, i;
    for(i = 0; i < MAXLINE && (c=getchar()) != EOF && c != '\n'; ++i)
        line[i] = c;
    line[i] = '\0';
    if(c == '\n') ++i;
    return i;
}



Solution by TheSunShadow

Here another solution to this exercice, not as elegant as it could be, but well... at least this one does not depend of a max length in the input lines

#include <stdio.h>

#define TAB 4       // This is the size of the tab columns.

#define MAXSITE 40  // Max number of characters in a line,
		    // must be larger than the longest word.
main()
{
  int site = 0, last = 0, c, i, col = 0;
  char line[MAXSITE];
	
  while((c = getchar()) != EOF){
		
    line[site] = c;    // We store each line in a temporary array
						
    if(c == '\t' && col <= MAXSITE - TAB){  // This controls the
					    // correct spacing
      for(i = col%TAB; i < TAB ; ++i){      // of the text with 
        line[site] = ' ';                   // the tabs sizes.
        ++site;
      }
				
      col += (TAB - col%TAB);
    }
		
    if(c != '\t'){
      ++site;
      ++col;
    }
				
    if(c == ' ' || c == '\t')
      last = site - 1;    // This is a marker of the last
			  // white space in a line.
								
    if(c == '\n'){          // Lines shorter than the max
      line[site] = '\0';    // lenght are written 'as is'.
      printf("%s", line);
      site = last = 0;
      col = 0;
    }
			 
    if(site == MAXSITE){    // Lines longer than the max lenght
			    // are written until the last space.
      for(i = 0; i < last; ++i)
        printf("%c", line[i]);
			
      putchar('\n');
			
      for(i = 0; i < MAXSITE - last; ++i)
        if(line[last + i + 1] != ' ' || line[last + i + 1] != '\t')
          line[i] = line[last + i + 1];
			
      site = MAXSITE - last - 1;
			
      col = site;
    }
  }
	
  for(i = 0; i < site; ++i)    // This writes the last input line.
    printf("%c", line[i]);
		
  putchar('\n');
}

Solution by Donald Goodman

This solution is "Category 1" also, because it implements recursion. It also puts the line breaking into its own function, which is appropriate even at the end of the tutorial; it's a separate task, so it deserves its own function. In any case, recursion greatly simplified the problem, so I hope this helps others.

One issue with this program is that it takes no account of double spaces, after periods or elsewhere; so if a break is done after a period followed by a double space, the new line will begin with a space, which is not optimal. Also, tabs should probably be reduced; this program does not do so, treating them simply as normal characters. Thus, while the lines are in fact broken after a given number of characters, tabs will make them appear longer.

The default line length is very short here; this reduces the amount that needs to be typed in testing.

If you have any improvements or suggestions, please post them to my User:Dgoodmaniii profile page.

/* +AMDG */
/*
 * A program to fold long input lines at the nearest space
 * prior to the length limit.  Lines longer than the limit
 * without any spaces are put all by themselves and not
 * broken.
 *
 */

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

#define MAXLINE 10000
#define LIMIT 20

int getline(char s[], int lim);
int cut(char s[], int start);

int main(void)
{
	int i;
	int length;
	char string[MAXLINE];

	while ((length = getline(string,MAXLINE)) > 0) {
		if (length > LIMIT) {
			cut(string, 0);
			printf("%s",string);
		}
		else
			printf("%s",string);
	}
	return 0;
}

int cut(char s[], int start)
{
	int i,j;
	int spaces = 0;

	for(i=start+LIMIT; i > start && s[i] != ' ' && s[i] != '\t'; --i);
	if (i == start) {
		for(i=start; s[i] != ' ' && s[i] != '\t'; ++i);
		s[i] = '\n';
	}
	if ((strlen(s) - i) <= LIMIT) {
		s[i] = '\n';
	}
	else if (i > start && i != start) { 
		s[i] = '\n';
		cut(s, i);
	}
	return 0;
}

int getline(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;
	s[i] = '\0';
	return i;
}

Solution by Flavio Ferreira Santos

I hope you guys appreciate my solution. If you have any improvements or suggestions, please email me Flavio Ferreira Santos.

/******************************************************
 KnR 1-22                                            *
 --------
 Write a program that wraps very long lines of input
 into two or more shorter lines.
 
 Author: Flavio Ferreira Santos
 email: flaviofsantos@gmail.com
 
 ******************************************************/

#include <stdio.h>

#define FOLDLIMIT 10    // fold limit

void print_array(char line[], int n);

/* Pseudocode
 * save sequence of (lettes or spaces) in buffer
 * save its size
 * case word
 *   if line size + word size > FOLD LIMIT
 *        print new line, print word, and turn word size the line size
 *   else
 *        print word, and add word size to line size */

int main(void)
{    
     int c, sline, sword, sspace;  // char, line size, word size, space size
     char word[100], space[100];   // buffers
     int inword;
     
     inword = sline = sword = sspace = 0;
     while ((c = getchar()) != EOF) {
          if (c == '\n') {               
               if (sline + sword > FOLDLIMIT) 
                    putchar('\n');
               print_array(word, sword);                    
               putchar('\n');
               inword = sline = sword = sspace = 0;
          } else if (c == ' ' || c == '\t') {
               if (inword) {
                    inword = 0;
                    if (sline + sword > FOLDLIMIT) {
                         putchar('\n');
                         print_array(word, sword);
                         sline = sword;
                         sword = 0;
                    } else {
                         print_array(word, sword);
                         sline += sword;
                         sword = 0;
                    }
               }
               space[sspace++] = c;
          } else {
               if (!inword) {
                    inword = 1;                    
                    print_array(space, sspace);
                    sline += sspace;
                    sspace = 0;
               }
               word[sword++] = c;
          }
     }
     
     return 0;
}

void print_array(char line[], int n) {
     int i;
     
     for (i = 0; i < n; i++)
          putchar(line[i]);
}

Solution by CakeOFTrust

Cryptic names are the bane.

#include <stdio.h>

#define YES 1
#define NO 0

int main(void)
{
  int TCOL = 8, ch, co[3], i, COL = 19, tabs[COL - 1];
  char bls[COL - 1], bonly = YES;

  co[0] = co[1] = co[2] = 0;

  while ((ch = getchar()) != EOF)
  {
      if (ch != '\t') {
          ++co[0];
          ++co[2];
      }

      else {
          co[0] = co[0] + (TCOL * (1 + (co[2] / TCOL)) - co[2]);
          i = co[2];
          co[2] = TCOL + (co[2] / TCOL) * TCOL;
      }

      if (ch != '\n' && ch != ' ' && ch != '\t')
      {
          if (co[0] >= COL) {
              putchar('\n');

              co[0] = 1;
              co[1] = 0;
          }

          else
              for (i = co[1]; co[1] > 0; --co[1])
              {
                  if (bls[i - co[1]] == ' ')
                      putchar(bls[i - co[1]]);

                  else
                      for (; tabs[i - co[1]] != 0;)

                          if (tabs[i - co[1]] > 0) {
                              putchar(' ');
                              --tabs[i - co[1]];
                          }

                          else {
                              tabs[i - co[1]] = 0;
                              putchar(bls[i - co[1]]);
                          }
              }

          putchar(ch);

          if (bonly == YES)
              bonly = NO;
      }

      else if (ch != '\n')
      {
          if (co[0] >= COL)
          {
              if (bonly == NO) {
                  putchar('\n');

                  bonly = YES;
              }

              co[0] = co[1] = 0;
          }

          else if (bonly == NO) {
              bls[co[1]] = ch;

              if (ch == '\t') {

                  if (TCOL * (1 + ((co[0] - (co[2] - i)) / TCOL)) -
                    (co[0] - (co[2] - i)) == co[2] - i)
                      tabs[co[1]] = -1;

                  else
                      tabs[co[1]] = co[2] - i;
              }

              ++co[1];
          }

          else
              co[0] = co[1] = 0;
      }

      else {
          putchar(ch);

          if (bonly == NO)
              bonly = YES;

          co[0] = co[1] = co[2] = 0;
      }
  }

  return 0;
}


Solution by Scopych

#include <stdio.h>

#define LINE_WIDTH 30
#define MAX_WORD_LEN 29   // less then line width

/* Author: Scopych
   Mail: scopych@gmail.com
   Date:   21.05.2018
   Purpose: the program folds long input line
      into two or more shorter lines after th
      non-blank character that occurs befor t
      n-th column of input.K&R2 ex.1-22.
*/

int getWord (int head); // extract word from input

char word[MAX_WORD_LEN];
int ch;

int main(void) {
   extern int ch;
   int lindex = 0;   // line index (position)
   int lenWord = 0;  // lenght of a word
   extern char word[];  // holds current word

   while ((ch = getchar()) != EOF) {
      if (ch == ' ' || ch == '\t' || 
                         ch == '\n') {
         putchar(ch);
         lindex++;
      } else {
         lenWord = getWord(ch);
         lindex += lenWord;
         if (lindex < LINE_WIDTH - 2) {
            printf("%s", word);
            putchar(ch);
            lindex++;
         } else {
            putchar('\n');
            putchar('\0');
            lindex = lenWord;
            lenWord = 0;
            printf("%s", word);
            putchar(ch);
         }
      }
   }
   return 0;
}

int getWord (int head) {
   extern char word[];
   extern int ch;
   int i, indx;

// before use a word, assign all array to 0-s.
   for (indx = 0; indx <= 100; ++indx) {  
      word[indx] = '\0';
   }
   word[0] = head;
   for (i = 1; i < MAX_WORD_LEN - 1
      && (ch = getchar()) != ' ' && ch != '\t
      && ch != '\n'; ++i) {
      word[i] = ch;
   }
   return i;
}

Solution by Luke Panayi

I'm tempted to call this an extremely simple solution compared to the rest here, but perhaps I'm not handling the specifications of the question properly.

#include <stdio.h>
#define fold 12
#define maxLine 1000

int main() {

	int i, j, c;
	char line[maxLine];

	for (i = 0, j = 0; i < maxLine-1 && (c=getchar()) != EOF; ++i, ++j) {
		if (c == ' ' && j >= fold) { /*adds a newline character upon seeing the first blank character after the j counter passes the fold limit*/
			j = 0; /*sets the j counter back to 0 such that lines are folded continiously throughout input*/
			line[i] = c;
			line[++i] = '\n';
		}
		else {
			line[i] = c;
		}
		if (j > fold*3) { /*arbitary multiple of fold limit to deal with very long lines without blank characters*/
			j = 0;
			line[i] = c;
			line[++i] = '\n';
		}
	}

	line[i] = '\0';
	printf("%s", line);

	return 0;
}

Solution by i9383

Think a few days If have some wrong welcome tell me

#include <stdio.h>
#define COLUMN 5 /*Define COLUMN length*/
#define LIM 15 /*Define LIM for max string of line*/
#define TAB 8 /*Define TAB for '\t' length*/ /*Used for if input	A	A Thinks column is 9*/

int getlinei(char s[], int lim); /*Get new line*/

main()
{
    int i, j, blank, state, tabcount, state2;
    char s[1000]; /*Array s Used for store*/

    while (getlinei(s, 1000)) {        /*If length from getlinei returned != 0*/
        j = 0;                         /*Every new line reset j to 0 Used for count every character
		                         If larger than or equal COLUMN or larger than LIM*/
        state = -1;                    /*Every new line  reset state to -1 If set to 0
		                         When beginning with ' ' '\t' '\n' will output*/
	                               /*Used for in or out newline state*/
        tabcount = 0;                  /*Every new line reset tabcount to 0 position*/
        blank = 0;                     /*Every new line reset blank to 0 Used for count ' ' '\t' '\n'*/
        for (i = 0; s[i] != '\0'; ++i) { /*Calculate Array s Every time i position add 1*/
        ++j;                           /*Every new character add 1 number*/
        if (s[i] == ' ' || s[i] == '\t' || s[i] == '\n')          /*Count blank*/
            ++blank;
        if (s[i] != '\t')              /*Tab position add 1 If s[i] not equal '\t'*/
            ++tabcount;
        if (tabcount == TAB)           /*If tabcount equal TAB set tabcount position to 0*/
            tabcount = 0;
        if (j >= COLUMN)               /*If j larger than or equal COLUMN*/
            if (s[i] == ' ' || s[i] == '\t') {
                if (blank != j) {      /*If blank not equal j output '\n' and Reset*/
                    putchar('\n');     /*Output '\n' to shorter line*/
                    state = 1;         /*If set state to 1 After '\n' If meet ' ' '\t' '\n'
				         Will not output Until meet no blank character*/
                    j = 0;             /*Reset j number of postition to 0 If after output '\n'*/
                    blank = 0;         /*Reset blank number*/
                }
            }
        else if (j > LIM) {            /*If j larger than max string 15*/
	    if (blank != j) {
                putchar('\n');
                state = 1;
                j = 0;
	    }                          /*Maybe did not need set blank to 0 If have one ' ' '\t' '\n' before if is executed*/
        }
        if (s[i] == '\t')              /*If s[i] equal '\t' Used for if input like
			                                              	A	A
									A'\t'A
									Thinks of j equal 9*/
            if ((j + TAB - tabcount - 1) >= COLUMN)          /*If j = 2 Tabcount position = 5 TAB - tabcount = 4 total is 6*/
		                                             /*-1 cause j counted '\t' need to remove Then is 5*/
		                                             /*Larger than or equal COLUMN then execute*/
                if (blank != j) {
                    putchar('\n');
                    state = 1;                               /*Doesn't set tabcount
                                                               Cause tabcount need always count string s for self count*/
                    j = 0;
                    blank = 0;
                }
        if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n')     /*If s[i] is non blank character*/
            state = 0;                                       /*Set state to 0*/
        if (state == 0)
            if (s[i] == '\t' && state != -1) {
                                                             /*state != -1 cause beginning input and output tab length is equal
                                                               Maybe don't need exchange*/
		                               /*Used for if input like
						                        AAAA A	A
									AAAA' 'A'\t'A*/
		                               /*When output is
			                                                AAAA
								        A	A*/
		                               /*Later will ' ' instead of '\t' Makes look like
						                        AAAA
						                        A  A*/
                state = TAB - tabcount;        /*Borrow state later will return*/
		                               /*Calculate ' ' number for instead '\t'*/
		                               /*If tabcount is 5 state = 8 - 5 is 3 ' '*/
		                               /*If tabcount = 7 TAB - tabcount = 1
		                                 If tabcount = 8 TAB - tabcount = 0
		                                 If enter '\t' Need TAB - tabcount = 8
		                                 So set tabcount = 0*/
                while (state) {               /*If state != 0*/
                    putchar(' ');
                    --state;                  /*Every time decrease 1 Unstil 0*/
                }
                state = 0;                    /*return number to state*/
            }
            else
                putchar(s[i]);                /*putchar*/ /*if need exchange if not else putchar*/
        if (s[i] == '\t')                     /*If s[i] is tab reset tabcount position*/
		                              /*If too early set to 0 When calculate TAB - tabcount alway is 8
		                                                                             When s[i] == '\t'*/
            tabcount = 0;                     /*Set tabcount position to 0 Next character apear will be 1*/
        }
    }
}

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

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

Solution by Chris Chadwick

As I read it, this exercise simply asks us to write a program that takes input and intelligently word wraps it to the output. As such, this is my effort at a solution.

/* 
	KnR exercise 1-22 solution, by Chris Chadwick - big10p1967@gmail.com
		
	NOTE: This is a 'debug' version that outputs spaces and tabs as visible characters, so that
	it can be seen that the program is functioning correctly. Spaces are displayed as underscores "_"
	and tabs as a sequence of periods "." - also, a bar (of hashes "#") is displayed to show the
	width all output will be wrapped to.
*/

#include <stdio.h>

#define TAB_SIZE	8
#define OUTPUT_WIDTH	(TAB_SIZE * 3)
#define TRUE		1
#define FALSE		0

int outcol = 1; /* Column position of where the next char will be output. Range = 1 to OUTPUT_WIDTH */

void wrapchar(char c);
void wrapword(char word[], int len);

int main ()
{
	int c, i;
	char word[OUTPUT_WIDTH];	/* Buffers word currently being read from input */
	int wordi = 0;			/* Index of word[] to store next non-blank character of input */
	int showcols = TRUE;		/* Flag to indicate if output wrap width bar needs displaying */
	int overflow = FALSE;		/* Flag to indicate overflow state of word buffer (word[]) */
	extern int outcol;

	while ((c = getchar()) != EOF)
	{
		if (showcols)
		{
			/* Print bar showing width of output to wrap to */
			for (i = OUTPUT_WIDTH; i; --i)
				putchar('#');
			putchar('\n');
			showcols = FALSE;
		}

		if (c == ' ')
		{
			if (wordi)
			{
				/* A word is currently being read into the buffer. This space signals the end of that word */
				wrapword(word, wordi);
				wordi = 0;
			}

			wrapchar('_'); /* Dummy space, to make it visible */
			overflow = FALSE;
		}
		else if (c == '\t')
		{
			if (wordi)
			{
				/* A word is currently being read into the buffer. This tab signals the end of that word */
				wrapword(word, wordi);
				wordi = 0;
			}

			/* Calculate spaces to next tab-stop */
			int spaces = TAB_SIZE - (outcol % TAB_SIZE) + 1;
	
			if ((outcol += spaces) > OUTPUT_WIDTH)
			{
				/* This tab has taken us past line end, so wrap */
				putchar('\n');
				outcol = TAB_SIZE + 1; /* Tab to next stop on the new line */
				spaces = TAB_SIZE;
			}
			
			/* Output a dummy tab, to make it visible */
			for (i = 1; i <= spaces; ++i)
				putchar('.');

			overflow = FALSE;
		}
		else if (c == '\n')
		{
			if (wordi)
				/* A word is currently being read into the buffer. This newline signals the end of that word */
				wrapword(word, wordi);

			putchar(c);

			outcol = 1;
			wordi = 0;
			showcols = TRUE;
			overflow = FALSE;
		}
		else
		{
			/* c is a non-blank char, so considered part of a word */
			
			if (wordi == OUTPUT_WIDTH)
			{
				/* This 'word' has overflowed the word buffer, so is longer than an entire output line! */
				/* We will simply flush the word buffer, breaking it up to wrap to the output */
				for (i = 0; i < OUTPUT_WIDTH; ++i)
					wrapchar(word[i]);

				wrapchar(c);
				wordi = 0;
				overflow = TRUE; /* Signal that the word buffer is currently overflowing */
			}
			else
			{
				if (overflow)
				{
					/* Currently in word buffer overflow state, so simply output current char */
					wrapchar(c);
				}
				else
				{
					/* Continue buffering word being read from input */
					word[wordi++] = c;
				}
			}
		}
	}

	return 0;
}

/* Outputs the given char, wrapping as required */
void wrapchar(char c)
{
	extern int outcol;
	
	if (outcol > OUTPUT_WIDTH)
	{
		/* Wrap to new line */
		putchar('\n');
		outcol = 1;
	}
	
	putchar(c);
	++outcol;
}

/* Outputs the given word, wrapping as required */
void wrapword(char word[], int len)
{
	extern int outcol;

	if ((outcol + (len - 1)) > OUTPUT_WIDTH)
	{
		/* Word won't fit on current line, so wrap it to next line */
		putchar('\n');
		outcol = 1;
	}
	
	for (int i = 0; i < len; ++i)
	{
		putchar(word[i]);
		++outcol;
	}
}

Solution by Cromagnon

Unix-like systems have a command called fold that does what this exercise ask to do. So, I write my solution to be operationally equivalent to UNIX fold. So if you do ./cromagnon < file > out1 (where cromagnon is the executable of my code), then do fold -s -w 80 < file > out2, and compare the output of both commands with diff out1 out2. You will see that both outputs are equal for whatever input (if you find some input that do not generate equal output, please mail me in my talk page). I am using GNU fold (from GNU Coreutils) to test it.

#include <stdio.h>

#define TEXTWIDTH 80
#define TABSTOP   8
#define NOBLANK   1  /* 1 to fold line even if there are no blanks before TEXTWIDTH, 0 otherwise */

unsigned int getfold(char s[], unsigned int shift);
unsigned int putfold(char s[], unsigned int foldstop);

/* fold lines after the last non-blank character before the n-th column */
int main(void)
{
  char s [TEXTWIDTH+2];
  unsigned int i, foldstop, shift;

  shift = 0;
  while ((foldstop = getfold(s, shift)) > 0)
    shift = putfold(s, foldstop);
  putfold(s, TEXTWIDTH + 1);
  return 0;
}

/* print string while folding it at foldstop, return the length after the fold*/
unsigned int putfold(char s[], unsigned int foldstop)
{
  unsigned int i, count;

  count = 0;
  if (foldstop < TEXTWIDTH + 1) {
    for (i = 0; s[i] != '\0'; ++i) {
      if (i == foldstop) {
        putchar('\n');
        ++count;
      }
      else if (i > foldstop)
        ++count;
      putchar(s[i]);
    }
    if (i > 0 && s[i-1] == '\n')
      count = 0;
  }
  else {
    for (i = 0; s[i] != '\0'; ++i)
      putchar(s[i]);
    if (i > 0 && s[i-1] == '\n')
      count = 0;
    else
      count = TEXTWIDTH;
  }
  return count;
}

/* get string of the size of a fold, return where (and whether) it must be folden */
unsigned int getfold(char s[], unsigned int shift)
{
  int ch;
  unsigned int i, foldstop, col;

  foldstop = TEXTWIDTH + 1;
  col = (shift < TEXTWIDTH) ? shift : 0;
  for (i = 0; (ch = getchar()) != EOF && ch != '\n' && col < TEXTWIDTH; ++i) {
    s[i] = ch;
    if (ch == '\t')
      col = col + TABSTOP - (col % TABSTOP);
    else
      ++col;
    if (i > 0 && (ch == ' ' || ch == '\t') && col <= TEXTWIDTH) {
      foldstop = i+1;
      if (shift == TEXTWIDTH)
        col = TEXTWIDTH;
    }
  }
  if (ch == EOF) {
    s[i]  = '\0';
    foldstop = 0;
  }
  else {
    s[i]   = ch;
    s[i+1] = '\0';
    if (ch != '\n' && NOBLANK && foldstop == TEXTWIDTH+1)  /* no folding is possible but NOBLANK is set */
      foldstop = i;
    else if (ch == '\n' && col <= TEXTWIDTH)               /* string ends in newline and it's before textwidth */
      foldstop = TEXTWIDTH + 1;
  }
  return foldstop;
}

Solution by Francisco Da Silva Filho

email: franfellipe2@hotmail.com

Utilizei uma variável temporária para armazenar a linha encurtada a ser exibida, e realoco o restante dos caracteres(em tmp) apos o ultimo espaço em branco da linha

#include <stdio.h>
#define MAXLINE 30
#define MAXTEXT 1000
#define TABVAL 8
#define CURTAB(c) ( TABVAL - (c % TABVAL))

/*Escreva um programa para `` dobrar '' linhas de entrada longas em duas ou mais linhas mais curtas após
o último caractere não branco que ocorre antes da n-ésima coluna de entrada. Verifique se o seu
programa faz algo inteligente com linhas muito longas e, se não houver espaços em branco ou guias
antes da coluna especificada.*/
void main(void){

    int c;
    char text[MAXTEXT+1];
    for(int i = 0; (c = getchar()) != EOF; i++){
        text[i] = c;
        if(c == '\n'){
           text[i+1] = '\0';
           i = -1;
           quebraLinha(text, MAXLINE);
        }
    }
}

void quebraLinha(char s[], int len){

    int i, j, k, col, lencol, lblank;
    char tmp[len+1];

    col = lencol = lblank = 0;

    for(i = 0; s[i] != '\0'; i++){
        tmp[col++] = s[i];
        lencol += (s[i] == '\t') ? CURTAB(lencol) : 1;

        if(s[i] == ' ' || s[i] == '\t')
            lblank = col - 1;

        if(lencol >= len){
            if(lblank > 0){ // imprimir até a ultima posição em branco
                for(j = 0; j <= lblank; j++)
                    printf("%c", tmp[j]);
                for(k = 0; j < col; k++, j++) // realocar o restante dos carateres na variavel temporaria
                    tmp[k] = tmp[j];
                col = lencol = k; // Seta a contagem do indice e o tamanho da linha
            }else{
                tmp[col] = '\0';
                printf("%s", tmp);
                col = lencol = 0; // Zera a a contagem do indice e o tamanho da linha
            }
            printf("\n");
        }else if(s[i] == '\n'){
            tmp[col] = '\0';
            printf("%s", tmp);
            col = lencol = 0;
        }
    }
}
 

Solution by Marvelcoder

* fold.c
*
*  Created on: 11-Aug-2020
*  Author: Marvelcoder
*
*


#include<stdio.h>

#define MAXLINE 1000
#define NTHCOL 10

int main(){

    char line[MAXLINE],ch;
    int taborblankindex,i,nthcolumnindex;

    taborblankindex=i=nthcolumnindex=0;


    while((ch=getchar())!=EOF){
        line[i]=ch;
        i++;
    }


    for(int j=0;j<=i;j++){
        if(j%NTHCOL==0){
           nthcolumnindex = nthcolumnindex + NTHCOL;
            if(line[nthcolumnindex]!=' ' || line[nthcolumnindex]!='\t'){
                int k = nthcolumnindex;
                while(line[k]!=' ' && line[k]!='\t'){
                    --k;
                }
                line[k]='\n';
            }else{
                line[nthcolumnindex]='\n';
            }
        }
        printf("%c",line[j]);
    }



return 0;
}

Solution by Rckskio

* fold.c
*
*  Created on: 20-Jan-2021
*  Author: Rckskio
*
* Obs. I copied the format of answer from Marvelcoder, I hope thats ok, if not I can remove.


#include <stdio.h>

#define LINELENGTH	50	/* n-th column of input */

int main(void)
{
	int i, c;

	i = 0;
	while((c = getchar()) != EOF)
	{
		++i;
		putchar(c);
		if (i >= LINELENGTH && c == ' ')
		{
			putchar('\0');
			i = 0;
			putchar('\n');
		}
	}

	return 0;
}


Solution by anonymous

* this handles spaces, tabs, new-lines, different tab lengths, different fold lengths
* this also smartly wraps when content goes over fold length by backtracking to nearest space or tab
* printing that content, and going to the next line to continue printing.
* This makes use of a "buffer" to keep data in memory until it is ready to be printed.
* One thing that could be improved is all of the nested if statements. These could be reduced to improve readability
* From my tests, only Cromagnon's solution worked flawlessly for me. Chris Chadwick's solution seemed to work, but the output is hard to read on large tests so I am not sure.
#include <stdio.h>

/*
Exercise 1-22. 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.
*/

#define FOLD_LENGTH 80
#define SPACES_PER_TAB_STOP 8

// these comments are tests for the program to run
//									       y
//										z
//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccd

int main()
{
    int c, i, j, k, col;
    char lineBuffer[FOLD_LENGTH];

    i = j = col = 0;

    if (SPACES_PER_TAB_STOP > FOLD_LENGTH)
    {
        printf("Error: the spaces per tab stop must be less than or equal to the fold length\n");
        return 1;
    }
    
    // read stdin until EOF reached (ctrl + z or end of file)
    while ((c = getchar()) != EOF)
    {
        // first check is to see if the current position is less than the fold length
        if (col < FOLD_LENGTH)
        {
            // if newline, print line buffer, reset i, and reset col tracker. Then print newline
            if (c == '\n')
            {
                for (j = 0; j < i; ++j)
                    putchar(lineBuffer[j]);
                i = col = 0;
                putchar(c);
            }
            // if tab, can go beyond FOLD_LENGTH so need to do a check on that first
            else if (c == '\t')
            {
                // if the current col plus the spaces to the next tab stop is less than fold length
                // then add the tab and update the col to match the new position
                if (col + SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP) <= FOLD_LENGTH)
                {
                    col += SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP);
                    lineBuffer[i++] = c;
                }
                // if adding the tab will cause it to go beyond the width, backtrack and print everything before the tab, add a new line, then print the tab and update the col
                else
                {
                    // search for a space or approved tab to stop at. This prevents words from getting cut into pieces by the fold wrap.
                    for (j = i - 1; j >= 0; --j)
                        if (lineBuffer[j] == ' ' || lineBuffer[j] == '\t') // already added tab or space that fits within fold length
                            break; // saves the value of j where there is a tab or space
                    
                    // if the for loop finished without finding a tab or space, the value of j will be -1. So print everything and cut the content into pieces
                    if (j == -1)
                    {
                        for (j = 0; j < i; ++j)
                            putchar(lineBuffer[j]);

                        printf("\n%c", c);
                        i = 0; // reset since new line
                        col = SPACES_PER_TAB_STOP; // set to this value since added a tab
                    }
                    else // tab or space found, print up to that point, wrap, print and update column position
                    {
                        for (k = 0; k <= j; ++k)
                            putchar(lineBuffer[k]);

                        putchar('\n');
                        ++j; // since lineBuffer[j] was printed, move to next char
                        col = 0; // reset since new line

                        // on the new line, print the rest stored in the buffer
                        while (j < i)
                            if (lineBuffer[j] == '\t')
                            {
                                putchar(lineBuffer[j++]);
                                col += SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP);
                            }
                            else
                            {
                                putchar(lineBuffer[j++]);
                                ++col;
                            }
                        
                        i = 0; // update iterator to zero since new line and finished printing all of the data in the buffer
                    }
                }
            }
            else
            {
                lineBuffer[i++] = c;
                ++col;
            }
        }
        // if equal to fold length or greater than it, need to backtrack or truncate data
        else
        {
            // if the char that is trying to be printed is a newline and the current col is at max size, print buffer, the newline, and reset
            if (c == '\n' && col == FOLD_LENGTH)
            {

                for (j = 0; j < i; ++j)
                    putchar(lineBuffer[j]);

                i = col = 0;
                putchar(c);
            }
            // all other chars or newlines that would be printed after FOLD_LENGTH...
            else
            {
                if (c == '\t')
                {
                    // search for a space or approved tab to stop at. This prevents words from getting cut into pieces by the fold wrap.
                    for (j = i - 1; j >= 0; --j)
                        if (lineBuffer[j] == ' ' || lineBuffer[j] == '\t') // already added tab or space that fits within fold length
                            break; // saves the value of j where there is a tab or space
                    
                    // if the for loop finished without finding a tab or space, the value of j will be -1. So print everything and cut the content into pieces
                    if (j == -1)
                    {
                        for (j = 0; j < i; ++j)
                            putchar(lineBuffer[j]);

                        printf("\n%c", c);
                        i = 0; // reset since new line
                        col = SPACES_PER_TAB_STOP; // set to this value since added a tab
                    }
                    else // tab or space found, print up to that point, wrap, print and update column position
                    {

                        for (k = 0; k <= j; ++k)
                            putchar(lineBuffer[k]);

                        putchar('\n');
                        ++j; // since lineBuffer[j] was printed, move to next char
                        col = 0; // reset since new line

                        // on the new line, print the rest stored in the buffer
                        while (j < i)
                            if (lineBuffer[j] == '\t')
                            {
                                putchar(lineBuffer[j++]);
                                col += SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP);
                            }
                            else
                            {
                                putchar(lineBuffer[j++]);
                                ++col;
                            }

                        // finally, print the char that cause this whole mess
                        putchar(c);
                        if (c == '\n')
                            col = 0; // another new line, reset the col
                        else if (c == '\t')
                            col += SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP);
                        else
                            ++col;
                        
                        i = 0; // update iterator to zero since new line and finished printing all of the data in the buffer
                    }
                }
                // all other chars or newlines that would be printed after FOLD_LENGTH that is not a tab
                else
                {
                    // search for a space or approved tab to stop at. This prevents words from getting cut into pieces by the fold wrap.
                    for (j = i - 1; j >= 0; --j)
                        if (lineBuffer[j] == ' ' || lineBuffer[j] == '\t') // already added tab or space that fits within fold length
                            break; // saves the value of j where there is a tab or space
                    
                    // if the for loop finished without finding a tab or space, the value of j will be -1. So print everything and cut the content into pieces
                    if (j == -1)
                    {
                        for (j = 0; j < i; ++j)
                            putchar(lineBuffer[j]);

                        printf("\n%c", c);
                        i = 0; // reset since new line and everything in the buffer was printed
                        if (c == '\n')
                            col = 0; // another new line
                        else
                            col = 1; // printed a non-tab char on the new line, so update col
                    }
                    else // tab or space found, print up to that point, wrap, print and update column position
                    {
                        for (k = 0; k <= j; ++k)
                            putchar(lineBuffer[k]);

                        putchar('\n');
                        ++j; // since lineBuffer[j] was printed via the above for loop, move to next char
                        col = 0; // reset since new line
                        while (j < i)
                            if (lineBuffer[j] == '\t' )
                            {
                                // the tab was previously approved so just print it and update col
                                putchar(lineBuffer[j++]);
                                col += SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP);
                            }
                            else
                            {
                                putchar(lineBuffer[j++]);
                                ++col;
                            }
                        
                        // finally, print the char that cause this whole mess
                        putchar(c);
                        if (c == '\n')
                            col = 0; // another new line, reset the col
                        else if (c == '\t')
                            col += SPACES_PER_TAB_STOP - (col % SPACES_PER_TAB_STOP);
                        else
                            ++col;
                            
                        // update iterator to zero since new line and finished printing all of the data in the buffer
                        i = 0; 
                    }
                }
                
            }
        }
    }

    return 0;
}
Personal tools