// define the line below for a trivial test program
// otherwise this is "extern int ecinner(char *data, char *commands);"
//#define DEBUG_MAIN
// how to build: cc -c -O1 ecinner.c
// -rw-r--r-- 1 gtoal users 17496 2004-11-02 22:52 ecinner.o
// TO DO: make sure ';'s work so that you can issue % command,
// eg:
// ecinner(test, "%l;(c0m)0"); // force all text to lower case.
//static char *version = "Ecinner V2.7 in C Tue Nov 02 21:36:51 GMT 2004";
/* See http://en.wikipedia.org/wiki/Buffer_gap for the data structure */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/**************************************************/
/* */
/* */
/* E C C E */
/* */
/* */
/* ECCE was designed by Hamish Dewar, now */
/* retired. This implementation is by */
/* Graham Toal, of Edinburgh Software Products. */
/* */
/* This source is released into the public domain */
/* by the author, without restriction. */
/* (c) Graham Toal, 1984. (BCPL version) */
/* (c) Graham Toal, 2004. (C version) */
/**************************************************/
/**************************************************************************/
#ifndef NULL
#define NULL 0
#endif
#define INVALID_PTR NULL
char ecce_err[256]; // Externally visible
#define FALSE (0!=0)
#define TRUE (0==0)
#define ISLOWER(c) ('a'<=(c)&&(c)<='z')
#define TOUPPER(c) (ISLOWER(c)?(c)-'a'+'A':(c))
/* Types */
typedef int bool;
typedef char *cindex;
/* Consts */
#define nl '\n'
#define bs 8
#define bell 7
#define nul 0
#define del 127
#define casebit ('a'-'A')
#define minusbit casebit
#define plusbit 0x80
#define Max_command_units 127
#define rep 1
#define txt 2
#define scope 4
#define sign 8
#define delim 16
#define numb 32
#define ext 64
#define err 128
#define dig 0
#define pc 1
#define lpar 2
#define comma 3
#define rpar 4
#define plus 5
#define minus 6
#define pling 7
#define star 8
#define termin 15
int init_globals (void);
void free_buffers (void);
static int local_echo (char *commands, int *sym);
static int read_sym (char *commands);
static bool fail_with (char *mess, char culprit);
int percent (char Command_sym);
static void unchain(void);
static void stack(void);
static void execute_command(void);
static void Scan_sign(char *commands); /* Could be a macro */
static void Scan_scope(char *commands); /* ditto macro */
static void Scan_text(char *commands);
static void Scan_repeat (char *commands);
static bool analyse (char *command);
static void load_file (char *data);
static bool execute_unit (void);
static void execute_all (void);
static char case_op (char sym);
static bool right (void);
static bool left (void);
static void move_forward (void);
static void move_back(void);
static void move_star (void);
static void move_back_star (void);
static void insert (void);
static void insert_back (void);
static bool verify(void);
static bool verify_back (void);
static bool find (void);
static bool find_back (void);
/* Global variables */
static bool ok;
static bool printed;
static long stopper;
static int max_unit = -1;
static char pending_sym;
extern cindex fbeg;
extern cindex lbeg;
extern cindex pp;
extern cindex fp;
extern cindex lend;
extern cindex fend;
static int type;
static char command;
static long repeat_count;
static long limit;
static int pointer;
static int last_unit;
static int this_unit;
static int pos;
static int endpos;
static int sym;
static long number;
static cindex pp_before;
static cindex fp_before;
static cindex ms = INVALID_PTR;
static cindex ms_back = INVALID_PTR;
static cindex ml;
static cindex ml_back;
static int to_upper_case;
static int to_lower_case;
static int caseflip;
static unsigned char sym_type[] = { /* 0:255 */
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
ext+termin, /*NL*/
err, /* */
ext+numb+7, /*!*/
delim, /*"*/
err, /*#*/
err, /*$*/
ext+1, /*%*/
err, /*&*/
delim, /*'*/
ext+2, /*(*/
ext+4, /*)*/
ext+numb+8, /***/
ext+5, /*+*/
ext+3, /*,*/
ext+6, /*-*/
delim, /*.*/
delim, /*slash*/
ext+numb+0, /*0*/
ext+numb+0, /*1*/
ext+numb+0, /*2*/
ext+numb+0, /*3*/
ext+numb+0, /*4*/
ext+numb+0, /*5*/
ext+numb+0, /*6*/
ext+numb+0, /*7*/
ext+numb+0, /*8*/
ext+numb+0, /*9*/
delim, /*:*/
ext+15, /*;*/
ext+2, /*<*/
delim, /*=*/
ext+4, /*>*/
0, /*?*/
err, /*@*/
err, /*A*/
sign+rep, /*B*/
sign+rep, /*C*/
sign+scope+txt+rep, /*D*/
sign+rep, /*E*/
sign+scope+txt+rep, /*F*/
err, /*G*/
scope, /*H*/
sign+txt+rep, /*I*/
sign+rep, /*J*/
sign+rep, /*K*/
sign+rep, /*L*/
sign+rep, /*M*/
err, /*N*/
err, /*O*/
err, /*P*/
err, /*Q*/
sign+rep, /*R*/
sign+txt, /*S*/
sign+scope+txt+rep, /*T*/
sign+scope+txt+rep, /*U*/
sign+txt, /*V*/
err, /*W*/
err, /*X*/
err, /*Y*/
err, /*Z*/
ext+2, /*[*/
0, /*\*/
ext+4, /*]*/
ext+6, /*^*/
delim, /*_*/
err, /*@*/
err, /*A*/
sign+rep, /*B*/
sign+rep, /*C*/
sign+scope+txt+rep, /*D*/
sign+rep, /*E*/
sign+scope+txt+rep, /*F*/
err, /*G*/
err, /*H*/
sign+txt+rep, /*I*/
sign+rep, /*J*/
sign+rep, /*K*/
sign+rep, /*L*/
sign+rep, /*M*/
err, /*N*/
err, /*O*/
err, /*P*/
err, /*Q*/
sign+rep, /*R*/
sign+txt, /*S*/
sign+scope+txt+rep, /*T*/
sign+scope+txt+rep, /*U*/
sign+txt, /*V*/
err, /*W*/
err, /*X*/
err, /*Y*/
err, /*Z*/
ext+2, /*[*/
0, /*\*/
ext+4, /*]*/
ext+6, /*^*/
delim /*_*/
/* May change some of these to delim at users discretion */
, err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err, err
};
/* Objects off heap */
extern cindex a;
static char *com;
static int *link;
static char *text;
static long *num;
static long *lim;
/*****************************************************************************/
static int delay;
static char *commandp;
int ecinner(char *commands) {
// current bugs - does not handle ';' correctly
commandp = commands;
delay = 0;
ecce_err[0] = '\0';
//ms = INVALID_PTR;
//ms_back = INVALID_PTR;
//max_unit = -1;
//pending_sym = nl;
stopper = -(fend-fbeg); /* Buffer size */
// Have some work to do to return failures cleanly.
if (analyse (commands)) execute_all (); else {
}
return(TRUE);
}
int init_globals (void) {
com = malloc (Max_command_units+1); /* char */
link = (int *) malloc ((Max_command_units+1)*sizeof(int)); /* cindex 0..Max_command_units */
text = malloc (Max_command_units+1); /* cindex 0..Max_command_units */
num = (long *) malloc ((Max_command_units+1)*sizeof(long));
lim = (long *) malloc ((Max_command_units+1)*sizeof(long));
if (com == NULL || link == NULL || text == NULL || num == NULL || lim == NULL) {
sprintf (ecce_err, "Unable to claim buffer space\n"); // return via err code instead?
free_buffers();
return(FALSE);
}
return(TRUE);
}
void free_buffers (void) {
if (lim) free (lim); lim = NULL;
if (num) free (num); num = NULL;
if (text) free (text); text = NULL;
if (link) free (link); link = NULL;
if (com) free (com); com = NULL;
}
static int local_echo (char *commands, int *sym) { /* Later, make this a char fn. */
int lsym;
lsym = *commandp++;
if (lsym == '\0') { // NOTE: would be nice not to rely on this! need ";" or \n after %C
commandp -= 1; // or = NULL?
if (delay == 0) {
delay = 1;
*sym = nl;
return(TRUE);
}
*sym = nl;
return(FALSE); // or signal to jump out to ecinner?
}
*sym = lsym;
return(TRUE);
}
static int read_sym (char *commands) {
if (pending_sym == 0) {
do {
if (!local_echo (commands, &sym)) return(FALSE);
} while (sym == ' ');
/* Better test wanted for noise. perhaps symtype[sym] == symtype[' ']??? */
} else {
sym = pending_sym; /* C has an ungetc() but not very standard... */
pending_sym = 0;
}
return(TRUE);
}
static bool fail_with (char *mess, char culprit) {
int dirn_sign;
if (('a' <= culprit) && (culprit <= 'z')) {
dirn_sign = '-';
} else {
if ((culprit & plusbit) != 0) {
dirn_sign = '+'; // this was for an extension I never implemented, eg g+3 goes to abs line 3
} else {
dirn_sign = ' ';
}
}
culprit = culprit & (~plusbit);
if (('A' <= culprit) && (culprit <= 'Z'))
culprit = culprit | casebit;
sprintf (ecce_err, "* %s %c%c\n", mess, culprit, dirn_sign); // remove?
//fprintf(stderr, "%s\n", ecce_err);sleep(4);
do {
if (!read_sym (NULL)) {ok = TRUE; return(FALSE);}
} while (sym_type[sym] != sym_type[';']);
return (ok = FALSE);
}
static int read_item(char *commands) {
int saved_digit;
if (!read_sym (commands)) return(FALSE);
if (('a' <= sym) && (sym <= 'z'))
sym = sym - casebit;
type = sym_type[sym];
if ((type & ext) == 0) return;
switch (type & 15) {
case star:
number = 0L;
return(TRUE);
case pling:
number = stopper-1;
return(TRUE);
case dig:
saved_digit = sym;
number = 0L;
do {
number = (number * 10) + (sym - '0');
if (!read_sym (commands)) return(FALSE);
} while (('0' <= sym) && (sym <= '9'));
pending_sym = sym;
sym = saved_digit; /* for printing in errors */
return(TRUE);
default:
return(TRUE);
}
}
int percent (char Command_sym) {
cindex P;
int p;
ok = TRUE;
if (!(('a' <= (Command_sym | casebit)) && ((Command_sym | casebit) <= 'z'))) {
(void) fail_with ("letter for", '%');
return(TRUE);
}
switch (Command_sym) {
case 'L':
to_upper_case = ~0;
to_lower_case = casebit;
/* to_lower_case = 0; ---- standard ecce */
caseflip = 0;
break;
case 'U':
to_upper_case = ~casebit;
to_lower_case = 0;
/* to_lower_case = casebit; ---- standard ecce */
caseflip = 0;
break;
case 'N':
to_upper_case = ~0;
to_lower_case = 0;
caseflip = casebit;
break;
case 'E':
to_upper_case = ~casebit; /* Only for searches - not in C command */
to_lower_case = 0;
caseflip = casebit;
break;
case 'W':
case 'C': // %C was explicitly typed, %c was implicit
// is the line below still appropriate? I want ';' to be equivalent to newline
// do { read_sym (); } while (sym_type[sym] != sym_type[';']);
case 'c':
#ifdef NOT_IMP
{
char *datap;
datap = result_buffer;
P = fbeg;
for (;;) {
if (P == pp) P = fp;
if (P == fend) break;
*datap++ = *P++;
}
*datap = '\0';
result_buffer = NULL;
}
if (Command_sym == 'W') {
pending_sym = nl;
break;
}
free_buffers ();
#endif
ok = FALSE;
(void) fail_with ("Not re-implemented yet", Command_sym);
return(TRUE);
default:
(void) fail_with ("Percent", Command_sym);
}
do {
if (!read_sym (NULL)) return(FALSE);
} while (sym_type[sym] != sym_type[';']);
return(TRUE);
}
static void unchain(void) {
do {
pointer = last_unit;
if (pointer < 0) return;
last_unit = link[pointer];
link[pointer] = this_unit;
} while (com[pointer] != '(');
}
static void stack(void) {
com[this_unit] = command;
link[this_unit] = pointer;
num[this_unit] = repeat_count;
lim[this_unit] = limit;
this_unit++;
}
#define right_star() while (fp != lend) *pp++ = *fp++
#define left_star() while (pp != lbeg) *--fp = *--pp
static void execute_command(void) {
cindex i;
int sym;
ok = TRUE;
switch (command & (~plusbit)) {
case 'E':
if (fp == lend) {
ok = FALSE;
return;
}
if (repeat_count == 0L) {
fp = lend;
ok = FALSE;
} else fp++;
return;
case 'e':
if (pp == lbeg) {
ok = FALSE;
return;
}
if (repeat_count == 0L) {
pp = lbeg;
ok = FALSE;
} else --pp;
return;
case 'C':
if (fp == lend) {
ok = FALSE;
return;
}
sym = *fp++;
if (('a' <= (sym | casebit)) && ((sym | casebit) <= 'z')) {
if (caseflip != 0) {
*pp++ = sym ^ casebit;
} else {
*pp++ = ((sym ^ casebit) | to_lower_case) & to_upper_case;
}
} else {
*pp++ = sym;
}
return;
case 'c':
if (pp == lbeg) {
ok = FALSE;
return;
}
sym = *--pp;
if (('a' <= (sym | casebit)) && ((sym | casebit) <= 'z')) {
if (caseflip != 0) {
*--fp = sym ^ casebit;
} else {
*--fp = ((sym ^ casebit) | to_lower_case) & to_upper_case;
}
} else {
*--fp = sym;
}
return;
case 'l':
case 'R':
if (repeat_count == 0L) {
right_star();
ok = FALSE;
} else (void) right ();
ms_back = INVALID_PTR;
return;
case 'r':
case 'L':
if (repeat_count == 0L) {
left_star();
ok = FALSE;
} else (void) left ();
ms = INVALID_PTR;
return;
case 'B':
*pp++ = nl;
lbeg = pp;
return;
case 'b':
*--fp = nl;
lend = fp;
return;
case 'J':
right_star();
if (fp == fend) {
ok = FALSE;
return;
}
lend = ++fp;
while (*lend != nl)
lend++;
return;
case 'j':
left_star();
if (pp == fbeg) {
ok = FALSE;
return;
}
lbeg = --pp;
do { --lbeg; } while (*lbeg != nl);
lbeg++;
return;
case 'M':
if (repeat_count == 0L) {
move_star();
ok = FALSE;
} else {
move_forward ();
}
return;
case 'm':
if (repeat_count == 0L) {
move_back_star();
ok = FALSE;
} else {
move_back(); left_star(); // Traditional Edinburgh mode...
// at one point I had M- leave the cursor at the RHS of the line...
// which is logically consistent but turned out to be too annoying
}
return;
case 'k':
case 'K':
if ((command & minusbit) != 0) {
move_back();
if (!ok) return;
}
pp = lbeg;
fp = lend;
if (lend == fend) {
ok = FALSE;
return;
}
lend = ++fp ;
while (*lend != nl) lend++;
return;
case 'V':
(void) verify ();
return;
case 'v':
(void) verify_back ();
return;
case 'F':
(void) find ();
return;
case 'f':
(void) find_back ();
return;
case 'U':
if (!find ()) return;
pp = pp_before;
lbeg = pp;
do { --lbeg; } while (*lbeg != nl);
lbeg++;
return;
case 'u':
if (!find_back ()) return;
fp = fp_before;
lend = fp;
while (*lend != nl)
lend++;
return;
case 'D':
if (!find ()) return;
fp = ml;
ms = fp;
return;
case 'd':
if (!find_back ()) return;
pp = ml_back;
ms_back = pp;
return;
case 'T':
if (!find ()) return;
while (fp != ml) *pp++ = *fp++;
return;
case 't':
if (!find_back ()) return;
while (pp != ml_back) *--fp = *--pp;
return;
case 'I':
insert ();
return;
case 'i':
insert_back ();
return;
case 's':
case 'S':
if (fp == ms) {
fp = ml;
} else if (pp == ms_back) {
pp = ml_back;
} else {
ok = FALSE;
return;
}
if ((command & minusbit) != 0) {
insert_back ();
} else {
insert ();
}
return;
case '(':
num[pointer] = repeat_count;
repeat_count = 1L;
return;
case ')':
--(num[this_unit]);
if ((0 != num[this_unit]) && (num[this_unit] != stopper)) {
this_unit = pointer;
}
repeat_count = 1L;
return;
case '\\':
ok = FALSE;
return;
case '?':
return;
case ',':
this_unit = pointer - 1;
return;
default:
(void) fail_with ("Unrecognised command", command);
return;
}
}
static void Scan_sign(char *commands) {
read_sym (commands);
if (sym_type[sym] == sym_type['+']) {
command = command | plusbit;
} else if ((sym_type[sym] == sym_type['-']) &&
(('A' <= command) && (command <= 'Z'))) { // isn't there a flag bit for minusbit (or do I check it later?)
command = command | minusbit;
} else {
pending_sym = sym;
}
}
static void Scan_scope(char *commands) { /* ditto macro */
number = 1L;
if (('D' != (command && (~(minusbit | plusbit)))) &&
((command && (~(minusbit | plusbit))) != 'U')) number = 0L;
read_item (commands);
if ((type & numb) == 0) pending_sym = sym;
limit = number;
}
static void Scan_text(char *commands) {
char last;
read_sym (commands);
last = sym;
if ((sym_type[sym] & delim) == 0) {
pending_sym = sym;
(void) fail_with ("Text for", command);
return;
}
if (('a' <= command) && (command <= 'z')) {
text[endpos] = 0;
for (;;) {
local_echo (commands, &sym);
if (sym == last) break;
if (sym == nl) {
pending_sym = nl;
break;
}
text[--endpos] = sym;
}
pointer = endpos--;
} else {
pointer = pos;
for (;;) {
local_echo (commands, &sym);
if (sym == last) break;
if (sym == nl) {
pending_sym = nl;
break;
}
text[pos++] = sym;
}
text[pos++] = 0;
}
ok = TRUE;
}
static void Scan_repeat (char *commands) {
number = 1L;
read_item (commands);
if ((type & numb) == 0) pending_sym = sym;
repeat_count = number;
}
static bool analyse (char *commands) {
int saved_type;
ok = TRUE;
pos = 0;
endpos = Max_command_units;
this_unit = 0;
last_unit = -1;
do { read_item (commands); } while (type == sym_type[';']);
command = sym;
if (command == '%') {
read_sym (commands);
if (sym_type[sym] == sym_type[';']) {
pending_sym = sym;
sym = 0;
}
percent (((('a' <= sym) && (sym <= 'z')) ? (sym - casebit) : sym ));
return (ok = FALSE); /* to inhibit execution */
}
if ((type & numb) != 0) {
if (max_unit > 0) {
num[max_unit] = number;
} else {
return (ok = FALSE);
}
read_item(commands);
if (type != sym_type[';'])
(void) fail_with ("?", sym);
pending_sym = sym;
return (ok);
}
for (;;) { /* on items */
if ((type & err) != 0) {
return (fail_with ("Command", command));
}
if ((type & delim) != 0) {
return (fail_with ("Command before", command));
}
if ((type & numb) != 0) {
return (fail_with ("Unexpected repetition count", command));
}
limit = 0L;
pointer = 0;
repeat_count = 1L;
if ((type & ext) == 0) {
saved_type = type; /* All this needs a tidy-up */
if ((saved_type & sign) != 0) Scan_sign (commands);
if ((saved_type & scope) != 0) Scan_scope (commands);
if ((saved_type & txt) != 0) Scan_text (commands);
if (!ok) return (ok);
if ((saved_type & rep) != 0) Scan_repeat (commands);
type = saved_type;
} else {
switch (type & 15) {
case termin:
pending_sym = nl; /* for skipping on error */
unchain ();
if (pointer >= 0) {
return (fail_with ("Missing", ')'));
}
max_unit = this_unit;
repeat_count = 1L;
command = ')';
stack ();
command = 0;
stack ();
return (ok);
case lpar:
command = '(';
pointer = last_unit;
last_unit = this_unit;
break;
case comma:
command = ',';
pointer = last_unit;
last_unit = this_unit;
break;
case rpar:
command = ')';
Scan_repeat (commands);
unchain ();
if (pointer < 0) {
return (fail_with ("Missing", '('));
}
num[pointer] = repeat_count;
break;
}
}
stack ();
read_item (commands);
command = sym;
} /* on items */
/* NOT REACHED */
return (ok);
}
static void load_file (char *data) {
cindex p = fbeg;
int sym;
sym = *data++;
while (sym != '\0') {
*p++ = sym;
if (p == fend) {
sprintf (ecce_err, "* File too large!\n"); // try to remove all IO?
percent ('A');
}
sym = *data++;
}
while (p != fbeg) *--fp = *--p;
lend = fp;
while (*lend != nl)
lend++;
}
static bool execute_unit (void) {
char culprit;
command = com[this_unit];
culprit = command;
pointer = link[this_unit];
repeat_count = num[this_unit];
for (;;) { /* On repeats of this_unit */
execute_command ();
--repeat_count;
if (ok) {
if (repeat_count == 0L || repeat_count == stopper) {
return (ok);
}
continue;
}
ok = TRUE;
for (;;) { /* scanning for end of unit (e_g_ ')') */
if (repeat_count < 0L ) {
if (com[this_unit+1] == '\\') {
this_unit++;
return (ok = FALSE);
}
return (ok);
}
if ((com[this_unit+1] == '\\') || (com[this_unit+1] == '?')) {
this_unit++;
return (ok);
}
/* indefinite repetition never fails (although it did till I found the bug!) */
for (;;) { /* scanning for end of sequence */
this_unit++;
command = com[this_unit];
switch (command) {
case '(':
this_unit = link[this_unit];
break; /* Skip over (...) as if it were single command. */
case ',':
return (ok);
case ')': /* Should test for '\\' and '?' following? */
--num[this_unit];
repeat_count = num[this_unit];
/* A bug was fixed here: something got lost in the
translation from BCPL to C -- the line below was
a 'break' which unfortunately broke out of the
enclosing case statement rather than the desired
for-loop! */
/* rely on enclosing for-loop to handle \ and ? correctly! */
goto breaklab;
default: /* Possible bugfix - what happens on missing cases? */;
}
if (com[this_unit] == 0) {/* 0 denotes end of command-line. */
return (fail_with ("Failure:", culprit));
}
} /* end of seq */
breaklab: ;
} /* find () ')' without \ or ? */
} /* executing repeats */
/* NOT REACHED */
return (ok);
}
static void execute_all (void) {
this_unit = 0;
do {
if (!execute_unit()) {
return;
}
this_unit++;
} while (com[this_unit] != 0);
ok = TRUE;
}
char case_op (char sym) { /* should be made a macro */
int chr = sym | casebit;
if (('a' <= chr) && (chr <= 'z')) sym = (sym | to_lower_case)
& to_upper_case;
return (sym);
}
static bool right (void) {
if (fp == lend) {
return (ok = FALSE);
}
*pp++ = *fp++;
return (ok = TRUE);
}
static bool left (void) {
if (pp == lbeg) {
return (ok = FALSE);
}
*--fp = *--pp;
return (ok = TRUE);
}
static void move_forward (void) {
ok = TRUE;
right_star ();
if (fp == fend) {
ok = FALSE;
return;
}
*pp++ = *fp++;
lbeg = pp;
lend = fp;
while (*lend != nl) lend++;
ms_back = INVALID_PTR;
}
static void move_back(void) {
ok = TRUE;
left_star ();
if (pp == fbeg) {
ok = FALSE;
return;
}
*--fp = *--pp;
lend = fp;
lbeg = pp;
do { --lbeg; } while (*lbeg != nl);
lbeg++;
ms = INVALID_PTR;
}
static void move_star (void) {
while (fp != fend) *pp++ = *fp++;
lend = fend;
lbeg = pp;
do { --lbeg; } while (*lbeg != nl);
lbeg++;
ms_back = INVALID_PTR;
}
static void move_back_star (void) {
while (pp != fbeg) *--fp = *--pp;
lbeg = fbeg;
lend = fp;
while (*lend != nl)
lend++;
ms = INVALID_PTR;
}
static void insert (void) {
int p = pointer;
ml_back = pp;
while (text[p] != 0) *pp++ = text[p++];
ms_back = pp;
ms = INVALID_PTR;
}
static void insert_back (void) {
int p = pointer;
ml = fp;
while (text[p] != 0) *--fp = text[p++];
ms = fp;
ms_back = INVALID_PTR;
}
static bool verify (void) {
int x = pointer;
cindex y = fp-1;
char if_sym;
char sym ;
do {
sym = case_op (text[x++]);
if_sym = case_op (*++y);
} while (sym == if_sym);
if (sym != 0) return (ok = FALSE);
ms = fp;
ml = y;
ms_back = INVALID_PTR;
return (ok = TRUE);
}
static bool verify_back (void) {
int x = pointer - 1;
int y = 0;
char if_sym;
char sym;
do {
sym = case_op (text[++x]);
if_sym = case_op (*(pp - ++y));
} while (sym == if_sym);
if (sym != 0) return (ok = FALSE);
ms_back = pp;
ml_back = pp - y + 1;
ms = INVALID_PTR;
return (ok = TRUE);
}
static bool find (void) {
char sym = text[pointer] | casebit; /* Is this a bug? */
/* probably not! */
pp_before = pp;
limit = lim[this_unit];
if (fp == ms) {
if (!(right ())) move_forward ();
}
for (;;) {
if ((*fp | casebit) == sym) {
if (verify ()) return (ok);
}
if (!right ()) {
if (--limit == 0L) break;
move_forward ();
if (!ok) break;
}
}
return (ok = FALSE);
}
static bool find_back (void) {
fp_before = fp;
limit = lim[this_unit];
if (pp == ms_back) {
if (!left ()) move_back ();
}
for (;;) {
if (verify_back ()) return(ok);
if (!left ()) {
if (--limit == 0L) break;
move_back ();
if (!ok) break;
}
}
return (ok = FALSE);
}
#ifdef DEBUG_MAIN
int main(int argc, char **argv)
{
char test[256] = "line 1\nline 2\nline 3\nHello World.\n";
ecinner(test, "(t0/ /i/number /)0"); // semicolon separators don't yet work
fprintf(stdout, "---------------\n%s\n--------------\n", test);
}
#endif