"The C Programming Language", 2nd edition, Kernighan and Ritchie

Answer to Exercise 1-21, page 34

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

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?

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;
}



Back to index





You are visitor number - call again soon!