📄 mined2.c
字号:
/* * MARKn sets mark n to the current line / current text pointer. */voidMARKn (c) uchar c;{ if (hop_flag > 0) GOMAn (c); else { mark_n_line [c & '\17'] = cur_line; mark_n_text [c & '\17'] = cur_text; status_msg ("Mark set"); }}/* * GOMAn moves to the marked position n */voidGOMAn (c) uchar c;{ if (checkmark (mark_n_line [c & '\17'], mark_n_text [c & '\17']) == NOT_VALID) error ("Mark not set", NIL_PTR); else move_address (mark_n_text [c & '\17'], find_y (mark_n_line [c & '\17']));}/* * Yankie () provides a reference to the last saved buffer to be read * by other mined invocations. */voidyankie (){ delete_file (yankie_file);#ifdef unix link (yank_file, yankie_file);#else build_string (text_buffer, copycommand, yank_file, yankie_file); system (text_buffer);#endif}/* * Set_up is an interface to the actual yank. It calls checkmark () to check * if the marked position is still valid. If it is, yank is called with the * arguments in the right order. */voidset_up (remove, append) FLAG remove; /* == DELETE if text should be deleted */ FLAG append; /* == TRUE if text should only be appended to yank buffer */{ switch (checkmark (mark_line, mark_text)) { case NOT_VALID : error ("Mark not set", NIL_PTR); return; case SMALLER : yank (mark_line, mark_text, cur_line, cur_text, remove, append); yankie (); break; case BIGGER : yank (cur_line, cur_text, mark_line, mark_text, remove, append); yankie (); break; case SAME : /* Ignore stupid behaviour */ /* yank_status = EMPTY; */ chars_saved = 0L; status_msg ("Nothing to save"); break; default : error ("Internal mark error", NIL_PTR); return; }}/* * YA () puts the text between the marked position and the current * in the buffer. */voidYA (){ set_up (NO_DELETE, (hop_flag > 0) ? TRUE : FALSE);}/* * DT () is essentially the same as YA (), but in DT () the text is deleted. */voidDT (){ if (viewonly == TRUE) {viewonlyerr (); return;} set_up (DELETE, (hop_flag > 0) ? TRUE : FALSE);}/* * Check_mark () checks if mark_line and mark_text are still valid pointers. * If they are it returns * SMALLER if the marked position is before the current, * BIGGER if it isn't or SAME if somebody didn't get the point. * NOT_VALID is returned when mark_line and/or mark_text are no longer valid. * Legal () checks if mark_text is valid on the mark_line. */FLAGcheckmark (mark_line, mark_text) register LINE * mark_line; register char * mark_text;{ register LINE * line; FLAG cur_seen = FALSE;/* Special case: check is mark_line and cur_line are the same. */ if (mark_line == cur_line) { if (mark_text == cur_text) /* Even same place */ return SAME; if (legal (mark_line, mark_text) == ERRORS) /* mark_text out of range */ return NOT_VALID; return (mark_text < cur_text) ? SMALLER : BIGGER; }/* Start looking for mark_line in the line structure */ for (line = header->next; line != tail; line = line->next) { if (line == cur_line) cur_seen = TRUE; else if (line == mark_line) break; }/* If we found mark_line (line != tail) check for legality of mark_text */ if (line == tail || legal (mark_line, mark_text) == ERRORS) return NOT_VALID;/* cur_seen is TRUE if cur_line is before mark_line */ return (cur_seen == TRUE) ? BIGGER : SMALLER;}/* * Legal () checks if mark_text is still a valid pointer. */intlegal (mark_line, mark_text) register LINE * mark_line; register char * mark_text;{ register char * textp = mark_line->text;/* Locate mark_text on mark_line */ while (textp != mark_text && * textp != '\0') textp ++; return (* textp == '\0') ? ERRORS : FINE;}/* * Yank puts all the text between start_position and end_position into * the buffer. * The caller must check that the arguments to yank () are valid (e.g. in * the right order). */voidyank (start_line, start_textp, end_line, end_textp, remove, append) LINE * start_line, * end_line; char * start_textp, * end_textp; FLAG remove; /* == DELETE if text should be deleted */ FLAG append; /* == TRUE if text should only be appended to yank buffer */{ register LINE * line = start_line; register char * textp = start_textp; int fd;/* Create file to hold buffer */ if ((fd = scratch_file (WRITE, append)) == ERRORS) return; chars_saved = 0L; lines_saved = 0; if (append == TRUE) status_msg ("Appending text ..."); else status_msg ("Saving text ...");/* Keep writing chars until the end_location is reached. */ while (textp != end_textp) { if (writechar (fd, * textp) == ERRORS) { (void) close (fd); return; } if (* textp ++ == '\n') { /* Move to the next line */ line = line->next; textp = line->text; lines_saved ++; } chars_saved ++; }/* Flush the I/O buffer and close file */ if (flush_buffer (fd) == ERRORS) { (void) close (fd); return; } (void) close (fd); yank_status = VALID; /* * Check if the text should be deleted as well. In case it should, * the following hack is used to save a lot of code. * First move back to the start_position (this might be the current * location) and then delete the text. * This might look a bit confusing to the user the first time. * Delete () will fix the screen. */ if (remove == DELETE) { move_to (find_x (start_line, start_textp), find_y (start_line)); if (delete_text (start_line, start_textp, end_line, end_textp) == ERRORS) { sleep (2) /* give time to read allocation error msg */; } mark_line = cur_line; mark_text = cur_text; } if (append == TRUE) status_line (num_out (chars_saved), " characters appended to buffer"); else status_line (num_out (chars_saved), " characters saved in buffer");}/* * Scratch_file () tries to create a unique file in a temporary directory. * It tries several different filenames until one can be created * or MAXTRIALS attempts have been made. * After MAXTRIALS times, an error message is given and ERRORS is returned. */#define MAXTRIALS 99intscratch_file (mode, append) FLAG mode; /* Can be READ or WRITE permission */ FLAG append; /* == TRUE if text should only be appended to yank buffer */{ static int trials = 0; /* Keep track of trials */ int fd = 0; /* Filedescriptor to buffer *//* If yank_status == NOT_VALID, scratch_file is called for the first time */ if (yank_status == NOT_VALID && mode == WRITE) { /* Create new file */ /* Generate file name. */#ifdef msdos build_string (yank_file, "%s%d", yankie_file, trials);#else build_string (yank_file, "%s%d-%d", yankie_file, getpid (), trials);#endif /* Check file existence */ if (access (yank_file, 0 /* F_OK */) == 0 || (fd = creat (yank_file, bufprot)) < 0) { if (++ trials >= MAXTRIALS) { build_string (text_buffer, "Unable to create scratchfile %s: ", yank_file); if (fd == 0) error (text_buffer, "File exists"); else error (text_buffer, serror ()); return ERRORS; } else return scratch_file (mode, append); /* try again */ } } else if (yank_status == NOT_VALID && mode == READ) { return ERRORS; } else /* yank_status == VALID */ if ( (mode == READ && (fd = open (yank_file, O_RDONLY | O_BINARY, 0)) < 0) || (mode == WRITE && (fd = open (yank_file, O_WRONLY | O_CREAT | ((append == TRUE) ? O_APPEND : O_TRUNC), bufprot)) < 0)) { yank_status = NOT_VALID; return ERRORS; } clear_buffer (); return fd;}/* ================================================================== * * Search Commands * * ================================================================== *//* * A regular expression consists of a sequence of: * 1. A normal character matching that character. * 2. A . matching any character. * 3. A ^ matching the begin of a line. * 4. A $ (as last character of the pattern) mathing the end of a line. * 5. A \<character> matching <character>. * 6. A number of characters enclosed in [] pairs matching any of these * characters. A list of characters can be indicated by a '-'. So * [a-z] matches any letter of the alphabet. If the first character * after the '[' is a '^' then the set is negated (matching none of * the characters). * A ']', '^' or '-' can be escaped by putting a '\' in front of it. * 7. If one of the expressions as described in 1-6 is followed by a * '*' than that expressions matches a sequence of 0 or more of * that expression. */char typed_expression [maxLINE_LEN]; /* Holds previous search expression *//* * SFW searches forward for an expression. */voidSFW (){ if (hop_flag > 0) SIDF (FORWARD); else search ("Search forward:", FORWARD);}/* * SRV searches backwards for an expression. */voidSRV (){ if (hop_flag > 0) SIDF (REVERSE); else search ("Search reverse:", REVERSE);}/* * RS searches using the last search direction and expression. */voidRS (){ if (hop_flag > 0) prev_search (); else re_search ();}/* * Get_expression () prompts for an expression. If just a return is typed, the * old expression is used. If the expression changed, compile () is called and * the returning REGEX structure is returned. It returns NIL_REG upon error. * The save flag indicates whether the expression should be appended at the * message pointer. */char exp_buf [maxLINE_LEN]; /* Buffer for new expr. */REGEX *get_expression (message) char * message;{ static REGEX program; /* Program of expression */ if (get_string (message, exp_buf, FALSE) == ERRORS) return NIL_REG; if (exp_buf [0] == '\0' && typed_expression [0] == '\0') { error ("No previous search expression", NIL_PTR); return NIL_REG; } if (exp_buf [0] != '\0') { /* A new expr. is typed */ copy_string (typed_expression, exp_buf); /* Save expr. */ /* Compile new expression: */ if (compile (exp_buf, & program) == ERRORS) return NIL_REG; } if (program.status == REG_ERROR) { /* Error during compiling */ error (program.result.err_mess, NIL_PTR); return NIL_REG; } return & program;}/* * make_expression is only called by search_for and maintains its own, * independant search program buffer */REGEX *make_expression (expr) char * expr;{ static REGEX program; /* Program of expression */ if (compile (expr, & program) == ERRORS) /* Compile new expression */ return NIL_REG; if (program.status == REG_ERROR) { /* Error during compiling */ error (program.result.err_mess, NIL_PTR); return NIL_REG; } return & program;}/* * Change () prompts for an expression and a substitution pattern and changes * all matches of the expression into the substitution. * change () starts looking for expressions at the current line and * continues until the end of the file if the FLAG `global' is VALID. * It prompts for each change if the FLAG `confirm' is TRUE. * For a call graph of search procedures see search (). */voidchange (message, global, confirm) char * message; /* Message to prompt for expression */ FLAG global, confirm;{ char mess_buf [maxLINE_LEN]; /* Buffer to hold message */ char replacement [maxLINE_LEN]; /* Buffer to hold subst. pattern */ REGEX * program; /* Program resulting from compilation */ register LINE * line = cur_line; register char * textp; char * substitute (); long lines = 0L; /* Nr of lines on which subs occurred */ long subs = 0L; /* Nr of subs made */ int ly = y; /* Index to check if line is on screen */ int previousy = y; char c; FLAG quit_change; if (viewonly == TRUE) {viewonlyerr (); return;}/* Save message and get expression */ if ((program = get_expression (message)) == NIL_REG) return;/* Get substitution pattern */ build_string (mess_buf, "%s %s by:", message, typed_expression); if (get_string (mess_buf, replacement, FALSE) == ERRORS) return; set_cursor (0, YMAX); flush ();/* Substitute until end of file */ do { if (line_check (program, line->text, FORWARD)) { lines ++; /* Repeat sub. on this line as long as we find a match */ do { if (confirm == TRUE) { ly = find_y (line); textp = program->start_ptr; move_address (program->start_ptr, ly); status_msg ("Replace ? (y/n)"); c = promptyn (); clear_status (); if (c == 'y') { subs ++; /* Increment subs */ if ((textp = substitute (line, program, replacement)) == NIL_PTR) return; /* Line too long */ set_cursor (0, ly); line_print (line); } else textp ++; } else { subs ++; /* Increment subs */ line->shift_count = 0; /* in case line would get completely shifted out */ if ((textp = substitute (line, program, replacement)) == NIL_PTR) { set_cursor (0, ly); line_print (line); move_to (x, y); return; /* Line too long */ } } } while ( (program->status & BEGIN_LINE) != BEGIN_LINE && (program->status & END_LINE) != END_LINE && line_check (program, textp, FORWARD) && quit == FALSE); /* Check to see if we can print the result */ if (confirm == FALSE && ly <= SCREENMAX) { set_cursor (0, ly); line_print (line); } } if (ly <= SCREENMAX) ly ++; line = line->next; } while (line != tail && global == VALID && quit == FALSE); quit_change = quit;/* 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 %ld substitutions on %ld lines", (quit_change == TRUE) ? "(Aborted) " : "", subs, lines); status_msg (mess_buf); } else if (global == NOT_VALID && subs >= REPORT) status_line (num_out (subs), " substitutions"); else clear_status (); if (confirm == TRUE) move_to (x, y); else move_to (LINE_START, previousy);/* if (quit == TRUE) swallow_dummy_quit_char (); */ quit = FALSE;}/* * 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; char * newtext; 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 ++; } } * textp = '\0';/* Check for line length not exceeding MAX_CHARS */ if (length_of (text_buffer) + length_of (program->end_ptr) >= MAX_CHARS) { error ("Substitution failed: resulted line too long", NIL_PTR); return NIL_PTR; }/* Append last part of line to the newly built line */ copy_string (textp, program->end_ptr);/* Free old line and install new one */ newtext = alloc (length_of (text_buffer) + 1); if (newtext == NIL_PTR) { ring_bell (); error ("Substitution failed: cannot allocate more memory", NIL_PTR); return NIL_PTR; } else { free_space (line->text); line->text = newtext; copy_string (line->text, text_buffer); return (line->text + (int) (textp - text_buffer)); }}/* * GR () a replaces all matches from the current position until the end * of the file. */voidGR (){ change ("Global replace:", VALID, FALSE);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -