#include "mined.h"
#include <signal.h>
#include <string.h>
void
UP(int u __unused)
{
if (y == 0) {
reverse_scroll();
move_to(x, y);
}
else
move_to(x, y - 1);
}
static const char *help_string=
" Mined (Minix Editor), DragonFly version.\n"
"------------------------+-------------------------------+---------------------\n"
" CURSOR MOTION | EDITING | MISC\n"
" Up | ^N Delete next word | ^L Erase & redraw\n"
" Down cursor keys | ^P Delete prev. word | screen\n"
" Left | ^T Delete to EOL | ^\\ Abort current\n"
" Right +-------------------------------+ operation\n"
" ^A start of line | BLOCKS | Esc repeat last\n"
" ^E end of line | ^@ Set mark | cmd # times\n"
" ^^ screen top | ^K Delete mark <--> cursor | F2 file status\n"
" ^_ screen bottom | ^C Save mark <--> cursor +=====================\n"
" ^F word fwd. | ^Y Insert the contents of | ^X EXIT\n"
" ^B word back | the save file at cursor | ^S run shell\n"
"------------------------+ ^Q Insert the contents of +=====================\n"
" SCREEN MOTION | the save file into new | SEARCH & REPLACE\n"
" Home file top | file | F3 fwd. search\n"
" End file bottom +-------------------------------+ SF3 bck. search\n"
" PgUp page up | FILES | F4 Global replace\n"
" PgD page down | ^G Insert a file at cursor | SF4 Line replace\n"
" ^D rev. scroll | ^V Visit another file +---------------------\n"
" ^U fwd. scroll | ^W Write current file | F1 HELP\n"
" ^] goto line # | |\n"
"------------------------+-------------------------------+---------------------\n"
"Press any key to continue...";
void
HLP(int u __unused)
{
string_print(enter_string);
string_print(help_string);
flush();
getchar();
RD(0);
return;
}
void
ST(int u __unused)
{
raw_mode(OFF);
kill(getpid(), SIGTSTP);
raw_mode(ON);
RD(0);
}
void
DN(int u __unused)
{
if (y == last_y) {
if (bot_line->next == tail && bot_line->text[0] != '\n') {
dummy_line();
DN(0);
return;
}
else {
forward_scroll();
move_to(x, y);
}
}
else
move_to(x, y + 1);
}
void
LF(int u __unused)
{
if (x == 0 && get_shift(cur_line->shift_count) == 0) {
if (cur_line->prev != header) {
UP(0);
move_to(LINE_END, y);
}
}
else
move_to(x - 1, y);
}
void
RT(int u __unused)
{
if (*cur_text == '\n') {
if (cur_line->next != tail) {
DN(0);
move_to(LINE_START, y);
}
}
else
move_to(x + 1, y);
}
void
HIGH(int u __unused)
{
move_to(0, 0);
}
void
LOW(int u __unused)
{
move_to(0, last_y);
}
void
BL(int u __unused)
{
move_to(LINE_START, y);
}
void
EL(int u __unused)
{
move_to(LINE_END, y);
}
void
GOTO(int u __unused)
{
int number;
LINE *line;
if (get_number("Please enter line number.", &number) == ERRORS)
return;
if (number <= 0 || (line = proceed(header->next, number - 1)) == tail)
error("Illegal line number: ", num_out((long) number));
else
move_to(x, find_y(line));
}
void
PD(int u __unused)
{
int i;
for (i = 0; i < screenmax; i++)
if (forward_scroll() == ERRORS)
break;
if (y - i < 0)
move_to(0, screenmax >> 1);
else
move_to(0, y - i);
}
void
PU(int u __unused)
{
int i;
for (i = 0; i < screenmax; i++)
if (reverse_scroll() == ERRORS)
break;
set_cursor(0, ymax);
#ifdef UNIX
tputs(CE, 0, _putchar);
#else
string_print(blank_line);
#endif
if (y + i > screenmax)
move_to(0, screenmax >> 1);
else
move_to(0, y + i);
}
void
HO(int u __unused)
{
if (proceed(top_line, -screenmax) == header)
PU(0);
else {
reset(header->next, 0);
RD(0);
}
move_to(LINE_START, 0);
}
void
EF(int u __unused)
{
if (tail->prev->text[0] != '\n')
dummy_line();
if (proceed(bot_line, screenmax) == tail)
PD(0);
else {
reset(proceed(tail->prev, -screenmax), screenmax);
RD(0);
}
move_to(LINE_START, last_y);
}
void
SU(int u __unused)
{
if (top_line->prev == header)
return;
reverse_scroll();
set_cursor(0, ymax);
#ifdef UNIX
tputs(CE, 0, _putchar);
#else
string_print(blank_line);
#endif
move_to(x, (y == screenmax) ? screenmax : y + 1);
}
void
SD(int u __unused)
{
if (forward_scroll() != ERRORS)
move_to(x, (y == 0) ? 0 : y - 1);
else
set_cursor(x, y);
}
int
forward_scroll(void)
{
if (bot_line->next == tail)
return ERRORS;
top_line = top_line->next;
bot_line = bot_line->next;
cur_line = cur_line->next;
set_cursor(0, ymax);
line_print(bot_line);
return FINE;
}
int
reverse_scroll(void)
{
if (top_line->prev == header)
return ERRORS;
if (last_y != screenmax)
last_y++;
else
bot_line = bot_line->prev;
top_line = top_line->prev;
cur_line = cur_line->prev;
set_cursor(0, 0);
#ifdef UNIX
tputs(AL, 0, _putchar);
#else
string_print(rev_scroll);
#endif
set_cursor(0, 0);
line_print(top_line);
return FINE;
}
void
MP(int u __unused)
{
move_previous_word(NO_DELETE);
}
void
move_previous_word(FLAG remove)
{
char *begin_line;
char *textp;
char start_char = *cur_text;
char *start_pos = cur_text;
if (cur_text == cur_line->text) {
if (cur_line->prev == header)
return;
start_char = '\0';
}
LF(0);
begin_line = cur_line->text;
textp = cur_text;
if (!alpha(*textp) || !alpha(start_char)) {
while (textp != begin_line && (white_space(*textp) || *textp == '\n'))
textp--;
}
while (textp != begin_line && alpha(*textp))
textp--;
if (textp != begin_line && *textp != '\n')
textp++;
move_address(textp);
if (remove == DELETE)
delete(cur_line, textp, cur_line, start_pos);
}
void
MN(int u __unused)
{
move_next_word(NO_DELETE);
}
void
move_next_word(FLAG remove)
{
char *textp = cur_text;
while (*textp != '\n' && alpha(*textp))
textp++;
while (*textp != '\n' && white_space(*textp))
textp++;
if (remove == DELETE) {
delete(cur_line, cur_text, cur_line, textp);
return;
}
if (*textp == '\n' && cur_line->next != tail) {
DN(0);
move_to(LINE_START, y);
textp = cur_text;
while (*textp != '\n' && white_space(*textp))
textp++;
}
move_address(textp);
}
void
DCC(int u __unused)
{
if (*cur_text == '\n')
delete(cur_line,cur_text, cur_line->next,cur_line->next->text);
else
delete(cur_line, cur_text, cur_line, cur_text + 1);
}
void
DPC(int u __unused)
{
if (x == 0 && cur_line->prev == header)
return;
LF(0);
DCC(0);
}
void
DLN(int u __unused)
{
if (*cur_text == '\n')
DCC(0);
else
delete(cur_line, cur_text, cur_line, cur_text + length_of(cur_text) -1);
}
void
DNW(int u __unused)
{
if (*cur_text == '\n')
DCC(0);
else
move_next_word(DELETE);
}
void
DPW(int u __unused)
{
if (cur_text == cur_line->text)
DPC(0);
else
move_previous_word(DELETE);
}
void
S(int character)
{
static char buffer[2];
buffer[0] = character;
if (insert(cur_line, cur_text, buffer) == ERRORS)
return;
if (character == '\n') {
set_cursor(0, y);
if (y == screenmax) {
line_print(cur_line);
forward_scroll();
}
else {
reset(top_line, y);
display(0, y, cur_line, last_y - y);
}
move_to(0, (y == screenmax) ? y : y + 1);
}
else if (x + 1 == XBREAK)
move_to(x + 1, y);
else {
put_line(cur_line, x, FALSE);
move_to(x + 1, y);
}
}
void
CTL(int u __unused)
{
char ctrl;
status_line("Enter control character.", NIL_PTR);
if ((ctrl = getchar()) >= '\01' && ctrl <= '\037') {
S(ctrl);
clear_status();
}
else
error ("Unknown control character", NIL_PTR);
}
void
LIB(int u __unused)
{
S('\n');
UP(0);
move_to(LINE_END, y);
}
LINE *
line_insert(LINE *line, const char *string, int len)
{
LINE *new_line;
new_line = install_line(string, len);
new_line->prev = line;
new_line->next = line->next;
line->next = new_line;
new_line->next->prev = new_line;
nlines++;
return new_line;
}
int
insert(LINE *line, char *location, char *string)
{
char *bufp = text_buffer;
char *textp = line->text;
if (length_of(textp) + length_of(string) >= MAX_CHARS) {
error("Line too long", NIL_PTR);
return ERRORS;
}
modified = TRUE;
while (textp != location)
*bufp++ = *textp++;
while (*string != '\0')
*bufp++ = *string++;
*bufp = '\0';
if (*(string - 1) == '\n')
line_insert(line, location, length_of(location));
else
copy_string(bufp, location);
free_space(line->text);
line->text = alloc(length_of(text_buffer) + 1);
copy_string(line->text, text_buffer);
return FINE;
}
LINE *
line_delete(LINE *line)
{
LINE *next_line = line->next;
line->prev->next = line->next;
line->next->prev = line->prev;
free_space(line->text);
free_space((char*)line);
nlines--;
return next_line;
}
void
delete(LINE *start_line, char *start_textp,
LINE *end_line, char *end_textp)
{
char *textp = start_line->text;
char *bufp = text_buffer;
LINE *line, *stop;
int line_cnt = 0;
int count = 0;
int shift = 0;
int nx = x;
modified = TRUE;
while (textp < start_textp) {
*bufp++ = *textp++;
count++;
}
if (count + length_of(end_textp) >= MAX_CHARS) {
error("Line too long", NIL_PTR);
return;
}
copy_string(bufp, (end_textp != NIL_PTR) ? end_textp : "\n");
line = start_line->next;
stop = end_line->next;
while (line != stop && line != tail) {
line = line_delete(line);
line_cnt++;
}
if (end_textp == NIL_PTR && length_of(start_line->text) == 1 && nlines > 1) {
start_line = start_line->prev;
line_delete(start_line->next);
line_cnt++;
}
else {
free_space(start_line->text);
start_line->text = alloc(length_of(text_buffer) + 1);
copy_string(start_line->text, text_buffer);
}
if (get_shift(start_line->shift_count)) {
shift = (XBREAK - count_chars(start_line)) / SHIFT_SIZE;
if (shift > 0) {
if (shift >= get_shift(start_line->shift_count))
start_line->shift_count = 0;
else
start_line->shift_count -= shift;
nx += shift * SHIFT_SIZE;
}
}
if (line_cnt == 0) {
if (shift > 0) {
set_cursor(0, y);
line_print(start_line);
}
else {
set_cursor(x, y);
put_line(start_line, x, TRUE);
}
move_to(nx, y);
return;
}
shift = last_y;
reset(top_line, y);
display(0, y, start_line, shift - y);
move_to((line_cnt == 1) ? nx : 0, y);
}
LINE *mark_line;
char *mark_text;
int lines_saved;
void
PT(int u __unused)
{
int fd;
if ((fd = scratch_file(READ)) == ERRORS)
error("Buffer is empty.", NIL_PTR);
else {
file_insert(fd, FALSE);
close(fd);
}
}
void
IF(int u __unused)
{
int fd;
char name[LINE_LEN];
if (get_file("Get and insert file:", name) != FINE)
return;
if ((fd = open(name, 0)) < 0)
error("Cannot open ", name);
else {
file_insert(fd, TRUE);
close(fd);
}
}
void
file_insert(int fd, FLAG old_pos)
{
char line_buffer[MAX_CHARS];
LINE *line = cur_line;
int line_count = nlines;
LINE *page = cur_line;
int ret = ERRORS;
if (get_line(fd, line_buffer) == ERRORS)
return;
if (insert(line, cur_text, line_buffer) == ERRORS)
return;
while ((ret = get_line(fd, line_buffer)) != ERRORS && ret != NO_LINE)
line = line_insert(line, line_buffer, ret);
if (ret == NO_LINE) {
line = line->next;
insert(line, line->text, line_buffer);
}
line_count = nlines - line_count;
if (line_count == 0) {
set_cursor(0, y);
line_print(line);
move_to((old_pos == TRUE) ? x : x + length_of(line_buffer), y);
}
else {
reset(top_line, y);
while (page != line && page != bot_line->next)
page = page->next;
if (page != bot_line->next || old_pos == TRUE)
display(0, y, cur_line, screenmax - y);
if (old_pos == TRUE)
move_to(x, y);
else if (ret == NO_LINE)
move_to(length_of(line_buffer), find_y(line));
else
move_to(0, find_y(line->next));
}
if (line_count >= REPORT)
status_line(num_out((long) line_count), " lines added.");
}
void
WB(int u __unused)
{
int new_fd;
int yank_fd;
int cnt;
int ret = 0;
char file[LINE_LEN];
if ((yank_fd = scratch_file(READ)) == ERRORS) {
error("Buffer is empty.", NIL_PTR);
return;
}
if (get_file("Write buffer to file:", file) != FINE)
return;
if ((new_fd = creat(file, 0644)) < 0) {
error("Cannot create ", file);
return;
}
status_line("Writing ", file);
while ((cnt = read(yank_fd, text_buffer, sizeof(text_buffer))) > 0)
if (write(new_fd, text_buffer, cnt) != cnt) {
bad_write(new_fd);
ret = ERRORS;
break;
}
close(new_fd);
close(yank_fd);
if (ret != ERRORS)
file_status("Wrote", chars_saved, file, lines_saved, TRUE, FALSE);
}
void
MA(int u __unused)
{
mark_line = cur_line;
mark_text = cur_text;
status_line("Mark set", NIL_PTR);
}
void
YA(int u __unused)
{
set_up(NO_DELETE);
}
void
DT(int u __unused)
{
set_up(DELETE);
}
void
set_up(FLAG remove)
{
switch (checkmark()) {
case NOT_VALID :
error("Mark not set.", NIL_PTR);
return;
case SMALLER :
yank(mark_line, mark_text, cur_line, cur_text, remove);
break;
case BIGGER :
yank(cur_line, cur_text, mark_line, mark_text, remove);
break;
case SAME :
yank_status = EMPTY;
chars_saved = 0L;
status_line("0 characters saved in buffer.", NIL_PTR);
break;
}
}
FLAG
checkmark(void)
{
LINE *line;
FLAG cur_seen = FALSE;
if (mark_line == cur_line) {
if (mark_text == cur_text)
return SAME;
if (legal() == ERRORS)
return NOT_VALID;
return (mark_text < cur_text) ? SMALLER : BIGGER;
}
for (line = header->next; line != tail; line = line->next) {
if (line == cur_line)
cur_seen = TRUE;
else if (line == mark_line)
break;
}
if (line == tail || legal() == ERRORS)
return NOT_VALID;
return (cur_seen == TRUE) ? BIGGER : SMALLER;
}
int
legal(void)
{
char *textp = mark_line->text;
while (textp != mark_text && *textp++ != '\0')
;
return (*textp == '\0') ? ERRORS : FINE;
}
void
yank(LINE *start_line, char *start_textp, LINE *end_line, char *end_textp,
FLAG remove)
{
LINE *line = start_line;
char *textp = start_textp;
int fd;
if ((fd = scratch_file(WRITE)) == ERRORS)
return;
chars_saved = 0L;
lines_saved = 0;
status_line("Saving text.", NIL_PTR);
while (textp != end_textp) {
if (write_char(fd, *textp) == ERRORS) {
close(fd);
return;
}
if (*textp++ == '\n') {
line = line->next;
textp = line->text;
lines_saved++;
}
chars_saved++;
}
if (flush_buffer(fd) == ERRORS) {
close(fd);
return;
}
close(fd);
yank_status = VALID;
if (remove == DELETE) {
move_to(find_x(start_line, start_textp), find_y(start_line));
delete(start_line, start_textp, end_line, end_textp);
}
status_line(num_out(chars_saved), " characters saved in buffer.");
}
#define MAXTRAILS 26
int
scratch_file(FLAG mode)
{
static int trials = 0;
char *y_ptr, *n_ptr;
int fd = ERRORS;
if (yank_status == NOT_VALID && mode == WRITE) {
y_ptr = &yank_file[11];
n_ptr = num_out((long) getpid());
while ((*y_ptr = *n_ptr++) != '\0')
y_ptr++;
*y_ptr++ = 'a' + trials;
*y_ptr = '\0';
if (access(yank_file, 0) == 0 || (fd = creat(yank_file, 0644)) < 0) {
if (trials++ >= MAXTRAILS) {
error("Unable to creat scratchfile.", NIL_PTR);
return ERRORS;
}
else
return scratch_file(mode);
}
}
else if ((mode == READ && (fd = open(yank_file, 0)) < 0) ||
(mode == WRITE && (fd = creat(yank_file, 0644)) < 0)) {
yank_status = NOT_VALID;
return ERRORS;
}
clear_buffer();
return fd;
}
char typed_expression[LINE_LEN];
void
SF(int u __unused)
{
search("Search forward:", FORWARD);
}
void
SR(int u __unused)
{
search("Search reverse:", REVERSE);
}
REGEX *
get_expression(const char *message)
{
static REGEX program;
char exp_buf[LINE_LEN];
if (get_string(message, exp_buf, FALSE) == ERRORS)
return NIL_REG;
if (exp_buf[0] == '\0' && typed_expression[0] == '\0') {
error("No previous expression.", NIL_PTR);
return NIL_REG;
}
if (exp_buf[0] != '\0') {
copy_string(typed_expression, exp_buf);
compile(exp_buf, &program);
}
if (program.status == REG_ERROR) {
error(program.result.err_mess, NIL_PTR);
return NIL_REG;
}
return &program;
}
void
GR(int u __unused)
{
change("Global replace:", VALID);
}
void
LR(int u __unused)
{
change("Line replace:", NOT_VALID);
}
void
change(const char *message, FLAG file)
{
char mess_buf[LINE_LEN];
char replacement[LINE_LEN];
REGEX *program;
LINE *line = cur_line;
char *textp;
long lines = 0L;
long subs = 0L;
int page = y;
copy_string(mess_buf, message);
if ((program = get_expression(mess_buf)) == NIL_REG)
return;
build_string(mess_buf, "%s %s by:", mess_buf, typed_expression);
if (get_string(mess_buf, replacement, FALSE) == ERRORS)
return;
set_cursor(0, ymax);
flush();
do {
if (line_check(program, line->text, FORWARD)) {
lines++;
do {
subs++;
if ((textp = substitute(line, program,replacement))
== NIL_PTR)
return;
} while ((program->status & BEGIN_LINE) != BEGIN_LINE &&
(program->status & END_LINE) != END_LINE &&
line_check(program, textp, FORWARD));
if (page <= screenmax) {
set_cursor(0, page);
line_print(line);
}
}
if (page <= screenmax)
page++;
line = line->next;
} while (line != tail && file == VALID && quit == FALSE);
copy_string(mess_buf, (quit == TRUE) ? "(Aborted) " : "");
if (subs == 0L && quit == FALSE)
error("Pattern not found.", NIL_PTR);
else if (lines >= REPORT || quit == TRUE) {
build_string(mess_buf, "%s %D substitutions on %D lines.", mess_buf,
subs, lines);
status_line(mess_buf, NIL_PTR);
}
else if (file == NOT_VALID && subs >= REPORT)
status_line(num_out(subs), " substitutions.");
else
clear_status();
move_to (x, y);
}
char *
substitute(LINE *line, REGEX *program, char *replacement)
{
char *textp = text_buffer;
char *subp = replacement;
char *linep = line->text;
char *amp;
modified = TRUE;
while (linep != program->start_ptr)
*textp++ = *linep++;
while (*subp != '\0' && textp < &text_buffer[MAX_CHARS]) {
if (*subp == '&') {
amp = program->start_ptr;
while (amp < program->end_ptr && textp<&text_buffer[MAX_CHARS])
*textp++ = *amp++;
subp++;
}
else {
if (*subp == '\\' && *(subp + 1) != '\0')
subp++;
*textp++ = *subp++;
}
}
if (length_of(text_buffer) + length_of(program->end_ptr) >= MAX_CHARS) {
error("Substitution result: line too big", NIL_PTR);
return NIL_PTR;
}
copy_string(textp, program->end_ptr);
free_space(line->text);
line->text = alloc(length_of(text_buffer) + 1);
copy_string(line->text, text_buffer);
return(line->text + (textp - text_buffer));
}
void
search(const char *message, FLAG method)
{
REGEX *program;
LINE *match_line;
if ((program = get_expression(message)) == NIL_REG)
return;
set_cursor(0, ymax);
flush();
if ((match_line = match(program, cur_text, method)) == NIL_LINE) {
if (quit == TRUE)
status_line("Aborted", NIL_PTR);
else
status_line("Pattern not found.", NIL_PTR);
return;
}
move(0, program->start_ptr, find_y(match_line));
clear_status();
}
int
find_y(LINE *match_line)
{
LINE *line;
int count = 0;
for (line = top_line; line != match_line && line != bot_line->next;
line = line->next)
count++;
if (line != bot_line->next)
return count;
if ((line = proceed(match_line, -(screenmax >> 1))) == header) {
count = 0;
for (line = header->next; line != match_line; line = line->next)
count++;
line = header->next;
}
else
count = screenmax >> 1;
reset(line, 0);
RD(0);
return count;
}
#define NORMAL 0x0200
#define DOT 0x0400
#define EOLN 0x0800
#define STAR 0x1000
#define BRACKET 0x2000
#define NEGATE 0x0100
#define DONE 0x4000
#define LOW_BYTE 0x00FF
#define HIGH_BYTE 0xFF00
#define previous(ptr) (*((ptr) - 1))
int exp_buffer[BLOCK_SIZE];
static const char *too_long = "Regular expression too long";
#define reg_error(str) program->status = REG_ERROR, \
program->result.err_mess = (str)
void
finished(REGEX *program, int *last_exp)
{
int length = (last_exp - exp_buffer) * sizeof(int);
program->result.expression = (int *) alloc(length);
bcopy(exp_buffer, program->result.expression, length);
}
void
compile(char *pattern, REGEX *program)
{
int *expression = exp_buffer;
int *prev_char;
int *acct_field = NULL;
FLAG negate;
char low_char;
char c;
if (*pattern == '^') {
program->status = BEGIN_LINE;
pattern++;
}
else {
program->status = 0;
if (*pattern == '*') {
*expression++ = '*' + NORMAL;
pattern++;
}
}
for (; ;) {
switch (c = *pattern++) {
case '.' :
*expression++ = DOT;
break;
case '$' :
if (*pattern == '\0') {
*expression++ = EOLN | DONE;
program->status |= END_LINE;
finished(program, expression);
return;
}
else
*expression++ = NORMAL + '$';
break;
case '\0' :
*expression++ = DONE;
finished(program, expression);
return;
case '\\' :
if (*pattern == '\0')
*expression++ = NORMAL + '\\';
else
*expression++ = NORMAL + *pattern++;
break;
case '*' :
prev_char = expression - 1;
if (*prev_char & BRACKET)
*(expression - (*acct_field & LOW_BYTE))|= STAR;
else
*prev_char |= STAR;
break;
case '[' :
acct_field = expression++;
if (*pattern == '^') {
pattern++;
negate = TRUE;
}
else
negate = FALSE;
while (*pattern != ']') {
if (*pattern == '\0') {
reg_error("Missing ]");
return;
}
if (*pattern == '\\')
pattern++;
*expression++ = *pattern++;
if (*pattern == '-') {
low_char = previous(pattern);
pattern++;
if (low_char++ > *pattern) {
reg_error("Bad range in [a-z]");
return;
}
while (low_char <= *pattern)
*expression++ = low_char++;
pattern++;
}
if (expression >= &exp_buffer[BLOCK_SIZE]) {
reg_error(too_long);
return;
}
}
pattern++;
if ((*acct_field = (expression - acct_field)) == 1) {
reg_error("Empty []");
return;
}
*acct_field |= BRACKET;
if (negate == TRUE)
*acct_field |= NEGATE;
previous(expression) |= BRACKET;
break;
default :
*expression++ = c + NORMAL;
}
if (expression == &exp_buffer[BLOCK_SIZE]) {
reg_error(too_long);
return;
}
}
}
LINE *
match(REGEX *program, char *string, FLAG method)
{
LINE *line = cur_line;
char old_char;
if (program->status == REG_ERROR)
return NIL_LINE;
if (!(program->status & BEGIN_LINE)) {
if (method == FORWARD) {
if (line_check(program, string + 1, method) == MATCH)
return cur_line;
}
else if (!(program->status & END_LINE)) {
old_char = *string;
*string = '\n';
if (line_check(program, line->text, method) == MATCH) {
*string = old_char;
return cur_line;
}
*string = old_char;
}
}
do {
line = (method == FORWARD) ? line->next : line->prev;
if (line->text == NIL_PTR)
continue;
if (line_check(program, line->text, method) == MATCH)
return line;
} while (line != cur_line && quit == FALSE);
return NIL_LINE;
}
int
line_check(REGEX *program, char *string, FLAG method)
{
char *textp = string;
program->start_ptr = textp;
if (program->status & BEGIN_LINE)
return check_string(program, string, NIL_INT);
if (method == REVERSE) {
for (textp = string; *textp != '\n'; textp++)
;
while (textp >= string) {
program->start_ptr = textp;
if (check_string(program, textp--, NIL_INT))
return MATCH;
}
}
else {
while (quit == FALSE && *textp != '\0') {
program->start_ptr = textp;
if (check_string(program, textp, NIL_INT))
return MATCH;
if (*textp == '\n')
break;
textp++;
}
}
return NO_MATCH;
}
int
check_string(REGEX *program, char *string, int *expression)
{
int opcode;
char c;
char *mark = NULL;
int star_fl;
if (expression == NIL_INT)
expression = program->result.expression;
while (quit == FALSE && !(*expression & DONE) &&
*string != '\0' && *string != '\n') {
c = *expression & LOW_BYTE;
opcode = *expression & HIGH_BYTE;
if ((star_fl = (opcode & STAR)) != 0) {
opcode &= ~STAR;
mark = string;
}
expression++;
switch (opcode) {
case NORMAL :
if (star_fl)
while (*string++ == c)
;
else if (*string++ != c)
return NO_MATCH;
break;
case DOT :
string++;
if (star_fl)
while (*string != '\0' && *string++ != '\n')
;
break;
case NEGATE | BRACKET:
case BRACKET :
if (star_fl)
while (in_list(expression, *string++, c, opcode)
== MATCH)
;
else if (in_list(expression, *string++, c, opcode) == NO_MATCH)
return NO_MATCH;
expression += c - 1;
break;
default :
panic("Corrupted program in check_string()");
}
if (star_fl)
return star(program, mark, string, expression);
}
if (*expression & DONE) {
program->end_ptr = string;
if ((*expression & EOLN) && *string != '\n' && *string != '\0')
return NO_MATCH;
if (string == program->start_ptr && !(program->status & BEGIN_LINE)
&& !(*expression & EOLN))
return NO_MATCH;
return MATCH;
}
return NO_MATCH;
}
int
star(REGEX *program, char *end_position, char *string, int *expression)
{
do {
string--;
if (check_string(program, string, expression))
return MATCH;
} while (string != end_position);
return NO_MATCH;
}
int
in_list(int *list, char c, int list_length, int opcode)
{
if (c == '\0' || c == '\n')
return NO_MATCH;
while (list_length-- > 1) {
if ((*list & LOW_BYTE) == c)
return (opcode & NEGATE) ? NO_MATCH : MATCH;
list++;
}
return (opcode & NEGATE) ? MATCH : NO_MATCH;
}
void
dummy_line(void)
{
line_insert(tail->prev, "\n", 1);
tail->prev->shift_count = DUMMY;
if (last_y != screenmax) {
last_y++;
bot_line = bot_line->next;
}
}