📄 mined2.c
字号:
* Replace is substitute with confirmation dialogue. */voidREPL (){ change ("Global replace (with confirm):", VALID, TRUE);}/* * LR () replaces all matches on the current line. */voidLR (){ change ("Line replace:", NOT_VALID, FALSE);}/* * 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 (). * Re_search () searches using the last search program and direction. Call graph of search procedures:RS ------------\SFW -\ > re_search > match -----------\SRV --> search < \ \ \ > get_expression > compile > line_check > check_stringGR \ / /REPL > change <--------------------------------/LR / \ \ substitute */REGEX * lastprogram = NIL_REG;FLAG lastmethod = NOT_VALID; /* FORWARD, REVERSE */char prevexpr [maxLINE_LEN]; /* Buffer for previous expr. */FLAG prevmethod = NOT_VALID; /* FORWARD, REVERSE */void do_search ();voidre_search (){ do_search (lastprogram, lastmethod);}voidprev_search (){ search_for (prevexpr, prevmethod);}voidsearch (message, method) char * message; FLAG method;{ register REGEX * program; char prevexp_buf [maxLINE_LEN]; /* Buffer for previous expr. */ if (lastmethod != NOT_VALID) copy_string (prevexp_buf, exp_buf);/* Get the expression */ if ((program = get_expression (message)) == NIL_REG) return; if (program != NIL_REG && lastmethod != NOT_VALID) { copy_string (prevexpr, prevexp_buf); prevmethod = lastmethod; } lastprogram = program; lastmethod = method; re_search ();}voidsearch_for (expr, method) char * expr; FLAG method;{ register REGEX * program;/* make the expression */ if ((program = make_expression (expr)) == NIL_REG) return; do_search (program, method);}voiddo_search (program, method) register REGEX * program; FLAG method;{ register LINE * match_line; if (method == NOT_VALID) { error ("No previous search", NIL_PTR); return; } if (program == NIL_REG) { error ("No previous search expression", NIL_PTR); return; } set_cursor (0, YMAX); clear_status (); flush ();/* Find the match */ if ((match_line = match (program, cur_text, method)) == NIL_LINE) { if (quit == TRUE) { status_msg ("Aborted");/* swallow_dummy_quit_char (); */ quit = FALSE; } else status_msg ("Pattern not found"); return; }/* clear_status (); */ move_address (program->start_ptr, find_y (match_line));}/* Now the search and replace utilities *//* ------------------------------------ *//* 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 () if something went wrong. It sets 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)/* * Bcopy copies `bytes' bytes from the `from' address into the `to' address. */#ifdef vms#define defbcopy#endif#ifdef msdos#define defbcopy#endif#ifdef defbcopy /* otherwise also in standard library */voidbcopy (from, to, bytes) register char * from, * to; register int bytes;{ while (bytes --) * to ++ = * from ++;}#else#ifdef sysV#define bcopy(from, to, len) memcpy (to, from, len)#elseextern void bcopy ();#endif#endif/* * Finished () is called when everything went right during compilation. It * allocates space for the expression, and copies the expression buffer into * this field. */FLAGfinished (program, last_exp) register REGEX * program; int * last_exp;{ register int length = (int) (last_exp - exp_buffer) * sizeof (int);/* Allocate space */ program->result.expression = (int *) alloc (length); if (program->result.expression == NIL_INT) { ring_bell (); error ("Cannot allocate memory for search expression", NIL_PTR); return ERRORS; } else { /* Copy expression. (expression consists of ints!) */ bcopy (exp_buffer, program->result.expression, length); return FINE; }}/* * 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. */FLAGcompile (pattern, program) register uchar * pattern; /* Pointer to pattern */ REGEX * program;{ register int * expression = exp_buffer; int * prev_char; /* Pointer to previous compiled atom */ int * acct_field = NIL_INT; /* Pointer to last BRACKET start */ FLAG negate; /* Negate flag for BRACKET */ uchar low_char; /* Index for chars in BRACKET */ uchar 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 (; ;) { c = * pattern ++; switch (c) { 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; return finished (program, expression); } else * expression ++ = NORMAL + '$'; break; case '\0' : * expression ++ = DONE; return finished (program, expression); 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 FINE; } 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 FINE; } /* Build list */ while (low_char <= * pattern && low_char != '\0') /* avoid wrap-around beyond '\377' (loop!) */ * expression ++ = low_char ++; pattern ++; } if (expression >= & exp_buffer [BLOCK_SIZE]) { reg_error (too_long); return FINE; } } pattern ++; /* Skip ']' */ /* Assign length of list in acct field */ if ((* acct_field = (int) (expression - acct_field)) == 1) { reg_error ("Empty []"); return FINE; } /* 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 FINE; } } /* 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; uchar * string; register FLAG method;{ register LINE * line = cur_line; uchar 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 */ status_msg ("Search wrapped around end of file"); 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. */intline_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 it 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_string () checks if 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 () returns MATCH for a match, NO_MATCH if the string * couldn't be matched or REG_ERROR for an illegal opcode in expression. */intcheck_string (program, string, expression) REGEX * program; register uchar * string; int * expression;{ register int opcode; /* Holds opcode of next expr. atom */ uchar c; /* Char that must be matched */ uchar * 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)) != 0) { /* 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 search program", NIL_PTR); */ ring_bell (); error ("Corrupted search program", NIL_PTR); sleep (2); return NO_MATCH; } if (star_fl) return star (program, mark, string, expression); } if (* expression & DONE) { program->end_ptr = (char *) 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 == (uchar *) 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. */intstar (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. */intin_list (list, c, list_length, opcode) register int * list; uchar 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;}/* ================================================================== * * End * * ================================================================== */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -