ftp.nice.ch/pub/next/unix/editor/jed.N.bs.tar.gz#/jed.N.bs/src/cmds.c

This is cmds.c in view mode; [Download] [Up]

/*
 *  Copyright (c) 1992, 1995 John E. Davis  (davis@space.mit.edu)
 *  All Rights Reserved.
 */
#include <config.h>

#include <stdio.h>
#include <slang.h>

#include <string.h>

#include "buffer.h"
#include "screen.h"
#include "window.h"
#include "ins.h"
#include "ledit.h"
#include "cmds.h"
#include "line.h"
#include "paste.h"
#include "display.h"
#include "vterm.h"
#include "sysdep.h"
#include "text.h"
#include "file.h"
#include "misc.h"
#include "search.h"
#include "hooks.h"
#include "abbrev.h"
#ifdef HAS_SUBPROCESSES
# include "jprocess.h"
#endif

void (*X_Suspend_Hook)(void);

int Blink_Flag = 1;
int Indented_Text_Mode = 0;	       /* if non zero, intent line after wrap */
int Kill_Line_Feature = 1;	       /* non-zero means kill through eol if bolp  */
int C_Bra_Newline = 1;		       /* if zero, do not insert newline before '{' */

int C_Comment_Hint;


static char *Top_Of_Buffer_Error = "Top Of Buffer.";
static char *End_Of_Buffer_Error = "End Of Buffer.";

/* return 1 if line extends beyond the screen */
static int long_line(void)
{
   int p, col;
   
   col = Screen_Col;
   p = Point;
   Point = CLine->len - 1;
   if ((*(CLine->data + Point) != '\n') || (CBuf == MiniBuffer)) Point++;
   if (calculate_column() >= JWindow->width - 1)
     {
	Point = p;
	Screen_Col = col;
	return(1);
     }
   Screen_Col = col;
   Point = p;
   return(0);
}

#define FAST_NOT_OK ((Repeat_Factor != NULL) || JWindow->trashed\
        || (ch < ' ') || (ch > 126) || Input_Buffer_Len\
	|| Suspend_Screen_Update\
        || (Screen_Col >= JWindow->width - 2) || (JWindow->column > 1)\
	|| Batch || (CLine->len == 0)\
	|| ((CBuf->marks != NULL) && Wants_Attributes)\
	|| input_pending(&Number_Zero) || Executing_Keyboard_Macro\
        || tabs_present()\
	|| (Read_This_Character != NULL))



int newline()
{
#if 0
   int push = 0;
#endif
   CHECK_READ_ONLY
     
     if (CBuf == MiniBuffer) return exit_minibuffer();
   
   insert_string ("\n");
#if 0
   /* This bit of nonsense gives a better looking screen update.  The problem
    * with doing this is that it screws up the marks.  
    */
   if (bolp() && (CLine->prev != NULL) && (CLine->len > 1))
     {
	push = 1;
	push_spot();
	CLine = CLine->prev;
	LineNum--;
	Point = 0;
	eol();
     }
   
   split_line();
   ins('\n');
   check_line();
   if (push)
     {
	pop_spot();
	return(1);
     }
   
   Point--;
   forwchars(&Number_One);
#endif
   return(1);
}

int previous_char_cmd()
{
   int pnt;
   Cursor_Motion = 1;
   if (bobp())
     {
	msg_error(Top_Of_Buffer_Error);
	return(0);
     }
   
   pnt = Point - 1;
   backwchars(&Number_One);
   Goal_Column = calculate_column();
   /* For syntax highlighting */
   if ((Last_Key_Function != (FVOID_STAR) previous_char_cmd) &&
       ((Last_Key_Function == (FVOID_STAR) ins_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify)))
     register_change(0);
   
   return (pnt == -1) || JWindow->trashed;
}

/* Slang calls by reference so make this a pointer ! */
void insert_whitespace(int *n)
{
   int tab = Buffer_Local.tab;
   int c1, c2, i, k, nspace;
   
   if ((nspace = *n) <= 0) return;
   CHECK_READ_ONLY_VOID
     c1 = calculate_column() - 1;
   c2 = c1 + nspace;
   
   if (tab)
     {
	i = c1 / tab;
	k = c2 / tab - i;
	if (k) nspace = c2 - (i + k) * tab;
	ins_char_n_times('\t', k);
     }
   ins_char_n_times(' ', nspace);
}

/* check from point to end of line looking for tabs */
static int tabs_present(void)
{
   unsigned char *p, *pmax;
   
   if (!Buffer_Local.tab) return(0);
   pmax = CLine->data + CLine->len;
   p = CLine->data + Point;
   
   while (p < pmax) if (*p++ == '\t') return(1);
   return(0);
}

int delete_char_cmd()
{
   int upd, n;
   char ch;
   
   CHECK_READ_ONLY
     if (eobp())
     {
	msg_error(End_Of_Buffer_Error);
	return(0);
     }
   
   ch = *(CLine->data + Point);
   
   if (FAST_NOT_OK || long_line ()
       || *tt_Term_Cannot_Insert
       )
     {
	if ((Point == 0) && eolp()
#ifdef JED_LINE_ATTRIBUTES
	    && ((CLine->prev != NULL)
		&& ((CLine->prev->flags & JED_LINE_READONLY) == 0))
#endif
	    )
	  n = 1;
	else n = 0;
	/* same effect, update looks better */
	n = backwchars(&n);
	del();
	forwchars(&n);
	upd = 1;
     }
   else
     {
	upd = ((CBuf->flags & BUFFER_TRASHED) == 0);
	fast_del();
	tt_delete_char ();
     }
   
   return(upd);
}

int backward_delete_char_cmd()
{
   char ch;
   int ret;
   
   CHECK_READ_ONLY
     if (bobp())
     {
	msg_error(Top_Of_Buffer_Error);
	return(0);
     }
   
   if (bolp())
     {
	backwchars(&Number_One);
	return delete_char_cmd();
     }
   
   ch = *(CLine->data + (Point - 1));
   
   if (FAST_NOT_OK || long_line ()
       || *tt_Term_Cannot_Insert
       )
     {
	backwchars(&Number_One);
	del();
	return(1);
     }
   
   ret = ((CBuf->flags & BUFFER_TRASHED) == 0);
   backwchars(&Number_One);
   tt_putchar('\b');
   Screen_Col--;
   fast_del();
   tt_delete_char();
   return(ret);
}

int backward_delete_char_untabify()
{
   unsigned char *p;
   int n;
   
   CHECK_READ_ONLY
     p = CLine->data + (Point - 1);
   
   /* note that short circuit is assumed to avoid seg fault */
   if (!Point || bobp() || (*p != '\t') || !Buffer_Local.tab) return backward_delete_char_cmd();
   
   n = calculate_column() - 1;
   backwchars(&Number_One);
   del();
   n = n - calculate_column();
   ins_char_n_times(' ', n);
   
   return(1);
}

int previous_line_cmd()
{
   int ret, gc;
   
   if (CLine == CBuf->beg)
     {
	msg_error(Top_Of_Buffer_Error);
	return(0);
     }
   check_line();
   gc = calculate_column();
   if (Cursor_Motion <= 0) Goal_Column = gc;
   else if (Goal_Column < gc) Goal_Column = gc;
   
   Cursor_Motion = 2;
   
   /* For syntax highlighting */
   if ((Last_Key_Function != (FVOID_STAR) previous_line_cmd) &&
       ((Last_Key_Function == (FVOID_STAR) ins_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify)))
     register_change(0);
   
   ret = JWindow->trashed || (CLine == JScreen[JWindow->top - 1].line);
   
   CLine = CLine->prev;
   LineNum--;
   point_column(Goal_Column);
   return(ret);
}

int next_line_cmd()
{
   int ret, gc;
   
   if (CLine == CBuf->end)
     {
	msg_error(End_Of_Buffer_Error);
	return(0);
     }
   check_line();
   gc = calculate_column();
   if (Cursor_Motion <= 0) Goal_Column = gc;
   else if (Goal_Column < gc) Goal_Column = gc;
   
   Cursor_Motion = 2;
   
   /* For syntax highlighting */
   if ((Last_Key_Function != (FVOID_STAR) next_line_cmd) &&
       ((Last_Key_Function == (FVOID_STAR) ins_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify)))
     register_change(0);
   
   ret = JWindow->trashed || (CLine == JScreen[JWindow->top + JWindow->rows - 2].line);
   
   CLine = CLine->next;
   LineNum++;
   point_column(Goal_Column);
   return(ret);
}

int next_char_cmd()
{
   Cursor_Motion = 1;
   
   /* For syntax highlighting */
   if ((Last_Key_Function != (FVOID_STAR) next_char_cmd) &&
       ((Last_Key_Function == (FVOID_STAR) ins_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd)
	|| (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify)))
     register_change(0);
   
   if (!forwchars(&Number_One))
     {
	msg_error(End_Of_Buffer_Error);
	return (0);
     }
   Goal_Column = calculate_column();
   return !Point || JWindow->trashed;  /* Point = 0 ==> moved a line */
}

extern Buffer *Paste_Buffer;

int kill_line()
{
   int n, pnt, flag = 0;
   
   CHECK_READ_ONLY
     
     if (eobp())
     {
	msg_error(End_Of_Buffer_Error);
	return(0);
     }
   
   push_mark();
   push_spot();
   pnt = Point;
   eol();
   n = Point - pnt;
   if ((!pnt && Kill_Line_Feature) || !n)
     {
	
	/* Either of these (flag =0,1) have the same effect on the buffer.
	 *  However, the first sets the mark at the end of the line and moves
	 *  the point to the end of the previous line.  This way the current
	 *  line structure is deleted and the screen update looks better.
	 */
	if (!pnt && (CLine->prev != NULL) && (CLine->next != NULL))
	  {
	     flag = 1;
	     forwchars(&Number_One);
	  }
	else n += forwchars(&Number_One);
	
     }
   
   if ((Last_Key_Function == (FVOID_STAR) kill_line) && (Paste_Buffer != NULL))
     {
	copy_region_to_buffer(Paste_Buffer);
     }
   else copy_to_pastebuffer();
   pop_spot();
   if (flag) n += backwchars(&Number_One);
   generic_deln(&n);
   if (flag) forwchars(&Number_One);
   return(1);
}


/* get indent value of current line, n is the column */
unsigned char *get_current_indent(int *np)
{
   unsigned char *p, *pmax;
   int tab, n;
   
   tab = Buffer_Local.tab;
   p = CLine->data;
   pmax = CLine->data + CLine->len;
   n = 0;
   while((p < pmax) && ((*p == ' ') || (tab && (*p == '\t'))))
     {
	if (*p == '\t')
	  n = tab * (n / tab + 1);
	else n++;
	p++;
     }
   *np = n;
   return p;
}


int trim_whitespace()
{
   register unsigned char *p, *pmax, ch;
   int n, save_point, len;
   
   CHECK_READ_ONLY
     len = CLine->len;
   if (len == 0) return(0);
   
   save_point = Point;
   if (Point == len) Point--;
   
   /* Note that we save the point before --ing it.  This way the comparison
    made below will effectively restore it if pointing at non whitespace */
   
   p = CLine->data + Point;
   if (Point && (*p == '\n') && (CBuf != MiniBuffer))
     {
	Point--;
	p--;
     }
   
   while ((Point > 0) && (((ch = *p) == '\t') || (ch == ' ')))
     {
	Point--;
	p--;
     }
   
   if (save_point != Point) if (!eolp() && ((*p != ' ') && (*p != '\t')))
     {
	Point++;
	p++;
     }
   
   n = 0;
   /* this needs to be inlined.  Actually for undo, I need del(n)! */
   pmax = CLine->data + CLine->len;
   while ((p < pmax) && ((ch = *p) != '\n')
	  && ((ch == ' ') || (ch == '\t'))) p++, n++;
   
   deln(&n);
   return(1);
}

/* indent line to column n */
void indent_to(int n)
{
   int m;
   
   get_current_indent(&m);
   
   if (n != m)
     {
	Point = 0;
	trim_whitespace();
	if (n >= 0) insert_whitespace(&n);
     }
}

int indent_line ()
{
   int n, n1;
   static int in_function;
   
   if (in_function) return -1;
   
   if (CBuf->indent_hook != NULL)
     {
	in_function = 1;
	SLexecute_function(CBuf->indent_hook);
	in_function = 0;
	return 1;
     }
   
   CHECK_READ_ONLY
     
     if (CLine == CBuf->beg) return(0);
   
   push_spot();
   CLine = CLine->prev;
   get_current_indent (&n);
   CLine = CLine->next;
   indent_to(n);
   pop_spot();
   
   /* This moves the cursor to the first non whitspace char if we are
    before it.  Otherwise leave it alone */
   
   n1 = calculate_column();
   get_current_indent(&n);
   if (n1 <= n) point_column(n + 1);
   return 1;
}

int newline_and_indent()
{
   static int in_function;
   if (in_function) return -1;
   if (CBuf->newline_indent_hook != NULL)
     {
	in_function = 1;
	SLexecute_function(CBuf->newline_indent_hook);
	in_function = 0;
	return 1;
     }
   newline();
   indent_line();
   return(1);
}

int ins_char_cmd()
{
   char ch;
   
   int wrap = User_Vars.wrap_column;
   int ret, ll;
   
   CHECK_READ_ONLY
     ch = (char) SLang_Last_Key_Char;
   
   if (ch == '\n')
     {
	newline();
	return(1);
     }
   
#ifdef HAS_ABBREVS
   if (CBuf->flags & ABBREV_MODE)
     {
	expand_abbrev (ch);
     }
#endif
   
   if ((CBuf->flags & OVERWRITE_MODE) && !eolp()) del();
   
   if (((ch == ' ') || (Point >= wrap)) && (CBuf->modes & WRAP_MODE)
       && (calculate_column() > wrap)) /* JWindow->width */
     {
	ins(ch);
	wrap_line(0);			/* do not format--- just wrap */
	if (Indented_Text_Mode) indent_line ();
	if (CBuf->wrap_hook != NULL)
	  SLexecute_function(CBuf->wrap_hook);
	
	return(1);
     }
   
   if ((ch == ' ') || FAST_NOT_OK  || (CBuf->flags & OVERWRITE_MODE)
       || (*tt_Term_Cannot_Insert && !eolp())
       )
     {
	ins(ch);
	if ((CBuf->syntax_table != NULL)
	    && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX)
	    && !input_pending(&Number_Zero)) blink_match (); /* (ch); */
	return(1);
     }
   
   
   ret = ((CBuf->flags & BUFFER_TRASHED) == 0) || (User_Prefers_Line_Numbers > 1);
   
   if (long_line ()) ll = 1; else ll = 0;
   ret = ret || ll;
   
   /* fast_ins goes first so that screen structure is updated now
    for following calls to use. */
   
   fast_ins(ch);
   if (!eolp() || ll)
     {
	tt_begin_insert();
	tt_putchar(ch);
	tt_end_insert();
	if (ll) register_change(0);
     }
   else tt_putchar(ch);
   Screen_Col++;
   if ((CBuf->syntax_table != NULL)
       && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX)
       && !input_pending(&Number_Zero)) blink_match (); /* (ch); */
   return(ret);
}

int eol_cmd (void)
{
   eol();
   if ((0 == (CBuf->flags & READ_ONLY))
#ifdef JED_LINE_ATTRIBUTES
       && (0 == (CLine->flags & JED_LINE_READONLY))
#endif
       )
     trim_whitespace();
   return(1);
}


int sys_spawn_cmd()
{
   if (Jed_Secure_Mode)
     {
	msg_error ("Access to shell denied.");
	return -1;
     }
   
   if (Batch)
     {
	sys_suspend ();
	return 0;
     }
   
   if (X_Suspend_Hook != NULL)
     {
	(*X_Suspend_Hook) ();
	return (0);
     }
   
   SLang_run_hooks("suspend_hook", NULL, NULL);
   if (SLang_Error) return(0);
   reset_display();
   reset_tty();
   sys_suspend();
   init_tty();
   flush_input ();
   init_display(1);
   /* cls(); */
   SLang_run_hooks("resume_hook", NULL, NULL);
   check_buffers();
   return(1);
}

int quit_jed(void)
{
   Buffer *b = CBuf;
   
   /* Any buffer marked with AUTO_SAVE_JUST_SAVE flag should be saved
    * if it has not already been.  That is what the flag is for and this
    * code fragment carries this out.
    */
   do
     {
	if ((b->flags & AUTO_SAVE_JUST_SAVE)
	    && (b->flags & BUFFER_TRASHED)
	    && (*b->file))
	  {
	     while (b->narrow != NULL) widen_buffer(b);
	     auto_save_buffer(b);      /* actually, it will save it */
	  }
	
#if defined(__WIN32__) && defined(HAS_SUBPROCESSES)
 	if (b->subprocess)
 	  jed_kill_process(b->subprocess - 1);
#endif
	
	b = b->next;
     }
   while (b != CBuf);
   
   reset_display();
   reset_tty();
#ifdef VMS
   vms_cancel_exithandler();
#endif
#ifdef SLANG_STATS
   SLang_dump_stats("slang.dat");
#endif
#ifdef MALLOC_DEBUG
   SLmalloc_dump_statistics ();
#endif
   exit(0);
   return(1);
}


int quoted_insert()
{
   char ch;
   int lerr = SLang_Error;
   
   CHECK_READ_ONLY
     if (*Error_Buffer || SLKeyBoard_Quit) return(0);
   if (Repeat_Factor != NULL)
     {
	ch = *Repeat_Factor;
	Repeat_Factor = NULL;
     }
   else
     {
	SLang_Key_TimeOut_Flag = 1;
	ch = jed_getkey();
	SLang_Key_TimeOut_Flag = 0;
     }
   
   
   SLang_Error = lerr;  /* ^G may set it */
   
   if ((ch == '\n') && (CBuf == MiniBuffer))
     {
	ins('\n');
	/* msg_error("Not allowed!"); */
	return (1);
     }
   
   SLKeyBoard_Quit = 0;
   ins_char_n_times(ch, 1);
   
   
   if ((CBuf->syntax_table != NULL)
       && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX)
       && !input_pending(&Number_Zero)) blink_match (); /* (ch); */
   
   return(1);
}

/* I should try it like emacs--- if prefix argument, then save all without user
 intervention */
int save_some_buffers(void)
{
   Buffer *b, *tmp;
   int ans = 0;
   char msg[256];
   int err;
   
   b = CBuf;
   do
     {
	if ((b->flags & BUFFER_TRASHED)
	    && (*b->file))
	  {
	     if (b->flags & AUTO_SAVE_JUST_SAVE) ans = 'y';
	     else
	       {
		  sprintf(msg,"Buffer %s not saved. Save it? (y/n)", b->name);
		  flush_message(msg);
		  ans = my_getkey();
	       }

	     while (1)
	       {
		  if ((ans == 'y') || (ans == 'Y'))
		    {
		       tmp = CBuf;
		       switch_to_buffer(b);
		       while (b->narrow != NULL) widen_buffer(b);
		       err = write_file_with_backup(b->dir, b->file);
		       switch_to_buffer(tmp);
  		       if (err < 0) return(-1);
		       b->flags &= ~BUFFER_TRASHED;
		       b->flags |= AUTO_SAVE_BUFFER;
		       b->hits = 0;
		       break;
		    }
		  else if ((ans == 'n') || (ans == 'N'))
		    {
		       /* disabling this */
		       /* auto_save_buffer(b); */
		       break;
		    }
		  else if (SLKeyBoard_Quit)
		    {
		       /* warning--- bug here if user edits file at
			startup and forgets to save it then aborts. */
		       return(-1);
		    }
		  else
		    {
		       beep();
		       sprintf(msg,"Buffer %s not saved. Save it", b->name);
		       ans = get_yes_no(msg);
		       if (ans == 1) ans = 'y'; else if (!ans) ans = 'n';
		       else return(-1);
		    }
	       }
	  }
	
	b = b->next;
     }
   while (b != CBuf);

   clear_message ();
   return(1);
}

int exit_jed()
{
   static int in_exit_jed = 0;
   
   if (!in_exit_jed)
     {
	in_exit_jed = 1;
	if (SLang_run_hooks("exit_hook", NULL, NULL))
	  {
	     in_exit_jed = 0;
	     return(1);
	  }
     }
   
   in_exit_jed = 0;
   if (SLang_Error) return(0);
   if (save_some_buffers() > 0) quit_jed();
   return(1);
}

int jed_buffer_visible (char *b)
{
   return buffer_visible (find_buffer(b));
}

static void scroll_completion (int dir)
{
   Window_Type *w;
   
   if (jed_buffer_visible (Completion_Buffer))
     {
	pop_to_buffer (Completion_Buffer);
   	if (dir > 0) pagedown_cmd (); else pageup_cmd ();
	while (!IS_MINIBUFFER) other_window ();
     }
   else
     {
	w = JWindow;
	other_window();
	if (!IS_MINIBUFFER)
	  {
	     if (dir > 0) pagedown_cmd (); else pageup_cmd ();
	  }
	while (JWindow != w) other_window ();
     }
}

static int goto_bottom_of_window (void)
{
   int n;
   n = JWindow->rows - window_line ();
   return n == nextline (&n);
}

static void goto_top_of_window (void)
{
   int n;
   n = window_line () - 1;
   (void) prevline (&n);
}


static int Last_Page_Line;
static int Last_Page_Point;

/* the page up/down commands set cursor_motion to -1 because we do not
 want to use any goal column information */
int pagedown_cmd()
{
   int col, this_line, this_point;
   int n;
   
   Cursor_Motion = -1;
   if (IS_MINIBUFFER)
     {
	scroll_completion (1);
	return 1;
     }
   
   if (eobp())
     {
	msg_error(End_Of_Buffer_Error);
	return 1;
     }
   
   n = JWindow->rows;
   if ((CBuf != JWindow->buffer) || (n == 1))
     {
	return (nextline(&n));
     }
   
   if (JWindow->trashed)
     {
	update (NULL, 0, 0);
	if (JWindow->trashed) return nextline(&n);
     }
   
   this_line = LineNum;
   this_point = Point;
   
   col = calculate_column ();
   if (goto_bottom_of_window ())
     {
	recenter (&Number_One);
     }
   
   goto_column1 (&col);
   
   if ((Last_Key_Function == (FVOID_STAR) pageup_cmd) && is_line_visible (Last_Page_Line))
     {
	goto_line (&Last_Page_Line);
	Point = Last_Page_Point;
     }
   else if (CLine->next == NULL) eol(); else Point = 0;
   
   Last_Page_Line = this_line;
   Last_Page_Point = this_point;
   
   return(1);
}

int pageup_cmd (void)
{
   int col, this_line, this_point;
   int n;
   
   Cursor_Motion = -1;
   
   if (IS_MINIBUFFER)
     {
	scroll_completion (-1);
	return 1;
     }
   
   if (bobp())
     {
	msg_error(Top_Of_Buffer_Error);
	return 1;
     }
   
   n = JWindow->rows;
   if ((CBuf != JWindow->buffer) || (n == 1))
     {
	return prevline(&n);
     }
   
   if (JWindow->trashed)
     {
	update (NULL, 0, 0);
	if (JWindow->trashed) return prevline (&n);
     }
   
   this_line = LineNum;
   this_point = Point;
   col = calculate_column ();
   goto_top_of_window ();
   (void) goto_column1(&col);
   recenter(&JWindow->rows);
   
   if ((Last_Key_Function == (FVOID_STAR) pagedown_cmd) && is_line_visible (Last_Page_Line))
     {
	goto_line (&Last_Page_Line);
	Point = Last_Page_Point;
     }
   else Point = 0; /* something like: Point = point_column(JWindow->column) better? */
   Last_Page_Line = this_line;
   Last_Page_Point = this_point;
   return(1);
}


int scroll_right()
{
   if (JWindow->column == 1) return(0);
   
   if ((JWindow->column = JWindow->column - JWindow->width / 2) < 1)
     {
	JWindow->column = 1;
     }
   
   touch_window();
   return(1);
}

int scroll_left()
{
   JWindow->column = JWindow->column + JWindow->width / 2;
   touch_window();
   return(1);
}

/* goto to column c, returns actual column */
int goto_column1(int *cp)
{
   int c1, c = *cp;
   if (c <= 0) c = 1;
   eol();
   c1 = calculate_column();
   if (c1 > c)
     {
	point_column(c);
	c1 = calculate_column();
     }
   return(c1);
}

/* move cursor to column c adding spaces if necessary */
void goto_column(int *c)
{
   int c1 = *c;
   if (c1 <= 0) c1 = 1;
   c1 = c1 - goto_column1(&c1);
   insert_whitespace(&c1);
}

/* does not leave current line */
unsigned int skip_whitespace()
{
   unsigned char *p, *pmax;
   
   if (CLine->len == 0) return('\n');
   
   p = CLine->data + Point;
   eol();
   pmax = CLine->data + Point;
   while(p < pmax)
     {
	if ((*p != ' ') && (*p != '\t')) break;
	p++;
     }
   Point = (int) (p - CLine->data);
   return(*p);
}

#define upcase(ch) (Case_Sensitive ? ch : UPPER_CASE(ch))


/* returns < 0 if what is smaller than current thing, 0 if matched, pos otherwise */
int looking_at(char *what)
{
   register unsigned char *p, *pmax;
   register unsigned char *w = (unsigned char *) what, ch;
   Line *l = CLine;
   
   p = l->data + Point;
   while (1)
     {
	pmax = l->data + l->len;
	while (((ch = *w) != 0) && (p < pmax))
	  {
	     if ((upcase(ch) != upcase(*p))) return 0;
	     p++; w++;
	  }
	if (ch == 0) return 1;
	l = l->next;
	if (l == NULL) return 0;
	p = l->data;
     }
}


void skip_chars1(char *range, int reverse)
{
   unsigned char lut[256];
   unsigned char *p, *pmax;
   Line *line;
   int n = 0;
   
   SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse);
   /* more flexibility is achieved with following line */
   if (reverse && lut['\n']) lut['\n'] = 0;
   
   line = CLine;
   while (line != NULL)
     {
	CLine = line;
	p = line->data + Point;
	pmax = line->data + line->len;
	
	while (p < pmax)
	  {
	     if (0 == lut[*p])
	       {
		  Point = (int)(p - CLine->data);
                  LineNum += n;
		  return;
	       }
	     p++;
	  }
	Point = 0;
	line = CLine->next;
        n++;
     }
   eob();
}

void bskip_chars1(char *range, int reverse)
{
   unsigned char lut[256];
   unsigned char *p;
   Line *line = CLine;
   int n = 0;
   
   SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse);
   /* more flexibility is achieved with following line */
   if (reverse && lut['\n']) lut['\n'] = 0;
   
   while (1)
     {
	if (Point == 0)
	  {
	     if (lut['\n'] == 0) return;
	     if (NULL == (line = CLine->prev)) break;
	     Point = line->len - 1;
             n++;
	  }
	
	CLine = line;
	
	p = line->data + (Point - 1);
	
	while (p >= line->data)
	  {
	     if (0 == lut[*p])
	       {
		  Point = 1 + (int)(p - line->data);
                  LineNum -= n;
		  return;
	       }
	     
	     p--;
	  }
	Point = 0;
     }
   bob();
}

void skip_chars (char *range)
{
   if (*range == '^') skip_chars1(range + 1, 1);
   else
     {
	if (*range == '\\') range++;
	skip_chars1(range, 0);
     }
}

void bskip_chars (char *range)
{
   if (*range == '^') bskip_chars1(range + 1, 1);
   else
     {
	if (*range == '\\') range++;
	bskip_chars1(range, 0);
     }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.