📄 mined2.c
字号:
do { subs++; /* Increment subs */ if ((textp = substitute(line, program,replacement)) == NIL_PTR) return; /* Line too long */ } while ((program->status & BEGIN_LINE) != BEGIN_LINE && (program->status & END_LINE) != END_LINE && line_check(program, textp, FORWARD)); /* Check to see if we can print the result */ 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) " : "");/* Fix the status line */ 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);}/* * Substitute() replaces the match on this line by the substitute pattern * as indicated by the program. Every '&' in the replacement is replaced by * the original match. A \ in the replacement escapes the next character. */char *substitute(line, program, replacement)LINE *line;REGEX *program;char *replacement; /* Contains replacement pattern */{ register char *textp = text_buffer; register char *subp = replacement; char *linep = line->text; char *amp; modified = TRUE;/* Copy part of line until the beginning of the match */ while (linep != program->start_ptr) *textp++ = *linep++; /* * Replace the match by the substitution pattern. Each occurrence of '&' is * replaced by the original match. A \ escapes the next character. */ while (*subp != '\0' && textp < &text_buffer[MAX_CHARS]) { if (*subp == '&') { /* Replace the original match */ 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++; } }/* Check for line length not exceeding MAX_CHARS */ if (length_of(text_buffer) + length_of(program->end_ptr) >= MAX_CHARS) { error("Substitution result: line too big", NIL_PTR); return NIL_PTR; }/* Append last part of line to the new build line */ copy_string(textp, program->end_ptr);/* Free old line and install new one */ free_space(line->text); line->text = alloc(length_of(text_buffer) + 1); copy_string(line->text, text_buffer); return(line->text + (textp - text_buffer));}/* * Search() calls get_expression to fetch the expression. If this went well, * the function match() is called which returns the line with the next match. * If this line is the NIL_LINE, it means that a match could not be found. * Find_x() and find_y() display the right page on the screen, and return * the right coordinates for x and y. These coordinates are passed to move_to() */void search(message, method)char *message;FLAG method;{ register REGEX *program; register LINE *match_line;/* Get the expression */ if ((program = get_expression(message)) == NIL_REG) return; set_cursor(0, ymax); flush();/* Find the match */ 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();}/* * find_y() checks if the matched line is on the current page. If it is, it * returns the new y coordinate, else it displays the correct page with the * matched line in the middle and returns the new y value; */int find_y(match_line)LINE *match_line;{ register LINE *line; register int count = 0;/* Check if match_line is on the same page as currently displayed. */ for (line = top_line; line != match_line && line != bot_line->next; line = line->next) count++; if (line != bot_line->next) return count;/* Display new page, with match_line in center. */ if ((line = proceed(match_line, -(screenmax >> 1))) == header) { /* Can't display in the middle. Make first line of file top_line */ count = 0; for (line = header->next; line != match_line; line = line->next) count++; line = header->next; } else /* New page is displayed. Set cursor to middle of page */ count = screenmax >> 1;/* Reset pointers and redraw the screen */ reset(line, 0); RD(); return count;}/* Opcodes for characters */#define NORMAL 0x0200#define DOT 0x0400#define EOLN 0x0800#define STAR 0x1000#define BRACKET 0x2000#define NEGATE 0x0100#define DONE 0x4000/* Mask for opcodes and characters */#define LOW_BYTE 0x00FF#define HIGH_BYTE 0xFF00/* Previous is the contents of the previous address (ptr) points to */#define previous(ptr) (*((ptr) - 1))/* Buffer to store outcome of compilation */int exp_buffer[BLOCK_SIZE];/* Errors often used */char *too_long = "Regular expression too long";/* * Reg_error() is called by compile() is something went wrong. It set the * status of the structure to error, and assigns the error field of the union. */#define reg_error(str) program->status = REG_ERROR, \ program->result.err_mess = (str)/* * Finished() is called when everything went right during compilation. It * allocates space for the expression, and copies the expression buffer into * this field. */void finished(program, last_exp)register REGEX *program;int *last_exp;{ register int length = (last_exp - exp_buffer) * sizeof(int);/* Allocate space */ program->result.expression = (int *) alloc(length);/* Copy expression. (expression consists of ints!) */ bcopy(exp_buffer, program->result.expression, length);}/* * Compile compiles the pattern into a more comprehensible form and returns a * REGEX structure. If something went wrong, the status field of the structure * is set to REG_ERROR and an error message is set into the err_mess field of * the union. If all went well the expression is saved and the expression * pointer is set to the saved (and compiled) expression. */void compile(pattern, program)register char *pattern; /* Pointer to pattern */REGEX *program;{ register int *expression = exp_buffer; int *prev_char; /* Pointer to previous compiled atom */ int *acct_field; /* Pointer to last BRACKET start */ FLAG negate; /* Negate flag for BRACKET */ char low_char; /* Index for chars in BRACKET */ char c;/* Check for begin of line */ if (*pattern == '^') { program->status = BEGIN_LINE; pattern++; } else { program->status = 0;/* If the first character is a '*' we have to assign it here. */ if (*pattern == '*') { *expression++ = '*' + NORMAL; pattern++; } } for (; ;) { switch (c = *pattern++) { case '.' : *expression++ = DOT; break; case '$' : /* * Only means EOLN if it is the last char of the pattern */ 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 last char, it must! mean a normal '\' */ if (*pattern == '\0') *expression++ = NORMAL + '\\'; else *expression++ = NORMAL + *pattern++; break; case '*' : /* * If the previous expression was a [] find out the * begin of the list, and adjust the opcode. */ prev_char = expression - 1; if (*prev_char & BRACKET) *(expression - (*acct_field & LOW_BYTE))|= STAR; else *prev_char |= STAR; break; case '[' : /* * First field in expression gives information about * the list. * The opcode consists of BRACKET and if necessary * NEGATE to indicate that the list should be negated * and/or STAR to indicate a number of sequence of this * list. * The lower byte contains the length of the list. */ acct_field = expression++; if (*pattern == '^') { /* List must be negated */ pattern++; negate = TRUE; } else negate = FALSE; while (*pattern != ']') { if (*pattern == '\0') { reg_error("Missing ]"); return; } if (*pattern == '\\') pattern++; *expression++ = *pattern++; if (*pattern == '-') { /* Make list of chars */ low_char = previous(pattern); pattern++; /* Skip '-' */ if (low_char++ > *pattern) { reg_error("Bad range in [a-z]"); return; } /* Build list */ while (low_char <= *pattern) *expression++ = low_char++; pattern++; } if (expression >= &exp_buffer[BLOCK_SIZE]) { reg_error(too_long); return; } } pattern++; /* Skip ']' */ /* Assign length of list in acct field */ if ((*acct_field = (expression - acct_field)) == 1) { reg_error("Empty []"); return; } /* Assign negate and bracket field */ *acct_field |= BRACKET; if (negate == TRUE) *acct_field |= NEGATE; /* * Add BRACKET to opcode of last char in field because * a '*' may be following the list. */ previous(expression) |= BRACKET; break; default : *expression++ = c + NORMAL; } if (expression == &exp_buffer[BLOCK_SIZE]) { reg_error(too_long); return; } } /* NOTREACHED */}/* * Match gets as argument the program, pointer to place in current line to * start from and the method to search for (either FORWARD or REVERSE). * Match() will look through the whole file until a match is found. * NIL_LINE is returned if no match could be found. */LINE *match(program, string, method)REGEX *program;char *string;register FLAG method;{ register LINE *line = cur_line; char old_char; /* For saving chars *//* Corrupted program */ if (program->status == REG_ERROR) return NIL_LINE;/* Check part of text first */ if (!(program->status & BEGIN_LINE)) { if (method == FORWARD) { if (line_check(program, string + 1, method) == MATCH) return cur_line; /* Match found */ } else if (!(program->status & END_LINE)) { old_char = *string; /* Save char and */ *string = '\n'; /* Assign '\n' for line_check */ if (line_check(program, line->text, method) == MATCH) { *string = old_char; /* Restore char */ return cur_line; /* Found match */ } *string = old_char; /* No match, but restore char */ } }/* No match in last (or first) part of line. Check out rest of file */ do { line = (method == FORWARD) ? line->next : line->prev; if (line->text == NIL_PTR) /* Header/tail */ continue; if (line_check(program, line->text, method) == MATCH) return line; } while (line != cur_line && quit == FALSE);/* No match found. */ return NIL_LINE;}/* * Line_check() checks the line (or rather string) for a match. Method * indicates FORWARD or REVERSE search. It scans through the whole string * until a match is found, or the end of the string is reached. */int line_check(program, string, method)register REGEX *program;char *string;FLAG method;{ register char *textp = string;/* Assign start_ptr field. We might find a match right away! */ program->start_ptr = textp;/* If the match must be anchored, just check the string. */ if (program->status & BEGIN_LINE) return check_string(program, string, NIL_INT); if (method == REVERSE) { /* First move to the end of the string */ for (textp = string; *textp != '\n'; textp++) ; /* Start checking string until the begin of the string is met */ while (textp >= string) { program->start_ptr = textp; if (check_string(program, textp--, NIL_INT)) return MATCH; } } else { /* Move through the string until the end of is found */ 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;}/* * Check() checks of a match can be found in the given string. Whenever a STAR * is found during matching, then the begin position of the string is marked * and the maximum number of matches is performed. Then the function star() * is called which starts to finish the match from this position of the string * (and expression). Check() return MATCH for a match, NO_MATCH is the string * couldn't be matched or REG_ERROR for an illegal opcode in expression. */int check_string(program, string, expression)REGEX *program;register char *string;int *expression;{ register int opcode; /* Holds opcode of next expr. atom */ char c; /* Char that must be matched */ char *mark; /* For marking position */ int star_fl; /* A star has been born */ if (expression == NIL_INT) expression = program->result.expression;/* Loop until end of string or end of expression */ while (quit == FALSE && !(*expression & DONE) && *string != '\0' && *string != '\n') { c = *expression & LOW_BYTE; /* Extract match char */ opcode = *expression & HIGH_BYTE; /* Extract opcode */ if (star_fl = (opcode & STAR)) { /* Check star occurrence */ opcode &= ~STAR; /* Strip opcode */ mark = string; /* Mark current position */ } expression++; /* Increment expr. */ switch (opcode) { case NORMAL : if (star_fl) while (*string++ == c) /* Skip all matches */ ; else if (*string++ != c) return NO_MATCH; break; case DOT : string++; if (star_fl) /* Skip to eoln */ 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; /* Add length of list */ break; default : panic("Corrupted program in check_string()"); } if (star_fl) return star(program, mark, string, expression); } if (*expression & DONE) { program->end_ptr = string; /* Match ends here */ /* * We might have found a match. The last thing to do is check * whether a '$' was given at the end of the expression, or * the match was found on a null string. (E.g. [a-z]* always * matches) unless a ^ or $ was included in the pattern. */ 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;}/* * Star() calls check_string() to find out the longest match possible. * It searches backwards until the (in check_string()) marked position * is reached, or a match is found. */int star(program, end_position, string, expression)REGEX *program;register char *end_position;register char *string;int *expression;{ do { string--; if (check_string(program, string, expression)) return MATCH; } while (string != end_position); return NO_MATCH;}/* * In_list() checks if the given character is in the list of []. If it is * it returns MATCH. if it isn't it returns NO_MATCH. These returns values * are reversed when the NEGATE field in the opcode is present. */int in_list(list, c, list_length, opcode)register int *list;char c;register int list_length;int opcode;{ if (c == '\0' || c == '\n') /* End of string, never matches */ return NO_MATCH; while (list_length-- > 1) { /* > 1, don't check acct_field */ if ((*list & LOW_BYTE) == c) return (opcode & NEGATE) ? NO_MATCH : MATCH; list++; } return (opcode & NEGATE) ? MATCH : NO_MATCH;}/* * Dummy_line() adds an empty line at the end of the file. This is sometimes * useful in combination with the EF and DN command in combination with the * Yank command set. */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; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -