Andrew Bedno    Andrew@Bedno.com • 773-213-4578
 History   Kudos   Samples 

C
1995 - Ongoing  (29 Years 3 Months)
C

Text Stream Word Wrapper

Neatly word wraps a text stream with several options.
Also download my library of C utility routines.

/* wordwrap.c - Andrew Bedno - 1995.10.30

   Output formatting utility.
   Wraps input stream at a given line length, 
   optionally breaking on a specified delimiter character,
   optionally indenting first and/or subsequent lines.

Pseudocode:

Loop while not end of file:
  Read input line.
  Set wrapped line count to 0.
  Increment input line count.
  Strip trailing spaces.
  Loop while input line length > 0:
    If wrapped line count = 0:
      Set indent size to first indent.
    Else
      Set indent size to wrapped indent.
    Subtract indent size from wrap length giving wrap test point.
    Find last delimiter in input line before wrap test point.
    If no delimiter before wrap length:
      If input line length > wrap length:
        Set parse length to wrap length.
      Else
        Set parse length to input line length.
    Else
      Set parse length to position of delimiter.
    Copy parse length substring from input line to output line.
    Delete parse length characters from start of input line.
    Strip leading and trailing spaces from output line.
    Strip leading spaces from output line.
    Write indent size spaces.
    Write output line.
    Increment wrapped line count.
    Increment output line count.
*/

#include <stdio.h>

char progname[40];
int verbose = 0;
long linecnt_in = 0;
long linecnt_out = 0;

int wrap_len = 77;
char wrap_char = ' ';
int indent_first = 0;
int indent_rest = 0;

#define MAXBUF 8192

/*-----------------------------------------------------------------------*/
/* <help> display command line help if any command line arguments.       */
/*-----------------------------------------------------------------------*/

int help()
{
  fprintf( stderr, "%s: AIB version 1.0 revision 1995.10.30.\n", progname );
  fprintf( stderr, "This utility takes a text stream from stdin\n" );
  fprintf( stderr, "and outputs it with each input line neatly word\n" );
  fprintf( stderr, "wrapped to potentially multiple output lines.\n" );
  fprintf( stderr, "Usage: %s [-v] [len [delim [indent_1st [ind_rest]]]]\n", \
                   progname );
  fprintf( stderr, "-v     Verbose diagnostic info to stderr.\n" );
  fprintf( stderr, "len    Maximum output line length (default %d).\n", \
                   wrap_len );
  fprintf( stderr, "delim  Character to wrap on (default \"%c\").\n", \
                   wrap_char );
  fprintf( stderr, "indent_1st   Initial output line prepended spaces.\n" );
  fprintf( stderr, "indent_rest  Wrapped lines prepended spaces.\n" );
  fflush( stderr );
  exit( 1 );
  return( 0 );
}

/*-----------------------------------------------------------------------*/
/* <err_msg> displays important messages.                                */
/*-----------------------------------------------------------------------*/

int err_msg( msg )
char *msg;
{
  if ( linecnt_in > 0 )
    fprintf( stderr, "%s: Line %ld: %s.\n", progname, linecnt_in, msg );
  else
  {
    fprintf( stderr, "%s: %s.\n", progname, msg );
    fprintf( stderr, "Enter  %s -h  for help.\n", progname );
  }
  fflush( stderr );
  exit( 1 );
  return( 0 );
}
  
/* **********   PROCEDURES EXCERPTED FROM ANDREW'S LIBRARIES   ********* */

/*-----------------------------------------------------------------------*/
/* <read_line> reads and return a line from stdin.                       */
/*-----------------------------------------------------------------------*/

int read_line( s )
char *s;
{
  int done, in_c, s_len;

  *s = '\0';
  if ( feof( stdin ) ) return( 1 );
  done = 0;
  s_len = -1;
  while ( ! done )
  {
    in_c = getchar();
    if ( ( ! feof( stdin ) ) && ( in_c != 10 ) ) s[ ++s_len ] = in_c;
    done = ( feof( stdin ) || ( in_c == 10 ) || ( s_len == MAXBUF - 1 ) );
  }
  if ( ( s_len > -1 ) && ( s[ s_len ] == 13 ) ) s[ s_len ] = '\0';
  if ( s_len > -1 ) s[ ++s_len ] = '\0';
  return( 0 );
}

/*-----------------------------------------------------------------------*/
/* <DeLead> removes all leading occurrences of a selected character.     */
/* Also returns pointer to the string.                                   */
/*-----------------------------------------------------------------------*/

char *DeLead( InStr, Ch )
char *InStr;
int Ch;
{
  int StartPos = 0;

  if ( ( ! *InStr ) || ( *InStr != Ch ) ) return( InStr );
  while ( InStr[ StartPos ] == Ch ) StartPos++;
  memmove( InStr, &InStr[ StartPos ], strlen( InStr ) - StartPos + 1 );
  return( InStr );
}

/*-----------------------------------------------------------------------*/
/* <DeTrail> removes all trailing occurrences of a selected character.   */
/* Also returns pointer to the string.                                   */
/*-----------------------------------------------------------------------*/

char *DeTrail( InStr, Ch )
char *InStr;
int Ch;
{
  int EndPos, CurrLen;

  CurrLen = strlen( InStr );  EndPos = CurrLen - 1;
  if ( ( ! *InStr ) || ( InStr[ EndPos ] != Ch ) )
    return( InStr );
  while ( InStr[ EndPos ] == Ch ) EndPos--;
  InStr[ EndPos + 1 ] = '\0';
  return( InStr );
}

/*-----------------------------------------------------------------------*/
/* <Rep> returns a string of n repetitions of a selected character.      */
/*-----------------------------------------------------------------------*/

char *Rep( Ch, Wid )
char Ch;
int Wid;
{
  static char RepOut[256];

  if ( Wid < 0 ) Wid = 0;
  if ( Wid ) memset( RepOut, Ch, Wid );
  RepOut[ Wid ] = '\0';
  return( RepOut );
}

/*-----------------------------------------------------------------------*/
/* <Space> returns a string of a selected number of spaces.              */
/*-----------------------------------------------------------------------*/

char *Space( Wid )
int Wid;
{
  return( Rep( ' ', Wid ) );
}

/*-----------------------------------------------------------------------*/
/* <Delete> removes n characters starting at selected index in a string. */
/* Modeled after command available in Pascal.                            */
/*-----------------------------------------------------------------------*/

char *Delete( InStr, DelPos, DelSize )
char *InStr;
int DelPos, DelSize;
{
  int CurrLen;

  CurrLen = strlen( InStr );
  memmove( &InStr[ DelPos ], &InStr[ DelPos + DelSize ],
           CurrLen - DelSize + 1 );
  return( InStr );
}

/*-----------------------------------------------------------------------*/
/* <Copy> Copies a portion of source string to target string.            */
/* Also returns pointer to the target string.                            */
/*-----------------------------------------------------------------------*/

char *Copy( SrcStr, StrStart, StrSize, TgtStr )
char *SrcStr;
int StrStart;
int StrSize;
char *TgtStr;
{
  int EndPos;

  *TgtStr = '\0';
  if ( ! *SrcStr ) return( TgtStr );
  if ( StrStart >= strlen( SrcStr ) ) return( TgtStr );
  EndPos = StrStart + StrSize - 1;
  if ( EndPos > strlen( SrcStr ) - 1 )
    EndPos = strlen( SrcStr ) - 1;
  memmove( &TgtStr[ 0 ], &SrcStr[ StrStart ], EndPos - StrStart + 1 );
  TgtStr[ EndPos + 1 ] = '\0';
  return( TgtStr );
}

/* ****************   PROCEDURES CUSTOM FOR THIS PROGRAM  ************** */

/*-----------------------------------------------------------------------*/
/* <ProcessLine> main procedures outputs word wrapped input line.        */
/*-----------------------------------------------------------------------*/

int ProcessLine( line_in )
char *line_in;
{
  char line_out[MAXBUF];
  int wrapped_lines = 0;
  char indent_buf[MAXBUF];
  int indent_curr = 0;
  int delim_pos = 0;
  int delim_found = 0;
  int wrap_test = 0;
  int wrap_loop = 0;

  *line_out = '\0';
  wrapped_lines = 0;
  DeTrail( line_in, ' ' );
  if (strlen(line_in) == 0)
  {
    fprintf( stdout, "\n" );
    fflush( stdout );
  }
  while (strlen(line_in) > 0)
  {
    if (wrapped_lines > 0)
      indent_curr = indent_first;
    else
      indent_curr = indent_rest;
    strcpy(indent_buf, Space(indent_curr));
    wrap_test = wrap_len - indent_curr;
    if ( wrap_test > strlen(line_in) )
      delim_pos = strlen(line_in) - 1;
    else
    {
      delim_pos = wrap_test - 1;
      wrap_loop = wrap_test;
      delim_found = 0;
      while ((wrap_loop >= 1) && (! delim_found))
      {
        if (line_in[ wrap_loop - 1 ] == wrap_char)
        {
          delim_pos = wrap_loop - 1;
          delim_found = 1;
        }
        else
          wrap_loop--;
      }
    }
    Copy( line_in, 0, delim_pos + 1, line_out );
    Delete( line_in, 0, delim_pos + 1 );
    DeLead( line_out, ' ' );
    DeTrail( line_out, ' ' );
    DeLead( line_in, ' ' );
    fprintf( stdout, "%s%s\n", indent_buf, line_out );
    fflush( stdout );
    linecnt_out++;
    wrapped_lines++;
  }
}

/*-----------------------------------------------------------------------*/
/* <main>                                                                */
/*-----------------------------------------------------------------------*/

int main(argc,argv)
int argc;
char *argv[];
{
  int result = 0;
  int argofs = 0;
  char tempstr[255];
  char line_in[MAXBUF];
  strcpy( progname, argv[ 0 ] );

  if ( argc > 1 )
  {
    while ( result == 0 )
    {
      result = 1;
      if ( ( strcmp( argv[ argofs + 1 ], "-v" ) == 0 ) || \
           ( strcmp( argv[ argofs + 1 ], "-V" ) == 0 ) )
      {
        verbose = 1;
        result = 0;
        argofs++;
      }
      if ( ( strcmp( argv[ argofs + 1 ], "-h" ) == 0 ) || \
           ( strcmp( argv[ argofs + 1 ], "-H" ) == 0 ) )
        help();
    }
  }
  if ( argc > argofs + 5 ) help();
  if ( argc > argofs + 1 )
  {
    result = sscanf( argv[ argofs + 1 ], "%d", &wrap_len );
    if ( ! result )
      err_msg( "Invalid output line length argument" );
    if ( ( wrap_len < 2 ) || ( wrap_len > MAXBUF ) )
      err_msg( "Output line length argument out of range" );
    if ( argc > argofs + 2 )
    {
      strcpy( tempstr, argv[ argofs + 2 ] );
      if (strlen(tempstr) != 1)
        err_msg( "Delimiter must be one character long" );
      wrap_char = tempstr[0];
      if ( argc > argofs + 3 )
      {
        result = sscanf( argv[ argofs + 3 ], "%d", &indent_first );
        if ( ! result )
          err_msg( "Invalid initial indent argument" );
        if ( ( indent_first < 0 ) || ( indent_first > wrap_len - 2 ) )
          err_msg( "Initial indent argument out of range" );
        if ( argc > argofs + 4 )
        {
          result = sscanf( argv[ argofs + 4 ], "%d", &indent_rest );
          if ( ! result )
            err_msg( "Invalid wrapped indent argument" );
          if ( ( indent_rest < 0 ) || ( indent_rest > wrap_len - 2 ) )
            err_msg( "Wrapped indent argument out of range" );
        }
      }
    }
  }
  if ( verbose )
  {
    fprintf( stderr, "Maximum output line length: %d\n",
                     wrap_len );
    fprintf( stderr, "Character on which to wrap: \"%c\"\n",
                     wrap_char );
    fprintf( stderr, "Initial output line indentation: %d\n",
                     indent_first );
    fprintf( stderr, "Wrapped output lines indentation: %d\n",
                     indent_rest );
    fflush(stderr);
  }
  while ( ! feof( stdin ) )
  {
    read_line( line_in );
    if ( ! feof( stdin ) )
    {
      linecnt_in++;
      ProcessLine( line_in );
    }
  }
  if ( verbose )
  {
    fprintf( stderr, "Input lines:  %ld\n", linecnt_in );
    fprintf( stderr, "Output lines: %ld\n", linecnt_out );
    fflush( stderr );
  }
  exit( 0 );
  return( 0 );
}


 DOWNLOAD         < NEWER    OLDER >