/*======================================================================*\ |* Editor mined *| |* Paste buffer handling *| \*======================================================================*/ #include "mined.h" #include "io.h" /* for flush, set_cursor */ #include /*======================================================================*\ |* System file link behaviour *| \*======================================================================*/ #ifdef unix #define linkyank #endif #ifdef __pcgcc__ #undef linkyank #endif #ifdef __CYGWIN__ #define linkyank #endif /*======================================================================*\ |* Global variables *| \*======================================================================*/ FLAG yank_status = NOT_VALID; /* Status of yank_file */ static FLAG html_status = NOT_VALID; /* Status of html_file */ static int yank_buf_no = 0; /* Buffer # for trials and multiple buffers */ static int max_yank_buf_no = 0; /* Max Buffer # used */ static LINE * pasted_start_line = NIL_LINE; static char * pasted_start_textp = NIL_PTR; static LINE * pasted_end_line = NIL_LINE; static char * pasted_end_textp = NIL_PTR; int buffer_open_flag = 0; /* Counter flag for the collective buffer */ /*======================================================================*\ |* Marker data *| \*======================================================================*/ /* default marker */ static LINE * mark_line = NIL_LINE; /* For marking position. */ static char * mark_text = NIL_PTR; /* explicit markers */ #define maxmarkers 10 static LINE * mark_n_line [maxmarkers] = { NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE, NIL_LINE}; static char * mark_n_text [maxmarkers] = { NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR, NIL_PTR}; /* implicit marker stack */ #define markstacklen 10 static struct { LINE * line; char * text; char * file; int lineno; int pos; } mark_stack [markstacklen] = { {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1}, }; static int mark_stack_poi = 0; static int mark_stack_top = 0; static int mark_stack_begin = 0; static int mark_stack_count = 0; #define dont_debug_mark_stack #ifdef debug_mark_stack #define printf_mark_stack(s) printf ("%s - mark_stack %d [%d..%d] @ %d\n", s, mark_stack_count, mark_stack_begin, mark_stack_top, mark_stack_poi) #define printf_debug_mark_stack(s) printf (s) #else #define printf_mark_stack(s) #define printf_debug_mark_stack(s) #endif /*======================================================================*\ |* Basic Paste operations *| \*======================================================================*/ /* * Legal () checks if mark_text is still a valid pointer. */ static int legal (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; } /* * 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. */ static FLAG checkmark (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; } if (mark_text < cur_text) { return SMALLER; } else { return 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 */ if (cur_seen) { return BIGGER; } else { return SMALLER; } } /*======================================================================*\ |* Cumulative buffer handling *| \*======================================================================*/ static void set_buffer_open (appending) FLAG appending; { #ifdef debug_ring_buffer printf ("set_buffer_open %d\n", buffer_open_flag); #endif if (buffer_open_flag == 0 && (appending == False || yank_buf_no == 0)) { yank_buf_no ++; if (yank_buf_no > max_yank_buf_no) { max_yank_buf_no = yank_buf_no; } yank_status = NOT_VALID; #ifdef debug_ring_buffer flags_changed = True; #endif } buffer_open_flag = 2; } static void close_buffer () { #ifdef debug_ring_buffer if (buffer_open_flag > 0) { flags_changed = True; } #endif buffer_open_flag = 0; } static void revert_yank_buf () { yank_buf_no --; if (yank_buf_no <= 0) { yank_buf_no = max_yank_buf_no; } } /*======================================================================*\ |* Yank text handling *| \*======================================================================*/ /* * Yank puts all the text between start_position and end_position into * the buffer. * The caller must check that the arguments to yank_text () are valid (e.g. in * the right order). */ static void yank_text (fd, buf_status, start_line, start_textp, end_line, end_textp, remove, append) int fd; FLAG * buf_status; LINE * start_line; char * start_textp; LINE * end_line; char * end_textp; FLAG remove; /* == DELETE if text should be deleted */ FLAG append; /* == True if text should only be appended to yank buffer */ { LINE * line = start_line; char * textp = start_textp; long chars_written = 0L; /* chars written to buffer this time */ long bytes_written = 0L; /* bytes written to buffer this time */ int lines_written = 0; /* lines written to buffer this time */ int return_len; /* Check file to hold buffer */ if (fd == ERRORS) { return; } if (append) { status_msg ("Appending text ..."); } else { status_msg ("Saving text ..."); chars_saved = 0L; bytes_saved = 0L; lines_saved = 0; } /* Keep writing chars until the end_location is reached. */ chars_written = char_count (textp) - 1; while (textp != end_textp) { if (* textp == '\n') { if (line == end_line) { error ("Internal error: passed end of text to be copied"); (void) close (fd); return; } /* handle different line ends */ return_len = write_lineend (fd, line->return_type, False); if (return_len == ERRORS) { error2 ("Write to buffer failed: ", serror ()); (void) close (fd); return; } lines_written ++; if (line->return_type != lineend_NONE) { chars_written ++; } bytes_written += return_len; /* move to the next line */ line = line->next; textp = line->text; chars_written += char_count (textp) - 1; } else { if (pastebuf_utf8 && ! utf8_text) { /* write UTF-8 */ unsigned long unichar = charvalue (textp); character unibuf [13]; char * up = (char *) unibuf; if (cjk_text || mapped_text) { unichar = lookup_encodedchar (unichar); if (no_unichar (unichar)) { unichar = ''; } } if (unichar >= 0x80000000) { /* special encoding of 2 Unicode chars, mapped from 1 CJK character */ up += utfencode (unichar & 0xFFFF, up); unichar = (unichar >> 16) & 0x7FFF; } (void) utfencode (unichar, up); /* don't use write_line which might write UTF-16 ! */ up = (char *) unibuf; while (* up != '\0') { if (writechar (fd, * up) == ERRORS) { error2 ("Write to buffer failed: ", serror ()); (void) close (fd); return; } up ++; bytes_written ++; } /* move to the next character */ advance_char (& textp); } else { /* write bytes transparently */ if (writechar (fd, * textp) == ERRORS) { error2 ("Write to buffer failed: ", serror ()); (void) close (fd); return; } bytes_written ++; /* move to the next byte */ textp ++; } } } chars_written -= char_count (end_textp) - 1; /* Flush the I/O buffer and close file */ if (flush_filebuf (fd) == ERRORS) { error2 ("Write to buffer failed: ", serror ()); (void) close (fd); return; } if (close (fd) < 0) { error2 ("Write to buffer failed: ", serror ()); return; } * buf_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; } bytes_saved += bytes_written; chars_saved += chars_written; lines_saved += lines_written; build_string (text_buffer, "%s %d lines to paste buffer (chars/bytes: %ld/%ld) - Paste with %s/Insert", (remove == DELETE) ? append ? "Cut/appended" : "Cut/moved" : append ? "Appended" : "Copied", lines_written, chars_written, bytes_written, emulation == 'e' ? "^Y" /* emacs yank */ : emulation == 'w' ? "^K^C" /* WordStart block copy */ : emulation == 'p' ? "^U" /* pico uncut */ : "^P" /* mined paste */ ); status_msg (text_buffer); } void delete_text_buf (start_line, start_textp, end_line, end_textp) LINE * start_line; char * start_textp; LINE * end_line; char * end_textp; { if (emacs_buffer) { set_buffer_open (False); yank_text (yankfile (WRITE, True), & yank_status, start_line, start_textp, end_line, end_textp, DELETE, True); } else { (void) delete_text (start_line, start_textp, end_line, end_textp); } } /*======================================================================*\ |* Yank file reading *| \*======================================================================*/ /** paste_line calls get_line and converts from Unicode if desired */ static int paste_line (fd, buffer, len) int fd; register char buffer [MAX_CHARS]; int * len; { int ret = get_line (fd, buffer, len, False); if (ret == ERRORS) { return ret; } if (utf8_text || ! pastebuf_utf8) { return ret; } else { char nativebuf [2 * MAX_CHARS]; char * poi = buffer; char * npoi = nativebuf; unsigned long prev_uc = 0; char * prev_npoi; while (* poi) { int ulen = UTF8_len (* poi); unsigned long uc = utf8value (poi); char * ppoi = poi; advance_utf8 (& poi); if (ppoi + ulen != poi) { /* illegal UTF-8 value */ * npoi ++ = ''; prev_uc = 0; } else if (cjk_text || mapped_text) { unsigned long nc = encodedchar2 (prev_uc, uc); if (no_char (nc)) { nc = encodedchar (uc); } else { npoi = prev_npoi; } prev_uc = uc; prev_npoi = npoi; if (no_char (nc)) { /* character not known in current encoding */ * npoi ++ = ''; } else if (cjk_text) { int cjklen = cjkencode (nc, npoi); npoi += cjklen; } else { * npoi ++ = (character) nc; } } else { if (uc >= 0x100) { /* character not known in current encoding */ * npoi ++ = ''; } else { * npoi ++ = (character) uc; } } } * npoi = '\0'; * len = strlen (nativebuf); if (* len >= MAX_CHARS) { error ("Line too long in current encoding"); return ERRORS; } else { strcpy (buffer, nativebuf); return ret; } } } /* * insert_file () inserts the contents of an opened file (as given by * filedescriptor fd) at the current location. * After the insertion, if stay_old_pos is True, the cursor remains at the * start of the inserted text, if stay_old_pos is False, it is placed to * its end. */ static void insert_file (fd, stay_old_pos, from_text_file) int fd; FLAG stay_old_pos; FLAG from_text_file; /* consider UTF-16 ? */ { char line_buffer [MAX_CHARS]; /* Buffer for next line */ register LINE * line = cur_line; register int line_count = total_lines; /* Nr of lines inserted */ LINE * page = cur_line; int ret; int len; lineend_type return_type; reset_get_line (from_text_file); /* Get the first piece of text (might be ended with a '\n') from fd */ ret = paste_line (fd, line_buffer, & len); if (ret == ERRORS) { /* empty file */ return; } /* Adjust line end type if present */ if (ret == SPLIT_LINE) { return_type = lineend_NONE; } else if (ret == NUL_LINE) { return_type = lineend_NUL; } else if (ret != NO_LINE) { return_type = extract_lineend_type (line_buffer, len); } else { return_type = cur_line->return_type; } /* Insert this text at the current location */ len = cur_text - cur_line->text; if (insert_text (line, cur_text, line_buffer) == ERRORS) { pasted_end_line = NIL_LINE; return; } cur_line->return_type = return_type; pasted_end_line = line; pasted_end_textp = line->text + len + length_of (line_buffer); /* Repeat getting lines (and inserting lines) until EOF is reached */ while (line != NIL_LINE && (ret = paste_line (fd, line_buffer, & len)) != ERRORS && ret != NO_LINE) { if (ret == SPLIT_LINE) { return_type = lineend_NONE; } else if (ret == NUL_LINE) { return_type = lineend_NUL; } else { return_type = extract_lineend_type (line_buffer, len); } line = line_insert (line, line_buffer, len, return_type); } /* Calculate nr of lines added */ line_count = total_lines - line_count; if (line == NIL_LINE) { pasted_end_line = NIL_LINE; /* show memory allocation error msg */ sleep (2); } else if (ret == NO_LINE) { /* Last line read not ended by a '\n' */ line = line->next; if (insert_text (line, line->text, line_buffer) == ERRORS) { pasted_end_line = NIL_LINE; /* give time to read error msg */ sleep (2); } else { pasted_end_line = line; pasted_end_textp = line->text + length_of (line_buffer); } } else if (line_count > 0) { pasted_end_line = line->next; pasted_end_textp = line->next->text; } (void) close (fd); /* If illegal lines were input, report */ show_get_l_errors (); /* Fix the screen */ if (line_count == 0) { /* Only one line changed */ set_cursor (0, y); line_print (y, line); move_to (x, y); pasted_start_line = cur_line; pasted_start_textp = cur_text; if (stay_old_pos == False) { move_address (pasted_end_textp, 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 || stay_old_pos) { display (y, cur_line, SCREENMAX - y, y); /* screen display style parameter (last) may be inaccurate */ } move_to (x, y); pasted_start_line = cur_line; pasted_start_textp = cur_text; if (stay_old_pos == False) { if (ret == NO_LINE) { move_address (pasted_end_textp, find_y (line)); } else { move_to (0, find_y (line->next)); } } } /* If number of added lines >= REPORT_CHANGED_LINES, print the count */ if (line_count >= REPORT_CHANGED_LINES) { status_line (dec_out ((long) line_count), " lines added"); } } /** Insert the buffer at the current location. PASTE () moves the cursor behind the inserted text. PASTEstay () moves the cursor in front of the inserted text. */ static void paste_buffer (old_pos) FLAG old_pos; { register int fd; /* File descriptor for buffer */ if (viewonly) { viewonlyerr (); return; } if (hop_flag > 0) { if ((fd = open (yankie_file, O_RDONLY | O_BINARY, 0)) < 0) { error ("No inter window buffer present"); return; } } else { if ((fd = yankfile (READ, False)) == ERRORS) { int e = geterrno (); if (e == 0 || e == ENOENT /* cygwin */) { error ("Buffer is empty"); } else { error2 ("Cannot read paste buffer: ", serror ()); } return; } if (append_flag) { close_buffer (); } } /* Insert the buffer */ insert_file (fd, old_pos, False); } /*======================================================================*\ |* Paste buffer setup *| \*======================================================================*/ int yankfile (mode, append) FLAG mode; /* Can be READ or WRITE permission */ FLAG append; /* == True if text should only be appended to yank buffer */ { return scratchfile (mode, append, yank_file, "buf", & yank_status); } static int htmlfile (mode, append) FLAG mode; /* Can be READ or WRITE permission */ FLAG append; /* == True if text should only be appended to yank buffer */ { return scratchfile (mode, append, html_file, "tag", & html_status); } /*======================================================================*\ |* Copy/Paste and Marker handling *| \*======================================================================*/ void PASTEEXT () { hop_flag = 1; PASTE (); } void PASTE () { paste_buffer (paste_stay_left); } void PASTEstay () { paste_buffer (True); } void YANKRING () { if (cur_line == pasted_end_line && cur_text == pasted_end_textp && checkmark (pasted_start_line, pasted_start_textp) == SMALLER) { move_address (pasted_start_textp, find_y (pasted_start_line)); if (delete_text (pasted_start_line, pasted_start_textp, pasted_end_line, pasted_end_textp) == ERRORS) { sleep (2) /* give time to read allocation error msg */; } else { /* for some mysterious reason, this is needed to fix the display: */ clear_status (); revert_yank_buf (); paste_buffer (False); } } else if (cur_line == pasted_start_line && cur_text == pasted_start_textp && checkmark (pasted_start_line, pasted_start_textp) == SAME) { if (delete_text (pasted_start_line, pasted_start_textp, pasted_end_line, pasted_end_textp) == ERRORS) { sleep (2) /* give time to read allocation error msg */; } else { /* for some mysterious reason, this is needed to fix the display: */ clear_status (); revert_yank_buf (); paste_buffer (True); } } else { error ("Cannot undo previous paste"); } } /* * paste_HTML () inserts the HTML embedding buffer at the current location. */ void paste_HTML () { int fd; /* File descriptor for buffer */ if (viewonly) { viewonlyerr (); return; } if ((fd = open (html_file, O_RDONLY | O_BINARY, 0)) < 0) { error ("HTML paste buffer vanished"); return; } insert_file (fd, False, False); } /* * INSFILE () prompts for a filename and inserts the file at the current * location in the file. */ void INSFILE () { register int fd; /* File descriptor of file */ char name [maxLINE_LEN]; /* Buffer for file name */ if (restricted) { restrictederr (); return; } if (viewonly) { viewonlyerr (); return; } /* Get the file name */ if (get_filename ("Get and insert file:", name) != FINE) { return; } clear_status (); status_line ("Inserting ", name); if ((fd = open (name, O_RDONLY | O_BINARY, 0)) < 0) { error2 ("Cannot open file: " /*, name */, serror ()); } else { /* Insert the file */ insert_file (fd, True, True); /* leave cursor at begin of insertion */ } } /* * 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 = FINE; /* Error check for write */ char wfile_name [maxLINE_LEN]; /* Output file name */ char * msg_doing; char * msg_done; if (restricted) { restrictederr (); return; } /* Checkout the buffer */ if ((yank_fd = yankfile (READ, False)) == ERRORS) { int e = geterrno (); if (e == 0 || e == ENOENT /* cygwin */) { error ("Buffer is empty"); } else { error2 ("Cannot read paste buffer: ", serror ()); } return; } /* Get file name */ if (get_filename ((hop_flag > 0) ? "Append buffer to file:" : "Write buffer to file:", wfile_name) != FINE) { return; } /* Create the new file or open previous file for appending */ if (hop_flag > 0) { status_line ("Opening ", wfile_name); if ((new_fd = open (wfile_name, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, fprot0)) < 0) { error2 ("Cannot append to file: " /* , wfile_name */, serror ()); return; } msg_doing = "Appending buffer to "; msg_done = "Appended buffer to"; } else { if (checkoverwrite (wfile_name) != True) { return; } else { status_line ("Opening ", wfile_name); if ((new_fd = open (wfile_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, fprot0)) < 0) { error2 ("Cannot create file: " /* , wfile_name */, serror ()); return; } } msg_doing = "Writing buffer to "; msg_done = "Wrote buffer to"; } status_line (msg_doing, wfile_name); flush (); /* Copy buffer into file */ while ((cnt = read (yank_fd, text_buffer, sizeof (text_buffer))) > 0) { if (write (new_fd, text_buffer, (unsigned int) cnt) != cnt) { error2 ("Writing buffer to file failed: ", serror ()); ret = ERRORS; break; } } if (cnt < 0) { error2 ("Reading paste buffer failed: ", serror ()); ret = ERRORS; } /* Clean up open files and status line */ (void) close (yank_fd); if (close (new_fd) < 0) { if (ret != ERRORS) { error2 ("Writing buffer to file failed: ", serror ()); ret = ERRORS; } } if (ret != ERRORS) { file_status (msg_done, bytes_saved, chars_saved, wfile_name, lines_saved, False, True, False, False); } } /* * MARK sets mark_line / mark_text to the current line / current text pointer. */ void MARK () { if (hop_flag > 0) { GOMA (); } else { mark_line = cur_line; mark_text = cur_text; status_msg ("Mark set"); } } /* * toggleMARK sets / unsets mark (for pico mode). */ void toggleMARK () { if (checkmark (mark_line, mark_text) == NOT_VALID) { MARK (); } else { mark_line = NIL_LINE; mark_text = NIL_PTR; status_msg ("Mark unset"); } } /* * GOMA moves to the marked position */ void GOMA () { if (checkmark (mark_line, mark_text) == NOT_VALID) { error ("Mark not set"); } else { Pushmark (); move_address (mark_text, find_y (mark_line)); } } /* * MARKn sets mark n to the current line / current text pointer. * Markn sets it silently. */ void MARKn (n) int n; { if (hop_flag > 0) { GOMAn (n); } else { if (n < 0 || n >= maxmarkers) { error ("Marker # out of range"); return; } mark_n_line [n] = cur_line; mark_n_text [n] = cur_text; status_msg ("Marker set"); } } void Markn (n) int n; { if (n == -1) { /* initial mark */ mark_line = cur_line; mark_text = cur_text; } else if (n < 0 || n >= maxmarkers) { error ("Marker # out of range"); return; } else { mark_n_line [n] = cur_line; mark_n_text [n] = cur_text; } } /* * GOMAn moves to the marked position n */ void GOMAn (n) int n; { Pushmark (); if (n < 0 || n >= maxmarkers) { error ("Marker # out of range"); return; } if (checkmark (mark_n_line [n], mark_n_text [n]) == NOT_VALID) { error ("Marker not set"); } else { move_address (mark_n_text [n], find_y (mark_n_line [n])); } } static char * copied_file_name () { int i; char * dup; char * filei; /* check if file name already in stack */ for (i = 0; i < markstacklen; i ++) { filei = mark_stack [i].file; if (filei != NIL_PTR && streq (filei, file_name)) { return filei; } } /* make a new copy of file name string */ dup = alloc (strlen (file_name) + 1); if (dup != NIL_PTR) { strcpy (dup, file_name); } return dup; } /* Pushmark pushes the current position to the mark stack. */ void Pushmark () { mark_stack [mark_stack_top].line = cur_line; mark_stack [mark_stack_top].text = cur_text; mark_stack [mark_stack_top].file = copied_file_name (); mark_stack [mark_stack_top].lineno = line_number; mark_stack [mark_stack_top].pos = get_cur_pos (); mark_stack_top = (mark_stack_top + 1) % markstacklen; if (mark_stack_top == mark_stack_begin) { mark_stack_begin = (mark_stack_begin + 1) % markstacklen; } else { mark_stack_count ++; } mark_stack_poi = mark_stack_top; printf_mark_stack ("Push"); } /* Popmark pops the current position from the mark stack. */ void Popmark () { FLAG switch_files; if (hop_flag > 0) { /* climb up stack towards top */ printf_mark_stack ("HOP Pop"); if (mark_stack_count == 0 || (mark_stack_poi % markstacklen) == mark_stack_top || ((mark_stack_poi + 1) % markstacklen) == mark_stack_top ) { printf_debug_mark_stack ("HOP Pop no more\n"); error ("No more stacked positions"); return; } mark_stack_poi = (mark_stack_poi + 1) % markstacklen; printf_mark_stack ("..."); } else { /* climb down stack towards bottom */ if (mark_stack_poi == mark_stack_begin) { printf_debug_mark_stack ("Pop no more\n"); error ("No more stacked positions"); return; } if (mark_stack_poi == mark_stack_top) { /* at top, push current position first */ printf_mark_stack ("Pop Push"); Pushmark (); mark_stack_poi --; } mark_stack_poi --; if (mark_stack_poi < 0) { mark_stack_poi = markstacklen - 1; } } if (mark_stack [mark_stack_poi].file == NIL_PTR) { printf_debug_mark_stack ("not valid\n"); error ("Stacked position not valid"); return; } switch_files = ! streq (mark_stack [mark_stack_poi].file, file_name); if (switch_files || checkmark (mark_stack [mark_stack_poi].line, mark_stack [mark_stack_poi].text) == NOT_VALID) { int mark_lineno; LINE * open_line; if (switch_files) { if (save_text_load_file (mark_stack [mark_stack_poi].file) == ERRORS) { return; } } mark_lineno = mark_stack [mark_stack_poi].lineno - 1; open_line = proceed (header->next, mark_lineno); if (open_line == tail) { EFILE (); error ("Stacked position not present anymore"); } else { int mark_col = mark_stack [mark_stack_poi].pos; int cur_pos = 0; char * cpoi; move_to (0, find_y (open_line)); cpoi = cur_line->text; while (* cpoi != '\n' && cur_pos < mark_col) { advance_char (& cpoi); cur_pos ++; } move_address (cpoi, y); } } else { move_address (mark_stack [mark_stack_poi].text, find_y (mark_stack [mark_stack_poi].line)); } } #ifndef linkyank /* * copy one file to the other Return False if that fails. */ static FLAG copyfile (yank_file, yankie_file) char * yank_file; char * yankie_file; { int yank_fd; /* Filedescriptor to yank buffer */ int new_fd; /* Filedescriptor to yankie file */ int cnt; /* Count check for read/write */ int ret = True; /* Checkout the buffer */ if ((yank_fd = open (yank_file, O_RDONLY | O_BINARY, 0)) < 0) { return False; } /* Create yankie file */ if ((new_fd = open (yankie_file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, bufprot)) < 0) { return False; } /* Copy buffer into file */ while ((cnt = read (yank_fd, text_buffer, sizeof (text_buffer))) > 0) { if (write (new_fd, text_buffer, (unsigned int) cnt) != cnt) { ret = False; break; } } if (cnt < 0) { ret = False; } /* Clean up open files and status line */ (void) close (yank_fd); if (close (new_fd) < 0) { ret = False; } return ret; } #endif /* * Yankie () provides a reference to the last saved buffer to be read * by other mined invocations. */ static void yankie () { #ifdef linkyank delete_file (yankie_file); if (link (yank_file, yankie_file) < 0) { /* no error handling here as a message would inappropriately obscure the original paste buffer copy information message or an error message to the paste buffer copy function */ } #else if (copyfile (yank_file, yankie_file) == False) { /* no error handling here as a message would inappropriately obscure the original paste buffer copy information message or an error message to the paste buffer copy function */ } #endif } /* * yank_block is an interface to the actual yank. * It calls checkmark () to check if the marked position is still valid. * If it is, yank_text is called. */ static void yank_block (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 : if (remove == DELETE) { if (mined_keypad) { error ("Mark not set for Cut and Paste - type Alt-Del to delete char, F1 k for help"); } else { error ("Mark not set for Cut and Paste - type Ctrl-Del to delete char, F1 k for help"); } } else { error ("Mark not set for Copy and Paste"); } return; case SMALLER : set_buffer_open (append); yank_text (yankfile (WRITE, append), & yank_status, mark_line, mark_text, cur_line, cur_text, remove, append); yankie (); break; case BIGGER : set_buffer_open (append); yank_text (yankfile (WRITE, append), & yank_status, cur_line, cur_text, mark_line, mark_text, remove, append); yankie (); break; case SAME : /* Ignore stupid behaviour */ status_msg ("Nothing to save"); break; default : error ("Internal mark error"); return; } } void yank_HTML (remove) FLAG remove; /* == DELETE if text should be deleted */ { switch (checkmark (mark_line, mark_text)) { case NOT_VALID : error ("Mark not set"); return; case SMALLER : yank_text (htmlfile (WRITE, False), & html_status, mark_line, mark_text, cur_line, cur_text, remove, False); break; case BIGGER : yank_text (htmlfile (WRITE, False), & html_status, cur_line, cur_text, mark_line, mark_text, remove, False); break; case SAME : /* Ignore stupid behaviour */ status_msg ("Nothing to save"); break; default : error ("Internal mark error"); return; } } /* * COPY () puts the text between the marked position and the current * in the buffer. */ void COPY () { if (append_flag) { yank_block (NO_DELETE, True); } else if (hop_flag > 0) { yank_block (NO_DELETE, True); } else { yank_block (NO_DELETE, False); } } /* * CUT () is essentially the same as COPY (), but the text is deleted. */ void CUT () { if (viewonly) { viewonlyerr (); return; } if (append_flag) { yank_block (DELETE, True); } else if (hop_flag > 0) { yank_block (DELETE, True); } else { yank_block (DELETE, False); } } /*======================================================================*\ |* Yank file handling *| \*======================================================================*/ /* * scratchfile/yankfile () 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 99 static void set_yank_file_name (buf_name, which, no) char * buf_name; char * which; int no; { #ifdef msdos build_string (buf_name, "%s-%s.%d", yankie_file, which, no); #else build_string (buf_name, "%s.%s.%d_%d", yankie_file, which, getpid (), no); #endif } /* * Delete yank file if there is one. */ void delete_yank_files () { /* if (yank_status == VALID) { delete_file (yank_file); } */ while (max_yank_buf_no > 0) { set_yank_file_name (yank_file, "buf", max_yank_buf_no); delete_file (yank_file); max_yank_buf_no --; } if (html_status == VALID) { delete_file (html_file); } } int scratchfile (mode, append, buf_name, which, buf_status) FLAG mode; /* Can be READ or WRITE permission */ FLAG append; /* == True if text should only be appended to yank buffer */ char * buf_name; char * which; FLAG * buf_status; { int fd = 0; /* Filedescriptor to buffer */ set_yank_file_name (buf_name, which, yank_buf_no); /* If * buf_status == NOT_VALID, scratchfile is called for the first time */ if (* buf_status == NOT_VALID && mode == WRITE) { /* Create new file */ /* Generate file name. */ /*set_yank_file_name (buf_name, which, yank_buf_no);*/ /* Check file existence */ if (access (buf_name, 0 /* F_OK */) == 0 || ( /* fd = creat (buf_name, bufprot) */ fd = open (buf_name, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, bufprot) ) < 0) { if (++ yank_buf_no >= MAXTRIALS) { if (fd == 0) { error2 ("Cannot create buffer file: " /* , buf_name */, "File exists"); } else { error2 ("Cannot create buffer file: " /* , buf_name */, serror ()); } return ERRORS; } else { /* try again */ return scratchfile (mode, append, buf_name, which, buf_status); } } } else if (* buf_status == NOT_VALID && mode == READ) { errno = 0; return ERRORS; } else /* * buf_status == VALID */ if ( (mode == READ && (fd = open (buf_name, O_RDONLY | O_BINARY, 0)) < 0) || (mode == WRITE && (fd = open (buf_name, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC) | O_BINARY , bufprot)) < 0)) { * buf_status = NOT_VALID; return ERRORS; } clear_filebuf (); return fd; } /*======================================================================*\ |* End *| \*======================================================================*/