📄 mined2.c
字号:
/* Decrement nlines */ nlines--; return next_line;}/* * Delete() deletes all the characters (including newlines) between the * startposition and endposition and fixes the screen accordingly. It * returns the number of lines deleted. */void delete(start_line, start_textp, end_line, end_textp)register LINE *start_line;LINE *end_line;char *start_textp, *end_textp;{ register char *textp = start_line->text; register char *bufp = text_buffer; /* Storage for new line->text */ LINE *line, *stop; int line_cnt = 0; /* Nr of lines deleted */ int count = 0; int shift = 0; /* Used in shift calculation */ int nx = x; modified = TRUE; /* File has been modified *//* Set up new line. Copy first part of start line until start_position. */ while (textp < start_textp) { *bufp++ = *textp++; count++; }/* Check if line doesn't exceed MAX_CHARS */ if (count + length_of(end_textp) >= MAX_CHARS) { error("Line too long", NIL_PTR); return; }/* Copy last part of end_line if end_line is not tail */ copy_string(bufp, (end_textp != NIL_PTR) ? end_textp : "\n");/* Delete all lines between start and end_position (including end_line) */ line = start_line->next; stop = end_line->next; while (line != stop && line != tail) { line = line_delete(line); line_cnt++; }/* Check if last line of file should be deleted */ if (end_textp == NIL_PTR && length_of(start_line->text) == 1 && nlines > 1) { start_line = start_line->prev; (void) line_delete(start_line->next); line_cnt++; } else { /* Install new text */ free_space(start_line->text); start_line->text = alloc(length_of(text_buffer) + 1); copy_string(start_line->text, text_buffer); }/* Fix screen. First check if line is shifted. Perhaps we should shift it back*/ if (get_shift(start_line->shift_count)) { shift = (XBREAK - count_chars(start_line)) / SHIFT_SIZE; if (shift > 0) { /* Shift line `shift' back */ if (shift >= get_shift(start_line->shift_count)) start_line->shift_count = 0; else start_line->shift_count -= shift; nx += shift * SHIFT_SIZE;/* Reset x value */ } } if (line_cnt == 0) { /* Check if only one line changed */ if (shift > 0) { /* Reprint whole line */ set_cursor(0, y); line_print(start_line); } else { /* Just display last part of line */ set_cursor(x, y); put_line(start_line, x, TRUE); } move_to(nx, y); /* Reset cur_text */ return; } shift = last_y; /* Save value */ reset(top_line, y); display(0, y, start_line, shift - y); move_to((line_cnt == 1) ? nx : 0, y);}/* ======================================================================== * * Yank Commands * * ======================================================================== */LINE *mark_line; /* For marking position. */char *mark_text;int lines_saved; /* Nr of lines in buffer *//* * PT() inserts the buffer at the current location. */void PT(){ register int fd; /* File descriptor for buffer */ if ((fd = scratch_file(READ)) == ERRORS) error("Buffer is empty.", NIL_PTR); else { file_insert(fd, FALSE);/* Insert the buffer */ (void) close(fd); }}/* * IF() prompt for a filename and inserts the file at the current location * in the file. */void IF(){ register int fd; /* File descriptor of file */ char name[LINE_LEN]; /* Buffer for file name *//* Get the file name */ 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); /* Insert the file */ (void) close(fd); }}/* * File_insert() inserts a an opened file (as given by filedescriptor fd) * at the current location. */void file_insert(fd, old_pos)int fd;FLAG old_pos;{ char line_buffer[MAX_CHARS]; /* Buffer for next line */ register LINE *line = cur_line; register int line_count = nlines; /* Nr of lines inserted */ LINE *page = cur_line; int ret = ERRORS; /* Get the first piece of text (might be ended with a '\n') from fd */ if (get_line(fd, line_buffer) == ERRORS) return; /* Empty file *//* Insert this text at the current location. */ if (insert(line, cur_text, line_buffer) == ERRORS) return;/* Repeat getting lines (and inserting lines) until EOF is reached */ while ((ret = get_line(fd, line_buffer)) != ERRORS && ret != NO_LINE) line = line_insert(line, line_buffer, ret); if (ret == NO_LINE) { /* Last line read not ended by a '\n' */ line = line->next; (void) insert(line, line->text, line_buffer); }/* Calculate nr of lines added */ line_count = nlines - line_count;/* Fix the screen */ if (line_count == 0) { /* Only one line changed */ set_cursor(0, y); line_print(line); move_to((old_pos == TRUE) ? x : x + length_of(line_buffer), y); } else { /* Several lines changed */ reset(top_line, y); /* Reset pointers */ 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 nr of added line >= REPORT, print the count */ if (line_count >= REPORT) status_line(num_out((long) line_count), " lines added.");}/* * WB() writes the buffer (yank_file) into another file, which * is prompted for. */void WB(){ register int new_fd; /* Filedescriptor to copy file */ int yank_fd; /* Filedescriptor to buffer */ register int cnt; /* Count check for read/write */ int ret = 0; /* Error check for write */ char file[LINE_LEN]; /* Output file */ /* Checkout the buffer */ if ((yank_fd = scratch_file(READ)) == ERRORS) { error("Buffer is empty.", NIL_PTR); return; }/* Get file name */ if (get_file("Write buffer to file:", file) != FINE) return; /* Creat the new file */ if ((new_fd = creat(file, 0644)) < 0) { error("Cannot create ", file); return; } status_line("Writing ", file); /* Copy buffer into 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; }/* Clean up open files and status_line */ (void) close(new_fd); (void) close(yank_fd); if (ret != ERRORS) /* Bad write */ file_status("Wrote", chars_saved, file, lines_saved, TRUE, FALSE);}/* * MA sets mark_line (mark_text) to the current line (text pointer). */void MA(){ mark_line = cur_line; mark_text = cur_text; status_line("Mark set", NIL_PTR);}/* * YA() puts the text between the marked position and the current * in the buffer. */void YA(){ set_up(NO_DELETE);}/* * DT() is essentially the same as YA(), but in DT() the text is deleted. */void DT(){ set_up(DELETE);}/* * 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. */void set_up(remove)FLAG remove; /* DELETE if text should be deleted */{ 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 : /* Ignore stupid behaviour */ yank_status = EMPTY; chars_saved = 0L; status_line("0 characters saved in buffer.", NIL_PTR); break; }}/* * 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. */FLAG checkmark(){ 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() == 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() == 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. */int legal(){ register char *textp = mark_line->text;/* Locate mark_text on mark_line */ while (textp != mark_text && *textp++ != '\0') ; 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) */void yank(start_line, start_textp, end_line, end_textp, remove)LINE *start_line, *end_line;char *start_textp, *end_textp;FLAG remove; /* DELETE if text should be deleted */{ register LINE *line = start_line; register char *textp = start_textp; int fd;/* Creat file to hold buffer */ if ((fd = scratch_file(WRITE)) == ERRORS) return; chars_saved = 0L; lines_saved = 0; status_line("Saving text.", NIL_PTR);/* Keep writing chars until the end_location is reached. */ while (textp != end_textp) { if (write_char(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. If it should, the following * hack is used to save a lot of code. First move back to the start_position. * (This might be the location we're on now!) and them delete the text. * It might be a bit confusing the first time somebody uses it. * Delete() will fix the screen. */ 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.");}/* * Scratch_file() creates a uniq file in /usr/tmp. If the file couldn't * be created other combinations of files are tried until a maximum * of MAXTRAILS times. After MAXTRAILS times, an error message is given * and ERRORS is returned. */#define MAXTRAILS 26int scratch_file(mode)FLAG mode; /* Can be READ or WRITE permission */{ static int trials = 0; /* Keep track of trails */ register char *y_ptr, *n_ptr; int fd; /* 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. */ 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'; /* Check file existence */ 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);/* Have another go */ } } 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;}/* ======================================================================== * * Search Routines * * ======================================================================== *//* * 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[LINE_LEN]; /* Holds previous expr. *//* * SF searches forward for an expression. */void SF(){ search("Search forward:", FORWARD);}/* * SF searches backwards for an expression. */void SR(){ search("Search reverse:", REVERSE);}/* * 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. */REGEX *get_expression(message)char *message;{ static REGEX program; /* Program of expression */ char exp_buf[LINE_LEN]; /* Buffer for new expr. */ 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') { /* A new expr. is typed */ copy_string(typed_expression, exp_buf);/* Save expr. */ compile(exp_buf, &program); /* Compile new expression */ } if (program.status == REG_ERROR) { /* Error during compiling */ error(program.result.err_mess, NIL_PTR); return NIL_REG; } return &program;}/* * GR() a replaces all matches from the current position until the end * of the file. */void GR(){ change("Global replace:", VALID);}/* * LR() replaces all matches on the current line. */void LR(){ change("Line replace:", NOT_VALID);}/* * Change() prompts for an expression and a substitution pattern and changes * all matches of the expression into the substitution. change() start looking * for expressions at the current line and continues until the end of the file * if the FLAG file is VALID. */void change(message, file)char *message; /* Message to prompt for expression */FLAG file;{ char mess_buf[LINE_LEN]; /* Buffer to hold message */ char replacement[LINE_LEN]; /* Buffer to hold subst. pattern */ REGEX *program; /* Program resulting from compilation */ register LINE *line = cur_line; register char *textp; long lines = 0L; /* Nr of lines on which subs occurred */ long subs = 0L; /* Nr of subs made */ int page = y; /* Index to check if line is on screen*//* Save message and get expression */ copy_string(mess_buf, message); if ((program = get_expression(mess_buf)) == NIL_REG) return; /* Get substitution pattern */ 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();/* 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*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -