Article 2759 of comp.sources.unix:
Submitted-By: mik@cs.su.oz.au (Michael Koelling)
Posting-Number: Volume 29, Issue 99
Archive-Name: red-96/part04

#!/bin/sh
# This is `part04' (part 4 of a multipart archive).
# Do not concatenate these parts, unpack them in order with `/bin/sh'.
# File `Red/Red/buffer.cc' is being continued...
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if test ! -r _sharseq.tmp; then
  echo 'Please unpack part 1 first!'
  exit 1
fi
shar_sequence=`cat _sharseq.tmp`
if test "$shar_sequence" != 4; then
  echo "Please unpack part $shar_sequence next!"
  exit 1
fi
if test ! -f _sharnew.tmp; then
  echo 'x - still skipping Red/Red/buffer.cc'
else
  echo 'x - continuing file Red/Red/buffer.cc'
  sed 's/^X//' << 'SHAR_EOF' >> 'Red/Red/buffer.cc' &&
X{
X  int ind = 0;
X  int col;		// screen column of cursor
X
X  col = index_to_screencol (pt.line, pt.column);	// find point screen col
X
X  while ((ind < pt.line->length) && 			// find non-blank char
X	 ((pt.line->text[ind] == ' ') || (pt.line->text[ind] == TAB)))
X    ind++;
X  if (ind == pt.line->length)
X    return;
X
X  pt.line->insert (' ', ind++);
X  (void) spaces_to_tab (ind);
X  pt.column = screencol_to_index (pt.line, col+1);	// find next column
X}
X
X//----------------------------------------------------------------------------
X// dec_indent: 
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::dec_indent () 
X{
X  int ind = 0;
X  int col;		// screen column of cursor
X
X  col = index_to_screencol (pt.line, pt.column);	// find point screen col
X
X  while ((ind < pt.line->length) &&  			// find non-blank char
X	 ((pt.line->text[ind] == ' ') || (pt.line->text[ind] == TAB)))
X    ind++;
X  if (ind == 0)						// already at left edge
X    return;
X  pt.column = ind;
X  untabify ();						// untab if necessary
X
X  pt.line->remove (--ind);
X  pt.column = screencol_to_index (pt.line, col-1);	// find index of column
X}
X
X//----------------------------------------------------------------------------
X// untabify: If the character before point is a TAB, turn it into spaces.  If
X//	not, just return.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::untabify () 
X{
X  int col, prev_col;
X
X  if (pt.column == 0)
X    return;
X  if (pt.line->text[pt.column-1] != TAB)
X    return;
X  else {
X    col = index_to_screencol (pt.line, pt.column);	// screen col after tab
X    pt.column--;
X    prev_col = index_to_screencol (pt.line, pt.column);	// screen col before tab
X    pt.line->remove (pt.column);			// delete tab
X    pt.line->insert_string ("        ", col-prev_col, pt.column);  // put spaces
X    pt.column = pt.column+col-prev_col;
X  }
X}
X
X//----------------------------------------------------------------------------
X// point_forward: Move the point one character forward.  If the end of a line 
X//	is reached, move to beginning of next line.  
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::point_forward ()
X{
X  return forward (pt);
X}
X
X//----------------------------------------------------------------------------
X// point_backward: Move the point one character backward.  If the beginning of
X//	a line is reached, move to end of next line.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::point_backward ()
X{
X  return backward (pt);
X}
X
X//----------------------------------------------------------------------------
X// point_up: Move point one line up. 'col' is the screen column to aim at.
X//	We have to find out what logical column that is (because of tabs).
X//	Returns the screen column it was set to or -1 if it couldn't be moved
X//	up.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::point_up (int col)
X{
X  if (pt.line->prev == endmark)
X    return False;
X
X  point_to_prev_line ();
X  point_to_screencol (col);
X  return True;
X}
X
X//----------------------------------------------------------------------------
X// point_down: Move point one line down. 'col' is the screen column to aim at.
X//	We have to find out what logical column that is (because of tabs).
X//	Returns true if it worked, False if it was in last line already.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::point_down (int col)
X{
X  if (pt.line->next == endmark)
X    return False;
X
X  point_to_next_line ();
X  point_to_screencol (col);
X  return True;
X}
X
X//----------------------------------------------------------------------------
X// point_to: Set point to the specified location.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to (BUFFERPOS pos)
X{
X  pt = pos;
X};
X
X//----------------------------------------------------------------------------
X// goto_pos: Set point to line number 'line', column 'col'.  If line number is
X//	greater than number of lines in buffer, set to last line. If it is
X//	less than one, go to first line.  Same with 'col'.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::goto_pos (int line, int col)
X{
X  point_to_bob ();
X  while (--line > 0) {				// set line
X    if (pt.line->next == endmark) break;
X    point_to_next_line ();
X  }
X
X  if (col>0)					// set column
X    if (col > pt.line->length)
X      pt.column = pt.line->length;
X    else
X      pt.column = col;
X}
X
X//----------------------------------------------------------------------------
X// point_to_bob: Set point to beginning of buffer.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to_bob ()
X{
X  pt.set (endmark->next,1,0);
X}
X
X//----------------------------------------------------------------------------
X// point_to_eob: Set point to end of buffer.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to_eob ()
X{
X  pt.set (endmark->prev, lines, endmark->prev->length);
X}
X
X//----------------------------------------------------------------------------
X// point_to_bol: Set point to beginning of line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to_bol ()
X{
X  pt.column = 0;
X}
X
X//----------------------------------------------------------------------------
X// point_to_eol: Set point to end of line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to_eol ()
X{
X  pt.column = pt.line->length;
X}
X
X//----------------------------------------------------------------------------
X// point_forward_word: Set point one word forward.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_forward_word ()
X{
X  Boolean ok = True;
X
X  while (ok && (!is_word_char (current_char ())))
X    ok = forward (pt);
X
X  while (ok && (is_word_char (current_char ())))
X    ok = forward (pt);
X}
X
X//----------------------------------------------------------------------------
X// point_backward_word: Set point one word backward.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_backward_word ()
X{
X  Boolean ok;
X
X  ok = backward (pt);
X
X  while (ok && (!is_word_char (current_char ())))
X    ok = backward (pt);
X
X  while (ok && (is_word_char (current_char ())))
X    ok = backward (pt);
X
X  if (ok)
X    forward (pt);
X}
X
X//----------------------------------------------------------------------------
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::point_to_next_error ()
X{
X  LINE* line = pt.line->next;
X  int   line_no = pt.line_no + 1;
X
X  while ((line->tag != ErrorLineTag) && (line != pt.line)) {
X    line = line->next;
X    if (line == endmark)
X      line_no = 0;
X    else
X      line_no++;
X  }
X
X  if (line == pt.line)
X    return False;
X  else {
X    pt.line = line;
X    pt.line_no = line_no;
X    pt.column = 0;
X    return True;
X  }
X}
X
X//----------------------------------------------------------------------------
X// next_line: Set pos to beginning of next line. The next line MUST be a valid
X//	buffer line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::next_line (BUFFERPOS& pos)
X{
X  assert (pos.line != endmark);
X  pos.line = pos.line->next;
X  pos.line_no++;
X  pos.column = 0;
X}
X
X//----------------------------------------------------------------------------
X// prev_line: set line one line up. That line MUST be a valid buffer line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::prev_line (BUFFERPOS& pos)
X{
X  pos.line = pos.line->prev;
X  pos.line_no--;
X  pos.column = 0;
X  assert (pos.line != endmark);
X}
X
X//----------------------------------------------------------------------------
X//  find: find the pattern "pattern" in the buffer and set point to its end
X//	and pt2 to it's beginning.
X//	Return True. If the pattern is not found, return False and leave
X//	point unchanged.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::find (char* pattern, Boolean case_sens,
X		      Boolean whole_word, Boolean backwd, Boolean wrap)
X{
X  BUFFERPOS spos = pt;	// search position
X  BUFFERPOS chpos;	// check position -- currently checked letter
X  int i;
X  Boolean done = False;
X
X  int length = strlen (pattern);
X
X  if (backwd)			// step back
X    if (!backward (spos))
X      spos.set (endmark->prev, lines, endmark->prev->length);
X
X  do {
X      do {		// search the text for pattern
X	  i = 0;
X	  chpos = spos;
X	  while (char_equal(chpos, pattern[i], case_sens) && (i<length)
X		 && forward (chpos))
X	      i++;
X
X	  if (i<length) {	// not found
X	    if (backwd) {
X	      if (!backward (spos))
X	        if (wrap)
X		  spos.set (endmark->prev, lines, endmark->prev->length);
X		else
X		  done = True;
X	    }
X	    else {	// (forwd)
X	      if (!forward (spos))
X	        if (wrap)
X		  spos.set (endmark->next, 1, 0);
X		else
X		  done = True;
X	    }
X	    done = done || spos.equal(pt);
X	  }
X      } while ((i<length) && (!done));
X
X    // if searching for whole word, check that neighbouring characters are no
X    // word characters
X
X      if ((i==length) && (whole_word)) {	// looking for word?
X	backward (spos);
X	if (is_word_char(char_at(spos)) || is_word_char(char_at(chpos))) {
X	  done = False;
X	  if (!backwd) {
X	    forward (spos);
X	    forward (spos);
X	  }
X	}
X	else {			// word found!
X	  forward (spos);	// set back to position where found
X	  done = True;
X	}
X      }
X      else			// not looking for word
X	done = True;
X  } while (!done);		// repeat if looking for whole word only
X
X  if (i==length) {				// found
X    assert ((chpos.line_no>0) && (chpos.line_no<=lines));
X    assert ((spos.line_no>0) && (spos.line_no<=lines));
X    pt = chpos;
X    pt2 = spos;
X    return True;
X  }
X  else 
X    return False;
X}
X
X//----------------------------------------------------------------------------
X// is_end: True if line is after last line
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::is_end (LINE* line)
X{
X  return line == endmark;
X}
X
X//----------------------------------------------------------------------------
X// is_top: True if line is first line
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::is_top (LINE* line)
X{
X  return line->prev == endmark;
X}
X
X//----------------------------------------------------------------------------
X// is_last: True if line is last line
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::is_last (LINE* line)
X{
X  return line->next == endmark;
X}
X
X//----------------------------------------------------------------------------
X// get_point: Get point location.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::get_point (BUFFERPOS& pos)
X{
X  pos = pt;
X}
X
X//----------------------------------------------------------------------------
X// get_text_to_eol: Return in the parameters the text of the current line
X//	from point to the end of the line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::get_text_to_eol (char*& str, int& len)
X{
X  str = &(pt.line->text[pt.column]);
X  len = pt.line->length - pt.column;
X}
X
X//----------------------------------------------------------------------------
X// get_text_in_line: Return in 'str' and 'len' the text of 'line' from column
X//	'col' to the end of the line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::get_text_in_line (LINE *line, int col, char*& str, int& len)
X{
X  str = &(line->text[col]);
X  len = line->length - col;
X}
X
X//----------------------------------------------------------------------------
X//  selection_to_string: Copy the current selection to a normal C string (NULL
X//	terminated).  The selection does not have to be turned on, only pt2
X//	and pt have to be set properly.
X//	PRE:
X//	  pt2 <= pt
X//----------------------------------------------------------------------------
X
Xchar* BUFFER::selection_to_string ()
X{
X  char* str;
X  int len, pos;
X  LINE* ln;
X
X  if (pt2.line == pt.line) {			// selection in one line
X    len = pt.column-pt2.column;
X    str = new char[len+1];
X    bcopy (&(pt2.line->text[pt2.column]), str, len);
X  }
X  else {					// selection over several lines
X    len = pt2.line->length - pt2.column + 1;	// calculate total length
X    ln = pt2.line->next;
X    while (ln != pt.line) {
X      len += ln->length + 1;
X      ln = ln->next;
X    }
X    len += pt.column;
X    str = new char[len+1];
X
X    pos = pt2.line->length - pt2.column;		// copy first line
X    bcopy (&(pt2.line->text[pt2.column]), str, pos);
X    str[pos++] = NewLine;
X
X    ln = pt2.line->next;
X    while (ln != pt.line) {				// copy middle lines
X      bcopy (ln->text, &str[pos], ln->length);
X      pos += ln->length;
X      str[pos++] = NewLine;
X      ln = ln->next;
X    }
X    bcopy (pt.line->text, &str[pos], pt.column);	// copy last line
X  }
X
X  str[len] = '\0';
X  return str;
X}
X
X//----------------------------------------------------------------------------
X//  set_tag: Set a tag (the little flag that is displayed in the editor window
X//	to the left of the line) for the current line.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::set_tag (LineTag tag)
X{
X  pt.line->tag = tag;
X}
X
X//----------------------------------------------------------------------------
X//  get_tag: Return the tag for the current line.
X//----------------------------------------------------------------------------
X
XLineTag BUFFER::get_tag (LINE* line)
X{
X  return line->tag;
X}
X
X//----------------------------------------------------------------------------
X//  set_mark: Set the mark at the current point position.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::set_mark ()
X{
X  mark = pt;
X}
X
X//----------------------------------------------------------------------------
X//  swap_point_mark: Exchange point and mark.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::swap_point_mark ()
X{
X  BUFFERPOS tmp;
X
X  if (mark.is_invalid ())
X    return False;
X
X  tmp = mark;
X  mark = pt;
X  pt = tmp;
X  return True;
X}
X
X//----------------------------------------------------------------------------
X//  set_pt2: Set pt2 at the current point position.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::set_pt2 ()
X{
X  pt2 = pt;
X}
X
X//----------------------------------------------------------------------------
X//  set_pt2_to_mark: Set pt2 to mark.  If mark is undefined, return false.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::set_pt2_to_mark ()
X{
X  if (mark.is_invalid ())		// can't select if mark is not set
X     return False;
X
X  pt2 = mark;
X  return True;
X}
X
X//----------------------------------------------------------------------------
X//  select_point_point: Select the text between point and pt2.  
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::select_point_point ()
X{
X  LINE* ln;
X  BUFFERPOS tmp;
X
X  assert (!selection_on);
X
X  if (pt2.is_behind (pt)) {		// if point is first...
X    tmp = pt2;				//  ...swap
X    pt2 = pt;
X    pt = tmp;
X  }
X
X  if (pt2.line == pt.line)
X    pt2.line->select = ContainsSelection;	// line contain whole selection
X  else {
X    pt2.line->select = SelectionStart;	// selection starts here, ...
X    ln = pt2.line->next;
X    while (ln != pt.line) {
X      ln->select = InSelection;			// ... contains these lines,...
X      ln = ln->next;
X      assert (ln != endmark);
X    }
X    pt.line->select = SelectionEnd;		// ... and ends here.
X  }
X
X  selection_on = True;
X}
X
X//----------------------------------------------------------------------------
X//  unselect: If the selection is active at the moment, unselect it (that is:
X//	mark all the selected lines as unselected again).
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::unselect ()
X{
X  LINE* ln;
X
X  assert (selection_on);
X
X  ln = pt2.line;		// first line of selection
X  while (ln != pt.line) {
X    ln->select = NoSelection;
X    ln = ln->next;
X  }
X  ln->select = NoSelection;
X
X  selection_on = False;
X}
X
X//----------------------------------------------------------------------------
X// clear_buffer: Erase the whole buffer contents, leaving an empty buffer.
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::clear_buffer ()
X{
X  LINE* line;
X
X  pt.line = endmark->next->next;
X  while (pt.line != endmark) {
X    line = pt.line->next;
X    delete pt.line;
X    pt.line = line;
X  }
X  pt.line = endmark->next;
X  pt.line->next = endmark;
X  endmark->prev = pt.line;
X
X  pt.line->length = 0;
X  pt.line_no = 1;
X  pt.column = 0;
X  lines = 1;
X
X  selection_on = False;
X}
X
X//----------------------------------------------------------------------------
X//  load: Load the contents of the associated file (defined on creation of the
X//	buffer) into the buffer.  If buffer was not empty, discard old 
X//	contents.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::load (char *filename)
X{
X  char ch;
X  LINE* ln;
X
X  ifstream file (filename);	// open file "filename"
X
X  if (!file) return False;
X
X  clear_buffer ();
X
X  while (file.get(ch))
X    if (ch == NewLine) {
X
X      ln = new LINE (40, NULL, 0);
X
X      pt.line->next->prev = ln;	// link new line into list
X      ln->next = pt.line->next;
X      pt.line->next = ln;
X      ln->prev = pt.line;
X
X      pt.line = ln;
X      lines++;
X    }
X    else
X      pt.line->append_char (ch);
X
X  pt.set (endmark->next, 1, 0);		// set point to beginning of buffer
X
X  return True;
X}
X
X//----------------------------------------------------------------------------
X// save: Save buffer to the file 'filename'.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::save (char *filename, bool append_newline)
X{
X  int i;
X  LINE* ln;
X  bool newline_at_end = false;
X
X  ofstream file (filename);	// open file "filename"
X
X  if (!file) return False;
X
X  ln = endmark->next;
X  while (ln != endmark) {
X    if (ln->length > 0) {
X      for (i=0; i<ln->length; i++)
X        file.put (ln->text[i]);
X      newline_at_end = false;
X    }
X    ln = ln->next;
X    if (ln != endmark) {
X      file.put (NewLine);
X      newline_at_end = true;
X    }
X  }
X  if (append_newline && (!newline_at_end))
X    file.put (NewLine);
X
X  return True;
X}
X
X//============================================================================
X//			      internal routines
X//============================================================================
X
X//----------------------------------------------------------------------------
X// current_char: Return character under point.
X//----------------------------------------------------------------------------
X
Xinline unsigned char BUFFER::current_char ()
X{
X  if (pt.column >= pt.line->length)
X    return NewLine;
X  else
X    return pt.line->text[pt.column];
X}
X
X//----------------------------------------------------------------------------
X// char_at: Return character at position p.
X//----------------------------------------------------------------------------
X
Xinline unsigned char BUFFER::char_at (BUFFERPOS p)
X{
X  if (p.column >= p.line->length)
X    return NewLine;
X  else
X    return p.line->text[p.column];
X}
X
X//----------------------------------------------------------------------------
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::internal_delete_line (LINE *ln)
X{
X  ln->prev->next = ln->next;		// unlink line from list
X  ln->next->prev = ln->prev;
X  lines--;
X
X  if (mark.line == ln)
X    mark.set (NULL, 0, 0);		// set to invalid
X
X  delete ln;
X}
X
X//----------------------------------------------------------------------------
X//  point_to_next_line: Set point to next buffer line. Attention: column is 
X//	NOT updated!
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to_next_line ()
X{
X  pt.line = pt.line->next;
X  pt.line_no++;
X}
X
X//----------------------------------------------------------------------------
X//  point_to_prev_line: Set point to next buffer line. Attention: column is 
X//	NOT updated!
X//----------------------------------------------------------------------------
X
Xvoid BUFFER::point_to_prev_line ()
X{
X  pt.line = pt.line->prev;
X  pt.line_no--;
X}
X
X//----------------------------------------------------------------------------
X//  point_to_screencol: Set point as close as possible to screencol and return
X//	the screen column actually used.
X//----------------------------------------------------------------------------
X
Xint BUFFER::point_to_screencol (int col)
X{
X  int screencol=0;
X
X  pt.column=0;
X  while ((screencol<col) && (current_char() != NewLine)) {
X    if (current_char() == TAB)
X      screencol = (screencol / TAB_length + 1) * TAB_length;
X    else
X      screencol++;
X    pt.column++;
X  }
X  return screencol;
X}
X
X//----------------------------------------------------------------------------
X//  forward: Move one position forward. Careful at end of buffer -- no check!
X//	Moves straight around from end to beginning of buffer.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::forward (BUFFERPOS& p)
X{
X  if (p.column < p.line->length) {		// no problems, step forward
X    p.column++;
X    return True;
X  }
X  else  if (p.line->next==endmark)		// at end of line
X    return False;
X  else {
X    p.line = p.line->next;
X    p.column = 0;
X    p.line_no++;
X    return True;
X  }
X}
X
X//----------------------------------------------------------------------------
X//  backward: Move one position backward. Careful at beginning of buffer -- no
X//	check! Wraps around.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::backward (BUFFERPOS& p)
X{
X  if (p.column > 0) {			// no problems, step backward
X    p.column--;
X    return True;
X  }
X  else if (p.line->prev==endmark)	// at end of line
X    return False;
X  else {
X    p.line = p.line->prev;
X    p.line_no--;
X    p.column = p.line->length;
X    return True;
X  }
X}
X
X//----------------------------------------------------------------------------
X// spaces_to_tab: If there are spaces in the current line before index that
X//	could be converted into a Tab, do so.  Return the number of spaces
X//	that were actually removed.
X//----------------------------------------------------------------------------
X
Xint BUFFER::spaces_to_tab (int index)
X{
X  int col;
X  int cnt = 0;
X
X  if (index == 0)
X    return 0;
X
X  col = index_to_screencol (pt.line, index);	// find screen col for index
X
X  if (col % TAB_length != 0)
X    return 0;
X  if (pt.line->text[index-1] != ' ')
X    return 0;
X
X  while ((index > 0) && (pt.line->text[index-1] == ' ') && (cnt < TAB_length)) {
X    pt.line->remove (--index);
X    cnt++;
X  }
X  pt.line->insert (TAB, index);
X  return cnt;
X}
X
X//----------------------------------------------------------------------------
X// index_to_screencol: Find the screen column for a given index in a line
X//----------------------------------------------------------------------------
X
Xint BUFFER::index_to_screencol (LINE* ln, int index)
X{
X  int i, col = 0;
X  
X  for (i=0; i<index; i++)
X    if (ln->text[i] == TAB)
X      col = (col / TAB_length + 1) * TAB_length;
X    else
X      col++;
X
X  return col;
X}
X
X//----------------------------------------------------------------------------
X// screencol_to_index: Find the index in a line that is on or after a given
X//	screen column.  If the line does not reach that column, return -1.
X//----------------------------------------------------------------------------
X
Xint BUFFER::screencol_to_index (LINE* ln, int column)
X{
X  int i = 0, col = 0;
X
X  while ((i < ln->length) && (col < column))
X      if (ln->text[i++] == TAB)
X	col = (col / TAB_length + 1) * TAB_length;
X      else
X	col++;
X
X  if (col > column)	// if there was a TAB, stay before TAB
X    i--;
X
X  if (col < column)
X    return -1;
X  else
X    return i;
X}
X
X//----------------------------------------------------------------------------
X//  is_word_char: Checks whether ch is a character legal in identifiers 
X//	(words).  These characters are letters, numbers and the underscore.
X//----------------------------------------------------------------------------
X
Xinline Boolean BUFFER::is_word_char (unsigned char ch)
X{
X  return ((ch<128) && (isalnum(ch) || (ch=='_')));
X}
X
X//----------------------------------------------------------------------------
X//  char_equal: Equality test for chars. If case_sens, it is the same as ==,
X//	if not case_sens, tests case insensitive.
X//----------------------------------------------------------------------------
X
XBoolean BUFFER::char_equal (BUFFERPOS p, unsigned char ch, Boolean case_sens)
X{
X  if (isalpha(ch) && (!case_sens))
X    return (tolower(char_at(p)) == tolower(ch));
X  else
X    return (char_at(p) == ch);
X}
SHAR_EOF
  echo 'File Red/Red/buffer.cc is complete' &&
  $shar_touch -am 0512222696 'Red/Red/buffer.cc' &&
  chmod 0640 'Red/Red/buffer.cc' ||
  echo 'restore of Red/Red/buffer.cc failed'
  shar_count="`wc -c < 'Red/Red/buffer.cc'`"
  test 33454 -eq "$shar_count" ||
    echo "Red/Red/buffer.cc: original size 33454, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/buffer.h ==============
if test -f 'Red/Red/buffer.h' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/buffer.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/buffer.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/buffer.h' &&
X#ifndef _BUFFER_H
X#define _BUFFER_H
X
X// ============================================================================
X//
X//  Class name: BUFFER
X//
X//  Author: M. Koelling							1995
X//
X//  Description:
X//
X//	BUFFER is part of the Blue Editor.  The buffer stores the text that
X//	is currently held in the editor.  It is organised as a sequence of 
X//	lines and two special positions: "point" and "mark".  "Point" 
X//	represents the "current position" (on screen represented by the cursor)
X//	and "mark" is a position that is remembered for later use (e.g. a 
X//	position can be marked and point can later jump to it).
X//	It can also represent a selection: If the seletion is on, "mark" 
X//	represents the beginning of the selection, "point" represents the end
X//	and all line within the selection are marked as selected.
X//	A variety of functions are provided to edit the contents of the buffer,
X//	retrieve its content and move point and mark.
X//
X// ============================================================================
X
X
X#include <Xm/Xm.h>
X
X#include "bufferpos.h"
X#include "line.h"
X
Xclass BUFFER {
X
X  friend BUFFERPOS;
X
X  public:
X    BUFFER ();			// Creation of empty buffer and assiciation of
X				// filename. The file gets not loaded yet.
X    ~BUFFER ();
X
X  // MODIFICATION FUNCTIONS:
X
X    void insert_char (char ch);
X    void insert_string (char* str, int len);
X    void insert_newline ();
X    char delete_char ();
X    void cut ();			// cut out selection (no saving)
X    Boolean indent ();			// indent as line above
X    int insert_half_tab ();		// insert spaces or tabs to next halftab
X    void inc_indent ();			// increment indentation of current line
X    void dec_indent ();			// decrement indentation of current line
X    void untabify ();			// turn TAB into spaces where necessary
X
X  // POINT MOVEMENT:
X
X    Boolean point_forward ();		// move point one character forward
X    Boolean point_backward ();		// move point one character backward
X    Boolean point_up (int col);		// move point one line up
X    Boolean point_down (int col);	// move point one line down
X    void point_to (BUFFERPOS pos);	// move point to specified position
X    void goto_pos (int line, int col);	// set point to line, column number
X    void point_to_bob ();		// set point to beginning of buffer
X    void point_to_eob ();		// set point to end of buffer
X    void point_to_bol ();		// set point to beginning of line
X    void point_to_eol ();		// set point to end of line
X    void point_forward_word ();		// move point one word forward
X    void point_backward_word ();	// move point one word backward
X    Boolean point_to_next_error ();	// set point to next error
X
X    void next_line (BUFFERPOS& pos);	// set pos one line down
X    void prev_line (BUFFERPOS& pos);	// set pos one line up
X
X    Boolean find (char* pattern,	// find a pattern (forward)
X	       Boolean case_sens,	//  if true, distinguish case
X	       Boolean whole_word,	//  if true, find whole word only
X	       Boolean backwd,		//  if true, search backwards
X	       Boolean wrap);		//  if true, wrap around at end of text
X
X  // ENQUIRY FUNCTIONS:
X
X    Boolean is_end (LINE* line);	// True if line is after last line
X    Boolean is_top (LINE* line);	// True if line is first line
X    Boolean is_last (LINE* line);	// True if line is last line
X
X    void get_point (BUFFERPOS& pos);	// get point position
X    void get_text_to_eol (char*& str,	// get text in pt.line from 
X			  int& len);	// point to eol
X    void get_text_in_line (LINE *line,	// get text in 'line' starting from col
X			  int col,
X			  char*& str,
X			  int& len);
X
X  // MISCELLANEOUS FUNCTIONS:
X
X    char* selection_to_string ();	// return the current selection
X					//  as a null terminated string
X
X    void set_tag (LineTag tag);		// set a tag in the current line
X    LineTag get_tag (LINE* line);	// get tag of line
X
X    void set_mark ();			// set a mark at point position
X    Boolean swap_point_mark ();		// exchange point and mark
X
X    void set_pt2 ();			// set a pt2 at point position
X    Boolean set_pt2_to_mark ();		// set pt2 to mark
X    void select_point_point ();		// select text between point and pt2
X    void unselect ();			// unselect text
X
X    void clear_buffer ();		// delete everything, make buffer empty
X    Boolean load (char *filename);
X    Boolean save (char *filename, 
X		bool append_newline);
X
X  // NOTE: all public variables should be treated as read only!!
X
X    BUFFERPOS pt;		// point position
X    BUFFERPOS pt2;		// used when selection is on: the other end
X				// Note: when sel is on, pt2 is always at the
X				// start, pt at the end of the selection
X    BUFFERPOS mark;		// mark position
X
X    Boolean selection_on;	// True if selection is currently on
X
X    int lines;			// total number of lines
X
X  private:
X
X    inline unsigned char current_char ();
X					// return the character at point
X    inline unsigned char char_at (BUFFERPOS p);	
X					// return the character position p
X
X    void internal_delete_line (LINE *ln);
X    void point_to_next_line ();
X    void point_to_prev_line ();
X    int point_to_screencol (int col);
X    Boolean forward (BUFFERPOS& p);
X    Boolean backward (BUFFERPOS& p);
X
X    int spaces_to_tab (int index);	// convert spaces into Tab
X
X    int index_to_screencol (LINE* ln, int index);
X    int screencol_to_index (LINE* ln, int column);
X
X    inline Boolean is_word_char (unsigned char ch);
X					// True if ch is in word characters
X    Boolean char_equal (BUFFERPOS p, unsigned char ch, Boolean case_sens);
X			 		// True if at position p is char ch
X    LINE* endmark;			// dummy line at end of buffer
X
X    const unsigned char NewLine;    // the Unix file newline character
X    const int TAB_length;
X    const unsigned char TAB;
X};
X
X#endif
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/buffer.h' &&
  chmod 0640 'Red/Red/buffer.h' ||
  echo 'restore of Red/Red/buffer.h failed'
  shar_count="`wc -c < 'Red/Red/buffer.h'`"
  test 5702 -eq "$shar_count" ||
    echo "Red/Red/buffer.h: original size 5702, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/bufferpos.cc ==============
if test -f 'Red/Red/bufferpos.cc' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/bufferpos.cc (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/bufferpos.cc (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/bufferpos.cc' &&
X// ============================================================================
X//  File: bufferpos.cc						-mik- 1995
X//
X//  Implementation of class BUFFERPOS.  See bufferpos.h for description.
X//  Bufferpos is part of the Blue programming environment and the Red editor.
X// ============================================================================
X
X#include "bufferpos.h"
X
X//----------------------------------------------------------------------------
X//  BUFFERPOS: Create a new buffer position at indicated location.
X//----------------------------------------------------------------------------
X
XBUFFERPOS::BUFFERPOS ()
X{
X  line = NULL;
X  line_no = -1;
X  column = -1;
X}
X
X//----------------------------------------------------------------------------
X//  set: Set position to specified position.
X//----------------------------------------------------------------------------
X
Xvoid BUFFERPOS::set (LINE* ln, int n, int col)
X{
X  line = ln;
X  line_no = n;
X  column = col;
X}
X
X//----------------------------------------------------------------------------
X//  is_valid: Return true, if the position marks a valid buffer position.
X//----------------------------------------------------------------------------
X
XBoolean BUFFERPOS::is_invalid ()
X{
X  return line == NULL;
X}
X
X//----------------------------------------------------------------------------
X//  is_before: Returns true, if this position is before position 'other' in
X//	the buffer.
X//----------------------------------------------------------------------------
X
XBoolean BUFFERPOS::is_before (BUFFERPOS other)
X{
X  return ((line_no < other.line_no) ||
X	   ((line_no == other.line_no) && (column < other.column)));
X}
X
X//----------------------------------------------------------------------------
X//  is_behind: Returns true, if this position is behind position 'other' in
X//	the buffer.
X//----------------------------------------------------------------------------
X
XBoolean BUFFERPOS::is_behind (BUFFERPOS other)
X{
X  return ((line_no > other.line_no) ||
X	   ((line_no == other.line_no) && (column > other.column)));
X}
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/bufferpos.cc' &&
  chmod 0640 'Red/Red/bufferpos.cc' ||
  echo 'restore of Red/Red/bufferpos.cc failed'
  shar_count="`wc -c < 'Red/Red/bufferpos.cc'`"
  test 2078 -eq "$shar_count" ||
    echo "Red/Red/bufferpos.cc: original size 2078, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/bufferpos.h ==============
if test -f 'Red/Red/bufferpos.h' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/bufferpos.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/bufferpos.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/bufferpos.h' &&
X#ifndef _BUFFERPOS_H
X#define _BUFFERPOS_H
X
X// ============================================================================
X//
X//  Class name: BUFFERPOS
X//
X//  Author: M. Koelling						1995
X//
X//  Description:
X//
X//	This class is used to store a position within the buffer in the editor.
X//	All instance variables are public and read and written directly. No
X//	implementation file exists for this class (since there are no 
X//	routines).
X//
X// ============================================================================
X
X#include <Xm/Xm.h>
X#include "line.h"
X
Xclass BUFFERPOS {
X
X  public:
X    BUFFERPOS ();				// create an invalid position
X
X    void set (LINE* ln, int n, int col);    // set position to specified pos
X
X    Boolean is_invalid ();		    // true if position has been set
X    Boolean is_before (BUFFERPOS other);    // true if this pos is before other
X    Boolean is_behind (BUFFERPOS other);    // true if this pos is behind other
X
X    Boolean equal (BUFFERPOS other)	    // equality test
X	{ return ((line==other.line)
X	    && (column==other.column)); };
X
X    Boolean at_eoln ()			    // true if pos is at end of line
X	{ return column==line->length; };
X
X    LINE* line;		// line of this position
X    int line_no;	// line number of this position
X    int column;		// and the column (starting at 0)
X};
X
X#endif
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/bufferpos.h' &&
  chmod 0640 'Red/Red/bufferpos.h' ||
  echo 'restore of Red/Red/bufferpos.h failed'
  shar_count="`wc -c < 'Red/Red/bufferpos.h'`"
  test 1320 -eq "$shar_count" ||
    echo "Red/Red/bufferpos.h: original size 1320, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/defines.h ==============
if test -f 'Red/Red/defines.h' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/defines.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/defines.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/defines.h' &&
X#ifndef _DEFINES_H
X#define _DEFINES_H
X
X
X#define RED_VERSION	"0.97b"
X
X#define PREF_NAME	"/.red-prefs"
X#define KB_FILE_NAME	"/.red-key-bindings"
X
X
X#endif
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/defines.h' &&
  chmod 0640 'Red/Red/defines.h' ||
  echo 'restore of Red/Red/defines.h failed'
  shar_count="`wc -c < 'Red/Red/defines.h'`"
  test 152 -eq "$shar_count" ||
    echo "Red/Red/defines.h: original size 152, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/editor.cc ==============
if test -f 'Red/Red/editor.cc' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/editor.cc (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/editor.cc (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/editor.cc' &&
X// ============================================================================
X//
X//  File: editor.cc						-mik- 1995
X//
X//  Implementation of class EDITOR.  See editor.h for description.
X//  Editor is part of the Blue programming environment.
X//
X// ============================================================================
X
X// for atoi:
X#include <stdlib.h>
X
X// for getwd:
X#include <unistd.h>
X
X#include <Xm/Form.h>
X#include <Xm/ScrollBar.h>
X#include <Xm/DrawingA.h>
X#include <Xm/ScrolledW.h>
X#include <Xm/Protocols.h>
X#include <Xm/AtomMgr.h>
X#include <X11/Shell.h>
X#include <X11/cursorfont.h>
X
X#include "editor.h"
X#include "red.h"
X#include "defines.h"
X#include "../Utility/utility.h"
X#include "../Utility/messages.h"
X#include "../Utility/stdfunc.h"
X#include "../Utility/debug.h"
X
X#define MAXPATH 255
X
X#ifdef RED_ONLY
X  #define  _CLASS_ "File"
X#else
X  #include "../Machine/controller.h"
X  #define  _CLASS_ "Class"
X#endif
X
X// callback functions necessary for editor widget callbacks
X
X#include "editor_callbacks.i"
X
X// =========================================================================
X// 				interface
X// =========================================================================
X
X// -------------------------------------------------------------------------
X//  EDITOR: Constructor. "show_toolbar" indicates whether tool bar is on.
X//	"compiled" indicates whether this class is compiled (and thus the 
X//	breakpoint buttons should be enabled).
X// -------------------------------------------------------------------------
X
XEDITOR::EDITOR (ApplicationData* resource)
X  : NewLine(10)
X{
X  rsrc = resource;
X
X  screen = NULL;
X  info = new INFO (rsrc->infofont);
X  buffer = NULL;
X  undo_stack = new ACTIONSTACK ();
X  buffer = NULL;
X
X  dragging = False;
X  last_func = NOT_BOUND;
X  search_found = True;
X  param_prompt = NULL;
X  strcpy (parameter, "");
X  button1_down = False;
X  double_click = False;
X
X  edit_window = NULL;
X
X  first_expose = True;
X  first_save = True;
X}
X
X// -------------------------------------------------------------------------
X//  ~EDITOR: Clean up.
X// -------------------------------------------------------------------------
X
XEDITOR::~EDITOR ()
X{
X  XtDestroyWidget (edit_window);
X  delete buffer;
X  delete info;
X  delete screen;
X}
X
X// -------------------------------------------------------------------------
X//  open: Load the file "fname" and show the editor window.  'cl' is the
X//	class whose source this is (if it is the integrated version).  For
X//	the stand-alone version, cl is always NULL.  If 'cl' is set, the
X//	source file MUST exist -- otherwise return False.
X// -------------------------------------------------------------------------
X
XBoolean EDITOR::open (Widget toplevel, ICLASS *cl, char *fname, 
X			LIST* breakpoints, Boolean show_toolbar, 
X			Boolean compiled, Boolean iconic)
X{
X  Boolean loaded, goodfile;
X  struct stat stbuf;
X  char* infoline1;
X
X  if (!edit_window) {
X    screen = new SCREEN (rsrc->editfont, !compiled);
X    init_window (toplevel, show_toolbar, compiled, iconic);
X  }
X
X  src_class = cl;
X  filemode = 0;
X  save_state = Saved;
X
X  delete buffer;			// just in case there was one already
X  buffer = new BUFFER ();		// new empty buffer
X
X  // check whether file exists and what kind of file it is
X
X  if (stat(fname, &stbuf) != 0) {	// does not exist
X    loaded = False;
X    goodfile = True;
X  }
X  else
X    if ((stbuf.st_mode & S_IFMT) == S_IFREG) {	// normal file
X      goodfile = True;
X      filemode = stbuf.st_mode;
X      loaded = buffer->load(fname);
X      if (breakpoints)
X        put_breakpoints (breakpoints);
X    }
X    else {				// bad file (e.g. directory)
X      goodfile = False;
X      fname = NULL;
X      loaded = False;
X    }
X
X  if (src_class && !loaded) {		// if it should exist but didn't...
X    delete buffer;			//  ...give up
X    buffer = NULL;
X    return False;
X  }
X
X  // fix the file name (make sure it is the complete path)
X
X  if (!fname || (fname[0] != '/')) {	// if name is not full path...
X    filename = new char[MAXPATH];	// ...prepend path
X    getcwd (filename, MAXPATH);
X    strcat (filename, "/");
X    if (fname)
X      strcat (filename, fname);
X  }
X  else
X    filename = fname;
X
X  // set up editor variables
X
X  set_title ();
X  top = bottom = buffer->pt;
X
X  // display window (realise it if it wasn't already)
X
X  blanklines = -1;
X  if (XtIsRealized(edit_window)) {
X    info->expose ();
X    display ();
X  }
X  else {
X    XtRealizeWidget (edit_window);	// will cause expose event and display
X    utility->set_cursor (edit_window, XC_left_ptr);
X
X    // initialise screen and info area
X
X    #ifdef RED_ONLY
X      screen->init (da,0);	// screen and info must be re-initialised every
X    #else				// time the window is realised.
X      screen->init (da,16);
X    #endif
X  }
X
X  if (rsrc->motd1[0] != '\0')
X    infoline1 = rsrc->motd1;
X  else
X    infoline1 = "Red Version "RED_VERSION;
X
X  if (loaded)
X    info->init (info_area, infoline1, rsrc->motd2);
X  else if (!goodfile) {
X    info->init (info_area, 
X	    "The file could not be opened because it is not a regular file.", 
X	    "(It might be a directory or a device.)");
X    XBell (XtDisplay (edit_window), 0);
X  }
X  else if (fname)
X    info->init (info_area, "New file", "");
X  else
X    info->init (info_area, infoline1, rsrc->motd2);
X
X  return True;
X}
X
X// -------------------------------------------------------------------------
X//  come_up: Try to bring this editor's window to the top, and, if it was
X//	iconified, de-iconify it.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::come_up ()
X{
X  XMapRaised (XtDisplay(edit_window), XtWindow(edit_window));
X}
X
X// -------------------------------------------------------------------------
X//  show_toolbar: Show or hide the toolbar (depending on the parameter 
X//	'show').
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::show_toolbar (Boolean show)
X{
X  if (show) {
X    XtManageChild (toolbar);
X    utility->attach_top (text_area, toolbar);
X  }
X  else {
X    XtUnmanageChild (toolbar);
X    utility->attach_top (text_area, menu_bar);
X  }
X}
X
X#ifndef RED_ONLY
X
X// -------------------------------------------------------------------------
X//  set_compiled: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::set_compiled (Boolean compiled)
X{
X  utility->set_sensitive (break_item, compiled);
X  utility->set_sensitive (clr_break_item, compiled);
X  utility->set_sensitive (watch_item, compiled);
X  screen->set_tag_grey (!compiled);
X}
X
X// -------------------------------------------------------------------------
X//  set_debug: 
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::set_debug (Boolean enable)
X{
X  utility->set_sensitive (examine_item, enable);
X  utility->set_sensitive (step_item, enable);
X  utility->set_sensitive (step_into_item, enable);
X  utility->set_sensitive (cont_item, enable);
X  utility->set_sensitive (term_item, enable);
X}
X
X// -------------------------------------------------------------------------
X//  display_message: Display a message in the info area and highlight part
X//	of the text (defined by 'region').  Used for displaying error
X//	messages.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::display_message (char* msg1, char* msg2, TEXTREGION region)
X{
X  if (region.start_line != -1) {
X    if (check_selection (False, False))	// if selection on, switch it off
X      ;
X    buffer->goto_pos (region.start_line, region.start_col);
X    show_point ();
X    buffer->set_pt2 ();
X    buffer->goto_pos (region.end_line, region.end_col);
X    toggle_selection ();
X  }
X
X  info->message (msg1, "", msg2);
X}
X
X// -------------------------------------------------------------------------
X//  insert_text: Insert some text into the buffer at the current cursor 
X//	position.  The text may not contain line breaks.  The selection
X//	must be off.  No redisplay is done (this is used as an internal
X//	function within user functions!).  This is not meant to be used for
X//	interactive editing (it does not store the action on the undo stack)
X//	For interactive insertion, use "insert" in "editor_edit.i".
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::insert_text (char* text)
X{
X  ACTION* action;
X  int startline, startcol;
X  char* s;	// current check position
X
X  s = str;
X  while (*s) {				// while not end of str
X      while ((*s) && (*s!='\n'))
X	s++;
X      buffer->insert_string (str, s-str);
X      if (*s) {
X	buffer->insert_newline ();
X	str = s+1;			// set to next line
X	s = str;
X      }
X  }
X
X  // store information about this on undo-stack
X
X  action = undo_stack->new_action ();		// get action record
X  action->set_insertion (startline, startcol, 
X			 buffer->pt.line_no, buffer->pt.column, false);
X  set_saved (False);
X}
X
X// -------------------------------------------------------------------------
X//  replace_region:  Replace a region of text in the buffer with a new text.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::replace_region (TEXTREGION region, char* text)
X{
X  BUFFERPOS save_pos;
X  Boolean out_of_screen;
X
X  if (check_selection (False, False))	// if selection on, switch it off
X    ;
X
X  buffer->get_point (save_pos);
X  buffer->goto_pos (region.start_line, region.start_col);
X  buffer->set_pt2 ();
X  buffer->goto_pos (region.end_line, region.end_col);
X  out_of_screen = (buffer->pt.is_before (top))
X		  || (buffer->pt2.is_behind(bottom));
X  delete_between_points ();
X  insert (text);
X  buffer->point_to (save_pos);
X  if (!out_of_screen)
X    redisplay ();
X}
X#endif
X
X// =========================================================================
X//			     user function execution
X//
X//  The following functions are triggered indirectly by user functions.
X//  This is typically the case when the user function popped up a dialog
X//  first and then the dialog can call one of these "do_" functions if it
X//  decides to really execute the function.
X// =========================================================================
X
X// -------------------------------------------------------------------------
X// save: Save the buffer to disk under current filename.  If it hasen't got
X//	a filename, call save_as instead.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::save ()
X{
X  char fname[MAXPATH];
X  Boolean made_backup = False;
X
X  if ((save_state == Saved) && (last_func != UFSave))
X    info->message ("No changes need to be saved", "", "");
X  else {
X    if (*basename(filename) != '\0') {		// if it has a file name...
X	if (first_save && red->backup_on()) {
X	  strncpy (fname, filename, MAXPATH-3);
X	  strcat (fname, ".~");
X	  rename (filename, fname);
X	  first_save = False;
X	  made_backup = True;
X	}
X	if (buffer->save (filename, red->append_nl_on())) {
X	  if (made_backup && (filemode!=0))		// set access rights as in original
X	    if (chmod (filename, filemode) != 0)
X	      info->warning ("Warning: There was a problem in installing the "
X			     "same access rights as in the original file.",
X			     "(The access rights might be different now.)");
X	  set_saved (True);
X	} 
X	else
X	  info->warning ("Error in saving " _CLASS_"!", "");
X    }
X    else
X      #ifdef RED_ONLY
X	red->save_as_request (this, dirname(filename));	// ask for save-as
X      #else
X	assert (False);
X      #endif
X  }
X}
X
X// -------------------------------------------------------------------------
X//  do_save: Save this buffer under a new file name. The new name is 
X//	passed as parameter.  (This is called by "save_as").
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::do_save (char* fname)
X{
X  struct stat stbuf;
X
X  assert (fname != NULL);
X
X  if (buffer->save (fname, red->append_nl_on())) {
X    if (filename)
X      XtFree (filename);		// discard old filename
X    filename = fname;
X    set_title ();
X    set_saved (True);
X    stat(filename, &stbuf);		// get the access rights of new file
X    filemode = stbuf.st_mode;
X  }
X  else
X    info->warning ("Could not save file!",
X	   "(The reason could be: invalid file name, file exists and is "
X	   "write protected, directory is write protected, ...)");
X}
X
X// -------------------------------------------------------------------------
X//  do_find: Internal find routine used by the find, find_next and
X//	find_selection functions (partly indirectly over finder).
X//	Perform the find and, if interactive is true, report an error if not
X//	found.
X// -------------------------------------------------------------------------
X
XBoolean EDITOR::do_find (char* pattern, SearchDir direction, 
X			Boolean case_sens, Boolean whole_word)
X{
X  char msg[100];
X
X  assert (pattern != NULL);
X
X  if (strlen(pattern)==0) {
X    info->message ("Empty search string", "", "");
X    return False;
X  }
X
X  if (direction==forwd)
X      if (search_found)
X        strcpy (msg, "Find forward: ");
X      else
X        strcpy (msg, "Find forward (wrap around): ");
X  else
X      if (search_found)
X        strcpy (msg, "Find backward: ");
X      else
X        strcpy (msg, "Find backward (wrap around): ");
X  strncat (msg, pattern, 70);
X  info->message (msg, "", "");
X
X  if (check_selection (False, (direction==forwd)))	// switch sel. off
X    ;
X  search_found = buffer->find (pattern, case_sens, whole_word,
X			       (direction==backwd), !search_found);
X  if (search_found) {
X    show_point ();
X    toggle_selection ();
X    return True;
X  }
X  else {
X    info->warning (msg, "Not found");
X    return False;
X  }
X}
X
X// -------------------------------------------------------------------------
X//  do_replace_all: 
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::do_replace_all (char* pattern, SearchDir direction, 
X			Boolean case_sens, Boolean whole_word, 
X			char* rep_pattern)
X{
X  BUFFERPOS start;
X  BUFFERPOS end;
X  int cnt = 0;
X
X  assert (pattern != NULL);
X  if (strlen(pattern)==0) {
X    info->message ("Empty search string", "", "");
X    return;
X  }
X
X  if (check_selection (False, (direction==backwd)))	// switch sel. off
X    ;
X  buffer->get_point (start);
X
X  while (buffer->find (pattern, case_sens, whole_word,
X			(direction==backwd), False)) {
X    delete_between_points ();
X    insert (rep_pattern);
X    cnt++;
X  }
X  if (buffer->pt.is_before (start)) {
X    buffer->point_to (start);
X    display ();
X  }
X  else {
X    buffer->point_to (start);
X    screen_update_from (start);
X  }
X  info->int_message (cnt, " instances replaced", "");
X}
X
X// -------------------------------------------------------------------------
X//  do_replace: Internal replace routine used by the replace (indirectly 
X//	over finder). Replaces the current selection with "pattern".
X//	If there is no current selection, just return False.
X// -------------------------------------------------------------------------
X
XBoolean EDITOR::do_replace (char* pattern)
X{
X  BUFFERPOS start;
X
X  if (!check_selection (True, True))		// if selection, cut it
X    return False;
X
X  buffer->get_point (start);
X  insert (pattern);
X  screen_update_from (start);
X  return True;
X}
X
X// -------------------------------------------------------------------------
X//  tell_selection: The editor (currently holding the X selection) is asked
X//	for the text of the selection (someone else wants to paste it).
X//	Return the text of the current selection.
X// -------------------------------------------------------------------------
X
Xchar* EDITOR::tell_selection ()
X{
X  char* s = new char[strlen(red->paste_buffer)];
X  strcpy (s, red->paste_buffer);
X  return s;
X}
X
X// -------------------------------------------------------------------------
X//  lose_selection: The editor has lost the X selection.  Remove the 
X//	highlight from the window.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::lose_selection ()
X{
X  if (buffer->selection_on) {
X    toggle_selection ();
X    screen->cursor_on (True);
X    show_point ();
X  }
X}
X
X// ========================== private functions ============================
X
X// -------------------------------------------------------------------------
X//  set_title: Update the window title and icon string attributes according
X//	to this editor's global attribute "filename".
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::set_title ()
X{
X  char title[80];
X  char *fname;
X
X  assert (filename);
X
X  fname = basename(filename);
X  if (fname[0] == '\0')
X    fname = "<no name>";
X
X  strcpy (title, "Red: ");
X  strcat (title, fname);
X
X  utility->set_title (edit_window, title, fname);
X}
X
X// -------------------------------------------------------------------------
X//  put_breakpoints: 
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::put_breakpoints (LIST* breaks)
X{
X  int line;
X
X  breaks->init_scan (ScanForward);
X  while ((line = (int)(breaks->next_element ()))) {
X    buffer->goto_pos (line, 0);
X    buffer->set_tag (BreakLineTag);
X  }
X  breaks->end_scan ();
X
X  buffer->goto_pos (1, 0);
X}
X
X// -------------------------------------------------------------------------
X//  set_saved: Set the saved/changed status of this buffer. This involves:
X//	set the internal flag and set the labal on screen. The parameter
X//	has to be true, to set it to "saved" or False to set it to "changed"
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::set_saved (Boolean sav)
X{
X  if (sav) {
X      info->message ( _CLASS_" saved", "", "");
X      utility->set_label (saved_label, "saved");
X      save_state = Saved;
X      #ifndef RED_ONLY
X	src_class->precompile ();
X      #endif
X  }
X  else if (save_state != Changed) {		// first change!
X      if (save_state == ReadOnly) {
X	messages->show_help (edit_window, HlpReadOnly);
X      }
X      utility->set_label (saved_label, "changed");
X      save_state = Changed;
X      #ifndef RED_ONLY
X	src_class->source_changed ();
X	set_compiled (False);
X      #endif
X  }
X}
X
X// -------------------------------------------------------------------------
X//  basename: return the filename without the path from a full path name.
X//	The pointer returned points into the original file name!  The string
X//	must not be free'd or modified.
X// -------------------------------------------------------------------------
X
Xchar *EDITOR::basename (char *filename)
X{
X  char *slash;
X
X  slash = strrchr (filename, '/');
X  if (slash)
X    return ++slash;
X  else
X    return filename;
X}
X
X// -------------------------------------------------------------------------
X//  dirname: return the pathname without the file name.  Returns a newly
X//	allocated string that should be deleted by the caller.
X//	Returns NULL if filename has no path in it.
X// -------------------------------------------------------------------------
X
Xchar *EDITOR::dirname (char *filename)
X{
X  char *dir;
X  char *slash;
X
X  assert (filename);
X
X  dir = new char[MAXPATH+1];
X  strncpy (dir, filename, MAXPATH);		// copy full path
X  dir[MAXPATH] = '\0';
X  slash = strrchr (dir, '/');
X  if (slash) {				// if '/' found...
X    *slash = '\0';			// ...cut off file name
X    return dir;
X  }
X  else {				// else return NULL
X    delete [] dir;
X    return NULL;
X  }
X}
X
X#include "editor_init.i"
X#include "editor_event.i"
X#include "editor_edit.i"
X#include "editor_move.i"
X#include "editor_display.i"
X#include "editor_func.i"
X#ifndef RED_ONLY
X  #include "editor_debug.i"
X#endif
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/editor.cc' &&
  chmod 0640 'Red/Red/editor.cc' ||
  echo 'restore of Red/Red/editor.cc failed'
  shar_count="`wc -c < 'Red/Red/editor.cc'`"
  test 19463 -eq "$shar_count" ||
    echo "Red/Red/editor.cc: original size 19463, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/editor.h ==============
if test -f 'Red/Red/editor.h' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/editor.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/editor.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/editor.h' &&
X#ifndef _EDITOR_H
X#define _EDITOR_H
X
X// ============================================================================
X//
X//  Class name: EDITOR
X//
X//  Author: M. Koelling							1995
X//
X//  Description:
X//
X//	EDITOR is part of the editor implementation for the Blue programming
X//	system and the stand-alone version Red.
X//
X//	EDITOR implements an editor for a single file in a single window.
X//	It is compiled and run as part of RED, which provides editing 
X//	facilities for multiple files in multiple windows by managing several
X//	instances of EDITOR.  All the resources shared by all editors are
X//	managed by Red (preferenes, key bindings), whereas all resources
X//	private to one editor are managed here.  They are mainly the screen
X//	elements belonging to this editor's window and the text buffer storing
X//	the text currenty edited.
X//
X// ============================================================================
X
X#include <Xm/Xm.h>
X#include <sys/stat.h>
X
X#include "screen.h"
X#include "info.h"
X#include "bufferpos.h"
X#include "buffer.h"
X#include "keymap.h"
X#include "userfunc.h"
X#include "actionstack.h"
X#include "../Utility/list.h"
X#include "../Utility/types.h"
X#include "../Utility/textregion.h"
X
X#ifdef RED_ONLY
X  #define ICLASS void
X#else
X  #include "../Project/iclass.h"
X#endif
X
Xenum SaveState { Saved, Changed, ReadOnly };
Xenum SearchDir { backwd, forwd };
X
Xclass EDITOR {
X
X	// widget callbacks are allowed to call internals...
X
X    friend void USERFUNC::init_functions ();
X
X    friend void EDITOR__window_close (Widget w, XtPointer editor,
X			 XtPointer call_data);
X
X    friend void EDITOR__menu_item (Widget w, XtPointer item, 
X			XtPointer call_data);
X
X    friend void EDITOR__tool_button_press (Widget w, XtPointer button_no, 
X			XtPointer call_data);
X
X    friend void EDITOR__scroll_event (Widget w, EDITOR *editor, 
X			XmScrollBarCallbackStruct* call_data);
X
X    friend void EDITOR__handle_event (Widget w, EDITOR *editor, 
X			XEvent* event, Boolean* ctd);
X
X    friend void EDITOR__resize (Widget w, EDITOR *editor, 
X			XtPointer call_data);
X
X    friend void EDITOR__do_revert (Widget w, XtPointer dlg, 
X			XtPointer call_data);
X
X    friend void x_paste_cb (Widget w, XtPointer call_data, Atom *selection, 
X			Atom *type, XtPointer value, unsigned long *length, 
X			int *format);
X  public:
X
X    EDITOR (ApplicationData* resource);
X
X	// Constructor of new editor.  'resource' are the application 
X	// resources.  The other flags indicate status at creation:
X	//  show_toolbar: if true, toolbar is visible
X	//  debug: if true, the row of debug buttons at bottom is visible
X	//  iconic: if true, editor window is opened as icon
X
X
X    ~EDITOR ();
X
X	// Destructor.
X
X
X    Boolean open (Widget toplevel, ICLASS *cl, char *fname, LIST* breakpoints, 
X		  Boolean show_toolbar, Boolean compiled, Boolean iconic);
X
X	// Open editor and load file "fname".
X
X
X    void come_up ();
X
X	// Bring this editor's window to the top of window stack.
X
X
X    void show_toolbar (Boolean show);	
X
X	// Show/hide the tool bar
X
X
X  #ifndef RED_ONLY
X    void set_compiled (Boolean compiled);	
X
X	// Indicate that this class is compiled.
X
X
X    void set_debug (Boolean enable);	
X
X	// Enable/disable debugging functions (stepping, etc)
X
X
X    void display_message (char* msg1, char* msg2, TEXTREGION region);
X
X	// Display an error message.  msg1 and msg2 define the two-line
X	// message.  region defines a region in the text that will be displayed
X	// and highlighted.
X
X
X    void insert_text (char* text);
X    
X	// Insert some text into the buffer at the current cursor position.
X
X
X    void replace_region (TEXTREGION region, char* text);
X
X	// Replace a part of the text in the buffer defined by 'region' with
X	// 'text'.
X  #endif
X
X  // == executing user functions -- the "do" functions are the part of the ==
X  // == game that really executes the function without asking any more     ==
X  // == questions.
X
X    void save ();
X
X	// save the buffer using the current name.
X
X
X    void do_save (char* fname);
X
X	// save the buffer under new name ("fname").
X
X
X    Boolean do_find (char* pattern, SearchDir direction,
X		     Boolean case_sens, Boolean whole_word);
X
X	// internal find used by all find functions.
X
X
X    void do_replace_all (char* pattern, SearchDir direction,
X		Boolean case_sens, Boolean whole_word, char* rep_pattern);
X
X	// Replace all 'pattern' with 'rep_pattern'.
X
X
X    Boolean do_replace (char* pattern);
X
X	// Internal replace used by replace.
X
X
X    char* tell_selection ();
X
X	// The editor is asked for the contents of the current selection.
X
X
X    void lose_selection ();
X
X	// The editor does not have the X selection any more.  Remove the
X	//  highlight.
X
X
X  private:
X
X  // -------------------- general (in editor.cc) ----------------------
X
X    void set_title ();			// update window and icon title
X    void put_breakpoints (LIST* breaks); // put existing breakpoints into buffer
X    void set_saved (Boolean sav);	// mark file as (not) saved
X    char *basename (char *filename);	// file name without directory path
X    char *dirname (char *filename);	// path without file name
X
X  // --------------- initialisation (in editor_init.i) ----------------
X
X    void init_window (Widget toplevel, Boolean show_tool, Boolean compiled,
X			Boolean iconic);
X
X  // -------------- event handling (in editor_event.i) ----------------
X
X    void handle_event (XEvent* event);		// a key/mouse event occurred
X    void scroll_event (int reason, int value);	// click in the scroll bar
X    void resize ();				// the window has been resized
X    void menu_item (MenuItemId item);		// a menu item was selected
X    void tool_button_press (int button_no);	// toolbar button was pressed
X    void handle_keypress (
X		XKeyPressedEvent *event);
X    void handle_mouseclick (
X		XButtonEvent *event);
X    void handle_buttonup (
X		XButtonEvent *event);
X    void handle_motion (XMotionEvent *event);
X    void handle_expose (XExposeEvent* event);
X    void click_in_tag_line (int line);
X    void call_userfunction (UserFuncId func);
X    void get_param (UserFuncId func);
X
X  // --------------- edit functions (in editor_edit.i) ----------------
X
X    void insert_char (char ch);	    // insert a character into the buffer
X    void insert_new_line (Boolean indent);   // insert a line break
X    void insert (char* str);	    // insert a string of characters
X    void delete_between_points ();  // delete the current selection
X    void self_insert_char ();	    // insert the last character typed
X    void new_line ();		    // insert a line break
X    void open_line ();		    // insert a line break but leave cursor
X    void tab_to_tab_stop ();	    // insert a Tab
X    void half_tab ();		    // insert a Half-Tab in line or block
X    void indent ();		    // indent as line above
X    void shift_line_right ();	    // increment line indentation by one
X    void shift_right ();	    // increment line or block indentation
X    void shift_line_left ();	    // decrement line indentation by one
X    void shift_left ();		    // decrement line or block indentation
X    void new_line_and_indent ();    // insert a line break and indent
X    void delete_char ();	    // delete char under cursor
X    void backward_delete_char ();   // backspace with delete
X    void backward_delete_untab ();  // backspace with delete (un-tabify)
X    void cut_word ();
X    void cut_to_end_of_word ();
X    void cut_line ();		    // cut current line to paste buffer
X    void cut_to_end_of_line ();
X    void cut_region ();		    // cut region to paste buffer
X
X    void select_region ();	    // select region between point and mark
X    void select_word ();	    // select complete current word
X    void select_line ();	    // select complete current line
X    void toggle_selection ();	    // switch selection on or off
X    void extend_highlight (	    // extend the current highlight
X		int screen_x,
X		int screen_y);
X    void drag_highlight (	    // drag the highlight
X		int screen_x,
X		int screen_y);
X    void make_selection ();	    // make selection from selection marks
X    Boolean check_selection (	    // if selection is on, turn it off
X		Boolean cut_it,
X		Boolean forwd);
X    void delete_selection ();	    // delete the current selection & display
X    void block_operation (	    // apply a function to the selection
X		CodePtr func);
X
X  // ---------- move & scroll functions (in editor_move.i) ------------
X
X    void backward_char ();	    // move cursor back
X    void forward_char ();	    // move cursor forward
X    void backward_word ();	    // move cursor word backwards
X    void forward_word ();	    // move cursor word forward
X    void next_line ();		    // move cursor one line down
X    void previous_line ();	    // move cursor one line up
X    void scroll_line_down ();	    // move display window one line down
X    void scroll_line_up ();	    // move display window one line up
X    void scroll_half_page_down ();
X    void scroll_half_page_up ();
X    void next_page ();		    // move display window one page down
X    void previous_page ();	    // move display window one page up
X    void scroll_drag (int value);
X    void beginning_of_line ();	    // move cursor to ...
X    void end_of_line ();	    // move cursor to ...
X    void beginning_of_text ();	    // move cursor to ...
X    void end_of_text ();	    // move cursor to ...
X    void cursor_to (int screen_x,   // set cursor, called by mouse click
X		    int screen_y);
X    Boolean forward_screenline (    // move cursor to start of next screen line
X		BUFFERPOS& pos);
X    Boolean backward_screenline (   // move cursor to start of prev screen line
X		BUFFERPOS& pos);
X
X  // ----------- display functions (in editor_display.i) -------------
X
X    void redisplay ();		    // display the buffer on screen
X    void display ();		    // display screen, cursor and scrollbar
X    void screen_update_from_bol (); // update screen from beg. of curr. line
X    void screen_update_from (	    // update part of screen and scrollbar
X		BUFFERPOS pos);
X    void display_from (		    // display part of buffer on part of screen
X		BUFFERPOS pos);
X    void show_point ();		    // display part of buffer containing point
X    void place_cursor_on_screen (); // place screen cursor according to point
X    void buffer_pos_to_screen_pos (
X		LINE* bufline, 
X		int bufcol,
X		int& scrline,
X		int& scrcol);
X    void set_point_to_square (int x, int y);
X
X  // --------------- user functions (in editor_func.i) ----------------
X
X  #ifdef RED_ONLY
X    void new_window ();
X    void open_other ();
X    void save_as ();
X  #endif
X
X    void revert ();		// ask: "Are you sure?"
X    void do_revert ();		// really revert now (no question)
X    void print ();
X    void close ();
X
X    void undo ();
X    void cut ();
X    void paste ();		// user func paste: request sel from X
X    void do_paste (char* text);	// now really paste it.
X
X    void interface_toggle ();
X
X    void find ();
X    void find_backward ();
X    void find_next ();
X    void find_next_reverse ();
X    void replace ();
X
X    void define_macro ();
X    void end_macro ();
X    void run_macro ();
X
X    void preferences ();
X    void key_bindings ();
X    void edit_toolbar ();
X    void fonts ();
X    void colours ();
X
X    void manual ();
X
X    void goto_line ();		    // move cursor to line (interactive)
X    void show_line ();		    // display current line number
X    void describe_key ();	    // print function of key (user intf)
X    void do_describe (UserFuncId func);	    // print function name
X    void set_mark ();		    // set mark at cursor position
X    void swap_point_mark ();	    // swap mark and cursor position
X
X    void blue_new_routine ();       // insert a new Blue routine skeleton
X
X    void edit_debug ();		    // print out some information for debugging
X    void empty_function ();	    // function that does nothing
X
X  // -------------- debug functions (in editor_debug.i) ---------------
X
X#ifndef RED_ONLY
X
X    void compile ();
X    void goto_error ();
X    void toggle_breakpoint ();	    // set a break point in current line
X    void set_breakpoint ();
X    void clear_breakpoint ();
X    void print_variable ();
X    void watch_variable ();
X    void step ();
X    void step_into ();
X    void continue_exec ();
X    void terminate_exec ();
X
X#endif
X
X  // ---------------------- end user functions ------------------------
X
X  // VARIABLES:
X
X    ApplicationData *rsrc;		// structure with application resource
X					//  values
X    ICLASS *src_class;			// the class we are editing (or NULL)
X    char *filename;			// name of file or NULL
X    mode_t filemode;			// mode (access rights) of file
X    SaveState save_state;		// indicate whether buffer is saved
X    Boolean first_expose;		// only true on very first expose
X    Boolean first_save;			// true if never been saved
X
X    char last_char;			// the character last typed
X    UserFuncId last_func;		// the last function executed
X
X    int mouse_line;			// line of last mouse click
X    int mouse_col;			// column of last mouse click
X    Boolean dragging;			// true while dragging selection
X    BUFFERPOS drag_start;		// the position where dragging started
X    Boolean button1_down;		// true while mouse button 1 is pressed
X    Time button1_uptime;		// time of button up (for double click)
X    Boolean double_click;		// True, if last click was double
X
X    Boolean search_found;		// true if last find was successfull
X    char* param_prompt;			// true if getting param in info area
X    char parameter[100];		// the parameter read in info area
X    int screen_column;			// the screen column aimed with up/down
X
X    SCREEN *screen;			// the edit screen
X    INFO *info;				// the information manager
X    BUFFER *buffer;			// the buffer storing the text
X    ACTIONSTACK* undo_stack;		// the stack storing actions for undo
X
X    BUFFERPOS top;			// position in buffer that is at top 
X					// of screen
X    BUFFERPOS bottom;			// position in buffer that is at 
X					// bottom of screen
X    int blanklines;			// number of screen lines below last
X					// text line
X    const unsigned char NewLine;	// the line break character used
X					//  internally in the editor (e.g. in
X					//  search patterns)
X
X    // below this only graphics objects (widgets)
X
X    Widget edit_window, text_area, da, scrollbar;
X    Widget menu_bar, toolbar, info_area, status_area;
X    Widget saved_label;
X
X  #ifndef RED_ONLY
X
X    Widget					// menus items
X      interface_item,
X      break_item, clr_break_item, watch_item, examine_item, 
X      step_item, step_into_item, cont_item, term_item;
X  #endif
X};
X
X#endif
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/editor.h' &&
  chmod 0640 'Red/Red/editor.h' ||
  echo 'restore of Red/Red/editor.h failed'
  shar_count="`wc -c < 'Red/Red/editor.h'`"
  test 14418 -eq "$shar_count" ||
    echo "Red/Red/editor.h: original size 14418, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/editor_callbacks.i ==============
if test -f 'Red/Red/editor_callbacks.i' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/editor_callbacks.i (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/editor_callbacks.i (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/editor_callbacks.i' &&
X// =========================================================================
X//
X// FILE: editor_callbacks.i	- part of editor.cc		  -mik- 1995
X//
X// This file contains the callbacks for the class EDITOR.
X// It is part of the implementation of class EDITOR.
X//
X// Callbacks C functions called on a user interface event (such as a button 
X// press).  They (unfortunatly) must have a C interface (Motif wants that).
X//
X// The convention for the Blue implementation is: Callback functions consist
X// ONLY of the required call to the desired object function.
X//
X// Naming Convention:  Callback names consist of the class and function 
X//	names of the function they call, separated by a double underscore,
X//
X//	e.g.:  CLASS__function_name
X//
X// =========================================================================
X
X// -------------------------------------------------------------------------
X//			 window manager close callback
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__window_close (Widget w, XtPointer editor, XtPointer call_data)
X{
X  ((EDITOR *)editor)->menu_item (CloseItem);
X}
X
X// -------------------------------------------------------------------------
X//			 editor menu item callback
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__menu_item (Widget w, XtPointer item, XtPointer call_data)
X{
X  int ac;
X  Arg al[10];
X  EDITOR* editor;
X
X  // extract editor pointer from widget user data
X
X  ac=0;
X  XtSetArg (al[ac], XmNuserData, &editor); ac++;
X  XtGetValues (w, al, ac);
X
X  editor->menu_item (MenuItemId ((int)item) );
X}
X
X// -------------------------------------------------------------------------
X//			 editor tool button callback
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__tool_button_press (Widget w, XtPointer button_no, 
X				XtPointer call_data)
X{
X  int ac;
X  Arg al[10];
X  EDITOR* editor;
X
X  ac=0;
X  XtSetArg (al[ac], XmNuserData, &editor); ac++;
X  XtGetValues (w, al, ac);
X
X  editor->tool_button_press ((int)button_no);
X}
X
X// -------------------------------------------------------------------------
X//			 editor scroll callback
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__scroll_event (Widget w, EDITOR *editor, 
X				XmScrollBarCallbackStruct* call_data)
X{
X  editor->scroll_event (call_data->reason, call_data->value);
X}
X
X
X// -------------------------------------------------------------------------
X//			 editor event callback
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__handle_event (Widget w, EDITOR *editor, XEvent* event, 
X				Boolean* ctd)
X{
X  editor->handle_event (event);
X}
X
X// -------------------------------------------------------------------------
X//			 editor resize callback
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__resize (Widget w, EDITOR *editor, XtPointer call_data)
X{
X  editor->resize ();
X}
X
X// -------------------------------------------------------------------------
X//			  question dialog callbacks
X// -------------------------------------------------------------------------
X
Xvoid EDITOR__do_revert (Widget w, XtPointer dlg, XtPointer call_data)
X{
X  EDITOR* editor;
X  bool yes_no;
X
X  editor = (EDITOR*) messages->close_question (dlg, w, yes_no);
X  editor->do_revert ();
X}
X
X// -------------------------------------------------------------------------
X//			  cut / paste callbacks
X// -------------------------------------------------------------------------
X
Xvoid x_paste_cb (Widget w, XtPointer call_data, Atom *selection, Atom *type,
X		XtPointer value, unsigned long *length, int *format)
X{
X  if (*type == XA_STRING)	// if the selection we got is a string...
X    ((EDITOR*)call_data)->do_paste ((char*)value);
X
X  XtFree ((char*)value);
X}
X
X// -------------------------------------------------------------------------
XBoolean x_tell_selection_cb (Widget w, Atom *selection, Atom *target, 
X		Atom *type_return, XtPointer *value_return, 
X		unsigned long *length_return, int *format_return)
X{
X  int ac;
X  Arg al[10];
X  EDITOR* ed;
X  char* text;
X
X  if (*target == XA_STRING) {
X
X    // extract object pointer from widget user data
X
X    ac=0;
X    XtSetArg (al[ac], XmNuserData, &ed); ac++;
X    XtGetValues (w, al, ac);
X
X    text = ed->tell_selection();
X    *type_return = XA_STRING;		// we are going to return a string
X    *value_return = text;		// this is the string
X    *length_return = strlen (text);	// length of returned string
X    *format_return = 8;			// format (no of bits/char) of data
X    return True;
X  }
X  else
X    return False;
X}
X
X// -------------------------------------------------------------------------
Xvoid x_selection_lost_cb  (Widget w, Atom *selection)
X{
X  int ac;
X  Arg al[10];
X  EDITOR* ed;
X
X  // extract object pointer from widget user data
X
X  ac=0;
X  XtSetArg (al[ac], XmNuserData, &ed); ac++;
X  XtGetValues (w, al, ac);
X
X  ed->lose_selection ();
X}
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/editor_callbacks.i' &&
  chmod 0640 'Red/Red/editor_callbacks.i' ||
  echo 'restore of Red/Red/editor_callbacks.i failed'
  shar_count="`wc -c < 'Red/Red/editor_callbacks.i'`"
  test 4989 -eq "$shar_count" ||
    echo "Red/Red/editor_callbacks.i: original size 4989, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/editor_debug.i ==============
if test -f 'Red/Red/editor_debug.i' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/editor_debug.i (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/editor_debug.i (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/editor_debug.i' &&
X// =========================================================================
X//
X// FILE: editor_debug.i	- part of editor.cc			  -mik- 1995
X//
X// This part contains implementations of the debugging functions.
X//
X// It is part of the implementation of class EDITOR.
X//
X// =========================================================================
X
X// -------------------------------------------------------------------------
X// compile: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::compile ()
X{
X  assert (src_class);
X  if (src_class->compile () == NULL)		// if no error...
X    info->message ("Class saved and compiled - no syntax errors", "", "");
X}
X
X// -------------------------------------------------------------------------
X// goto_error: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::goto_error ()
X{
X}
X
X// -------------------------------------------------------------------------
X// toggle_breakpoint: 
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::toggle_breakpoint ()
X{
X  if (buffer->get_tag(buffer->pt.line) == NoLineTag)
X    set_breakpoint ();
X  else if (buffer->get_tag(buffer->pt.line) == BreakLineTag)
X    clear_breakpoint ();
X}
X
X// -------------------------------------------------------------------------
X// set_breakpoint: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::set_breakpoint ()
X{
X  BPErr err;
X
X  if ((buffer->get_tag(buffer->pt.line) == BreakLineTag)  // got one already
X      || (buffer->get_tag(buffer->pt.line) == ExecBreakLineTag))
X    return;
X
X  err = src_class->set_breakpoint (buffer->pt.line_no);
X
X  switch (err) {
X    case BPnoError:
X	if (buffer->get_tag(buffer->pt.line) == ExecLineTag) {
X	  buffer->set_tag (ExecBreakLineTag);
X	  screen->set_tag (ExecBreakScreenTag);
X	}
X	else {
X	  buffer->set_tag (BreakLineTag);
X	  screen->set_tag (BreakScreenTag);
X	}
X	break;
X    case BPErrTooManyBP:
X	info->warning ("Too many breakpoints",
X	"(A maximum of five breakpoints per routine is possible.)");
X	break;
X    case BPErrNoCodeLine:	
X	info->warning ("No code in this line",
X	"(You can set breakpoints only in lines that contain statements.)");
X	break;
X    case BPErrNotCompiled:
X	info->warning ("Class not compiled",
X	"(You can set a breakpoint only after a class has been compiled.)");
X	break;
X  }
X}
X
X// -------------------------------------------------------------------------
X// clear_breakpoint: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::clear_breakpoint ()
X{
X  if (buffer->get_tag(buffer->pt.line) == BreakLineTag) {
X    src_class->clear_breakpoint (buffer->pt.line_no);
X    buffer->set_tag (NoLineTag);
X    screen->set_tag (NoScreenTag);
X  }
X  else if (buffer->get_tag(buffer->pt.line) == ExecBreakLineTag) {
X    src_class->clear_breakpoint (buffer->pt.line_no);
X    buffer->set_tag (ExecLineTag);
X    screen->set_tag (ExecScreenTag);
X  }
X}
X
X// -------------------------------------------------------------------------
X// print_variable: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::print_variable ()
X{
X}
X
X// -------------------------------------------------------------------------
X// watch_variable: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::watch_variable ()
X{
X}
X
X// -------------------------------------------------------------------------
X// step: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::step ()
X{
X  controller->step ();
X}
X
X// -------------------------------------------------------------------------
X// step_into: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::step_into ()
X{
X  controller->step_into ();
X}
X
X// -------------------------------------------------------------------------
X// continue: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::continue_exec ()
X{
X  controller->continue_exec ();
X}
X
X// -------------------------------------------------------------------------
X// terminate: 
X//	
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::terminate_exec ()
X{
X  controller->terminate ();
X}
SHAR_EOF
  $shar_touch -am 0512222696 'Red/Red/editor_debug.i' &&
  chmod 0640 'Red/Red/editor_debug.i' ||
  echo 'restore of Red/Red/editor_debug.i failed'
  shar_count="`wc -c < 'Red/Red/editor_debug.i'`"
  test 4378 -eq "$shar_count" ||
    echo "Red/Red/editor_debug.i: original size 4378, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= Red/Red/editor_display.i ==============
if test -f 'Red/Red/editor_display.i' && test X"$1" != X"-c"; then
  echo 'x - skipping Red/Red/editor_display.i (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting Red/Red/editor_display.i (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Red/Red/editor_display.i' &&
X// =========================================================================
X//
X// FILE: editor_display.i	- part of editor.cc		  -mik- 1995
X//
X// This part contains implementations of all functions concerned with the
X// display of the text in the editor.  It is part of the implementation of
X// class EDITOR.
X//
X// =========================================================================
X
X// -------------------------------------------------------------------------
X//  redisplay: Display the buffer on screen.  That is: clear the whole
X//	screen, calculate topline (the line at the top of the screen) so
X//	that point is in the middle of the screen, and redisplay the then
X//	visible buffer contents on the screen.
X//	This is done by calculating topline and then calling "display".
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::redisplay ()
X{
X  int ln, length;
X  char* str;
X
X  top = buffer->pt;
X  top.column = 0;
X  ln = (screen->lines-1)/2;
X
X  buffer->get_text_in_line (buffer->pt.line, 0, str, length);
X  ln -= screen->nr_of_lines (str, buffer->pt.column, 0);
X
X  while (ln > 0) {
X    if (buffer->is_top (top.line))
X      break;
X    buffer->prev_line (top);
X    buffer->get_text_in_line (top.line, 0, str, length);
X    ln -= screen->nr_of_lines (str, length, 0);
X  }
X
X  if (ln < 0)		// screenline not beginning of buffer line
X    top.column = screen->square_to_index (str, length, ln, 0, 0);
X
X  assert (top.column >= 0);
X  display ();
X}
X
X// -------------------------------------------------------------------------
X//  display: Display the current screen (according to top.line), place the
X//	cursor and set the scrollbar accordingly.
X//	It is assumed that topline points to the line to be displayed at the
X//	top of the screen. If the cursor is not on the screen, place it on
X//	the screen. The whole screen is then redisplayed.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::display ()
X{
X  int oldblanklines = blanklines;
X
X  screen->cursor_on (False);
X  screen->cursor_to (0,0);
X  display_from (top);
X
X  if (buffer->selection_on) {
X    if (buffer->pt.is_before (top)) {
X      buffer->unselect ();
X      dragging = False;
X      buffer->point_to (top);
X      place_cursor_on_screen ();
X      screen->cursor_on (True);
X    }
X    else if (buffer->pt2.is_behind (bottom)) {
X      buffer->unselect ();
X      dragging = False;
X      buffer->point_to (bottom);
X      place_cursor_on_screen ();
X      screen->cursor_on (True);
X    }
X  }
X  else {
X    if (buffer->pt.is_before (top))
X      buffer->point_to (top);
X    else if (buffer->pt.is_behind (bottom))
X      buffer->point_to (bottom);
X    place_cursor_on_screen ();
X    screen->cursor_on (True);
X  }
X
X//  if ((!buffer->pt.is_before (top)) && (!buffer->pt.is_behind (bottom))) {
X//    place_cursor_on_screen ();
X//    screen->cursor_on (!buffer->selection_on);
X//  }
X
X  utility->set_scrollbar (scrollbar, top.line_no, 
X				bottom.line_no - top.line_no + 1,
X				buffer->lines + 1);
X}
X
X// -------------------------------------------------------------------------
X//  screen_update_from_bol: Update the screen from the beginning of the 
X//	current line.
X//	Display from:	buffer pos: beg. of pt.line
X//			screen pos: screen pos of (beg. of pt.line)
X//	The selection must be off.
X//	Positions cursor to point position.
X// -------------------------------------------------------------------------
X
Xvoid EDITOR::screen_update_from_bol ()
X{
X  BUFFERPOS pos;
X  BUFFERPOS pt_pos;
X
X  buffer->get_point (pt_pos);		// store point position
X
X  if (buffer->pt.column <= screen->columns) {
X    buffer->point_to_bol ();
X    screen->cursor_to (0, screen->line);
X  }
X  else {
X    buffer->point_to_bol ();
X    show_point ();
X  }
X  buffer->get_point (pos);
X  buffer->point_to (pt_pos);		// restore point position
X  screen_update_from (pos);
X}
X
X// -------------------------------------------------------------------------
X//  screen_update_from: Update the screen from a certain point. That is:
X//	Display the screen from that point and update the scroll bar.
X//	Display from:	buffer pos: 'pos'
SHAR_EOF
  : || echo 'restore of Red/Red/editor_display.i failed'
fi
echo 'End of archive part 4'
echo 'File Red/Red/editor_display.i is continued in part 5'
echo 5 > _sharseq.tmp
exit 0


