/*
 * Generic text formatting utilities
 * Implementation file
 * ---------------------------------------------------------------------------
 * $Id: txtutil.cc,v 1.2 2002/03/28 15:16:43 hsteoh Exp hsteoh $
 */

#include <ctype.h>
#include "txtutil.h"


/* FUNCTION DEFINITIONS */

char *text::make_line() {
  line = new char[width+1];		// create new line
  lines.append(line);			// add to existing text
  *line = '\0';				// (in case someone reads the line
					//  before anything is written to it)
  need_space=0;				// beginning of line: don't need space
  x=0;					// restart at column 0

  return line;
}

// Just wrap to width, disregarding word boundaries. This is a last resort to
// typeset words which are longer than the line width.
void text::dumb_wrap(char *word, int len) {
  if (x+need_space+1 <= width) {
    if (need_space) {
      *line++ = ' ';			// insert space after previous word
      x++;
    }
  } else {
    line = make_line();			// start filling in word at next line
  }

  while (len--) {			// simply copy word into line...
    *line++ = *word++;
    x++;				// until it doesn't fit any more
    if (len<1) need_space=1;		// end of word: need space before next
					// word (unless there's a linebreak)
    if (x>=width) {			// then fit it on next line
      *line='\0';
      line = make_line();
    }
  }
}

void text::add_word(char *start, int len) {
  if (!line)
    line = make_line();			// create new line

  if (x+len+need_space <= width) {	// does text fit into current line?
    if (need_space) {			// yes
      *line++ = ' ';			// insert interword space
      x++;				// (count the space as well!)
    }
    // (fall through to word insertion code)
  } else if (len<=width) {		// need to wrap word
    line = make_line();			// make a new line
    // (fall through to word insertion code)
  } else {				// word doesn't even fit on line!
    dumb_wrap(start, len);
    return;				// (abort)
  }

  // Append word to line
  x += len;				// new column position
  while (len--) {
    *line++ = *start++;
  }
  *line = '\0';				// terminate line (in case someone
					// accesses the line before next line
					// break is encountered)
  need_space=1;				// now need space before next word
}

void text::add_string(char *str) {
  char *word;

  while (*str) {
    str = eat_spaces(str);		// eat spaces at beginning of line

    // scan word (first word has slightly different processing)
    word=str;
    while (*str && !isspace(*str))
      str++;

    add_word(word, str-word);		// append word to text buffer
  } // endwhile(*str)
}

void text::add_lines(char *str) {
  char *word;

  if (!line)
    line = make_line();			// otherwise initial linebreaks won't
					// work properly.

  while (*str) {
    // Eat spaces at start of line, but respect newlines
    while (*str && isspace(*str) && *str!='\n') str++;

    if (*str == '\n') {
      linebreak();			// force a linebreak
      str++;				// eat linebreak
    } else {
      // scan word
      word = str;
      while (*str && !isspace(*str))
        str++;

      add_word(word, str-word);		// append word to buffer
    }
  } // endwhile(*str)
}

void text::linebreak() {
  line = make_line();
}

char *eat_spaces(char *s) {
  while (*s && isspace(*s)) s++;
  return s;
}

