The C Programming Language

Chapter 1 - A Tutorial Introduction 21

mmresult 2009. 3. 25. 17:29


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