// 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