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

Write a program entab that replaces strings of blanks with the minimum number of tabs and blanks to achieve the same spacing. Use the same stops as for detab . When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?

Category 0 Solution by Rick Dearman
Category 1 Solution by Stefan Farfeleder


Rick Dearman's Cat 0 solution:

/******************************************************
   KnR 1-21
   --------
   Write a program "entab" which replaces strings of 
   blanks with the minimum number of tabs and blanks 
   to achieve the same spacing.

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

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

#define MAXLINE 1000 /* max input line size */
#define TAB2SPACE 4 /* 4 spaces to a tab */

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

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


int
main()
{
  int i,t;
  int spacecount,len;

  while (( len = getline()) > 0 )
    {
      spacecount = 0;
      for( i=0; i < len; i++)
	{
	  if(line[i] == ' ')
	    spacecount++; /* increment counter for each space */
	  if(line[i] != ' ')
	    spacecount = 0; /* reset counter */
	  if(spacecount == TAB2SPACE) /* Now we have enough spaces
				      ** to replace them with a tab
				      */
	    {
	      /* Because we are removing 4 spaces and
	      ** replacing them with 1 tab we move back 
	      ** three chars and replace the ' ' with a \t
	      */
	      i -= 3; /* same as "i = i - 3" */
	      len -= 3;
	      line[i] = '\t';
	      /* Now move all the char's to the right into the
	      ** places we have removed.
	      */
	      for(t=i+1;t<len;t++)
		line[t]=line[t+3];
	      /* Now set the counter back to zero and move the 
	      ** end of line back 3 spaces
	      */
	      spacecount = 0;
	      line[len] = '\0'; 
	    }
	}
      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;

}




Stefan Farfeleder's Cat 1 solution:

/* 1-21.c */

#include <stdio.h>

#define TABSTOP 4

int main(void)
{
    size_t spaces = 0;
    int ch;
    size_t x = 0;               /* position in the line */
    size_t tabstop = TABSTOP;   /* get this from the command-line 
                                 * if you want to */

    while ((ch = getchar()) != EOF)
    {
        if (ch == ' ')
        {
            spaces++;
        }
        else if (spaces == 0) /* no space, just printing */
        {
            putchar(ch);
            x++;
        }
        else if (spaces == 1) /* just one space, never print a tab */
        {
            putchar(' ');
            putchar(ch);
            x += 2;
            spaces = 0;
        }
        else
        {
            while (x / tabstop != (x + spaces) / tabstop) 
                /* are the spaces reaching behind the next tabstop ? */
            {
                putchar('\t');
                x++;
                spaces--;
                while (x % tabstop != 0)
                {
                    x++;
                    spaces--;
                }
            }

            while (spaces > 0) /* the remaining ones are real space */
            {
                putchar(' ');
                x++;
                spaces--;
            }
            putchar(ch); /* now print the non-space char */
            x++;
        }
        if (ch == '\n')
        {
            x = 0; /* reset line position */
        }
    }

    return 0;
}







/*-------------------------------------------------*/
/* Another solution for review purpose */
#include <stdio.h>
#define MAXCHAR 1024
#define TABSPACE 8
int gline_entab(char[],int);
int CalcNextTabStop(int,int);
int main(void)
{
    int len,p;
    char s[MAXCHAR];
    p = 0;
    len = 0;
    while ((len = gline_entab(s,MAXCHAR))>0) {
        printf("%s",s);
        /* the following code is only meant for debugging purpose */
        while (s[p] != '\0') {
                  if (s[p] == '\t') {
                     putchar('\\');
                     putchar('t');
                  }
                  else if (s[p] == '\n') {
                       putchar('\\');
                       putchar('n');
                  }
                  else if (s[p] == ' ') 
                       putchar('-');
                  else
                      putchar(s[p]);
          
                  p++;
        }
        putchar('\n');
        p = 0;    
    }
   return 0;
}
int gline_entab(char s[], int lim) 
{
    int i,j,k,c;
    int fspace,cspace;
    i=j=k=fspace=cspace=0;
    while (i<lim-1 && ((c = getchar())!= EOF) && c != '\n') {
          printf("i = %d\n",i);      
          if (c == ' ') {
            if (fspace == 0) { //first occurence of ' '
               fspace = i;
               cspace=1;
               k= CalcNextTabStop(j,TABSPACE);
            }
            else  { //repeat occurence of ' '
                 if (j == k) {
                    s[fspace]='\t';
                    i = fspace;
                    fspace = 0;
                    cspace = 0;
                 }
                 else 
                      cspace++;
            }
          }
          else { 
               if (cspace>0)
                  i = fspace;
               while (cspace>0) {
                     s[i] = ' ';
                     i++;
                     cspace--;
               }   
               s[i] = c;
               fspace = 0;
          }
          i++;
          j++;
    }
    if (c == '\n') {
       s[i] = c;
       i++;
    }
    s[i] = '\0';
    return i;
}
int CalcNextTabStop(int p,int sz)
{
    return (((p/sz)+1)*sz)-1;
}




Well, another simpler solution similar to that one of exercise 20. Please, review it.

TheSunShadow


#include <stdio.h>

#define TAB 5 // Number of spaces of one tab.
      
main()
{
  int c, i = 0, j;
	
  while((c = getchar()) != EOF){
		
    if(c == ' '){
			
      ++i; // This is a counter of white spaces.
		
      if((i % TAB) == 0) // Every group of a number of 'TAB'
        putchar('\t');   // spaces is replaced by a tab.
    }
		
    else{
			
      for(j = 0; j < (i % TAB); ++j) 	// Every group smaller than
        putchar(' ');		        // 'TAB' spaces is untouched.
				
      putchar(c); // Well, there exist other characters but spaces.
			
      if(i != 0)	// Once some text is found, the counter is reset.
        i = 0;
    }	
  }
}


Solution by Amarendra Godbole, using the IN and OUT macros introduced earlier.

#include <stdio.h>

#define TABSTOP 4
#define IN  1
#define OUT 0

int
main(void)
{
    int spc, i, c, nspace;
    int state, ntab;

    state = OUT;
    nspace = 0;
    ntab = 0;
    spc = 0;
    while ((c = getchar()) != EOF) {
        if (c == ' ') {
            state = IN;
            nspace++;
        } else {
            if (state == IN) {
                if (nspace >= TABSTOP) {
                    ntab = nspace / TABSTOP;
                    spc = nspace % TABSTOP;
                    for (i = 0; i < ntab; i++)
                        putchar('\t');
                    for (i = 0; i < spc; i++)
                        putchar(' ');
                } else {
                    for (i = 0; i < nspace; i++)
                        putchar(' ');
                }
                nspace = 0;
                putchar(c);
                state = OUT;
            } else {
                putchar(c);
            }
        }
    }
    return 0;
}
Personal tools
Tidy_icons
not logged in