1 /*
2 * w32cbrd: collection of common clipboard manipulation routines shared by
3 * the Win32 console- and GUI-based vile editor.
4 *
5 * Caveats
6 * =======
7 * -- On a stock Win95 host, the first copy to the clipboard from the
8 * console version of vile causes the busy thread cursor to be displayed
9 * (i.e., cursor changes to a pointer/hourglass icon). This cursor stays
10 * active for 5-10 seconds (all apps are active) and then goes away.
11 * Subsequent copies do not show this cursor. On an NT host, this
12 * phenomenon does not occur.
13 *
14 * $Id: w32cbrd.c,v 1.44 2020/01/17 22:29:27 tom Exp $
15 */
16
17 #include "estruct.h"
18 #include "edef.h"
19
20 #include <stdlib.h>
21 #include <search.h>
22
23 #if defined(UNICODE) && defined(CF_UNICODETEXT)
24 #define USE_UNICODE 1
25 #else
26 #define USE_UNICODE 0
27 #endif
28
29 #if USE_UNICODE
30 #define myTextFormat CF_UNICODETEXT
31 #else
32 #define myTextFormat CF_TEXT
33 #endif
34
35 #define CLIPBOARD_BUSY "[Clipboard currently busy]"
36 #define CLIPBOARD_COPY_MB "[Clipboard copy from minibuffer not supported]"
37 #define CLIPBOARD_COPYING "[Copying...]"
38 #define CLIPBOARD_COPY_FAIL "[Clipboard copy failed]"
39 #define CLIPBOARD_COPY_MEM "[Insufficient memory for copy operation]"
40
41 typedef struct rgn_cpyarg_struct {
42 UINT nbyte, nline;
43 W32_CHAR *dst;
44 } RGN_CPYARG;
45
46 static int print_low, print_high;
47
48 /* ------------------------------------------------------------------ */
49
50 static void
minibuffer_abort(void)51 minibuffer_abort(void)
52 {
53 W32_CHAR str[3];
54
55 /*
56 * Aborting out of the minibuffer is not easy. When in doubt, use a
57 * sledge hammer.
58 */
59
60 str[0] = ESC;
61 str[1] = '\0';
62 (void) w32_keybrd_write(str);
63 update(TRUE);
64 }
65
66 static void
report_cbrdstats(UINT nbyte,UINT nline,int pasted)67 report_cbrdstats(UINT nbyte, UINT nline, int pasted)
68 {
69 char buf[128];
70
71 if (!global_b_val(MDTERSE)) {
72 lsprintf(buf,
73 "[%s %d line%s, %d bytes %s clipboard]",
74 (pasted) ? "Pasted" : "Copied",
75 nline,
76 PLURAL(nline),
77 nbyte,
78 (pasted) ? "from" : "to");
79 mlwrite(buf);
80 } else
81 mlforce("[%d lines]", nline);
82 }
83
84 /* The memory block handle _must_ be unlocked before calling this fn. */
85 static int
setclipboard(HGLOBAL hClipMem,UINT nbyte,UINT nline)86 setclipboard(HGLOBAL hClipMem, UINT nbyte, UINT nline)
87 {
88 int rc, i;
89
90 TRACE((T_CALLED "setclipboard(%p, %d, %d)\n", hClipMem, nbyte, nline));
91
92 for (rc = i = 0; i < 8 && (!rc); i++) {
93 /* Try to open clipboard */
94
95 if (!OpenClipboard(NULL))
96 Sleep(500);
97 else
98 rc = 1;
99 }
100 if (!rc) {
101 mlforce(CLIPBOARD_BUSY);
102 GlobalFree(hClipMem);
103 returnCode(FALSE);
104 }
105 EmptyClipboard();
106 rc = (SetClipboardData(myTextFormat, hClipMem) != NULL);
107 CloseClipboard();
108 if (!rc) {
109 mlforce(CLIPBOARD_COPY_FAIL);
110 GlobalFree(hClipMem);
111 } else {
112 /* success */
113
114 report_cbrdstats(nbyte - 1, /* subtract terminating NUL */
115 nline,
116 FALSE);
117 }
118 returnCode(rc);
119 }
120
121 /* Count lines and nonbuffer data added during "copy to clipboard" operation. */
122 static void
cbrd_count_meta_data(int len,UINT * nbyte,UINT * nline,char * src)123 cbrd_count_meta_data(int len,
124 UINT * nbyte,
125 UINT * nline,
126 char *src)
127 {
128 register UINT c;
129
130 while (len--) {
131 if ((c = (UCHAR) * src++) == '\n') {
132 (*nline)++;
133 (*nbyte)++; /* API requires CR/LF terminator */
134 } else if (c < _SPC_ && c != _TAB_) /* assumes ASCII char set */
135 (*nbyte)++; /* account for '^' meta char */
136 else if (c > _TILDE_ && (!PASS_HIGH(c))) /* assumes ASCII char set */
137 (*nbyte) += 3; /* account for '\xdd' meta chars */
138 }
139 }
140
141 /*
142 * This function is called to process each logical line of data in a
143 * user-selected region. It counts the number of bytes of data in the line.
144 */
145 static int
count_rgn_data(void * argp,int l,int r)146 count_rgn_data(void *argp, int l, int r)
147 {
148 RGN_CPYARG *cpyp;
149 int len;
150 LINE *lp;
151
152 lp = DOT.l;
153
154 /* Rationalize offsets */
155 if (llength(lp) < l)
156 return (TRUE);
157 if (r > llength(lp))
158 r = llength(lp);
159 cpyp = argp;
160 if (r == llength(lp) || regionshape == rgn_RECTANGLE) {
161 /* process implied newline */
162
163 cpyp->nline++;
164 cpyp->nbyte += 2; /* CBRD API maps NL -> CR/LF */
165 }
166 len = r - l;
167 cpyp->nbyte += len;
168 cbrd_count_meta_data(len, &cpyp->nbyte, &cpyp->nline, lvalue(lp) + l);
169 return (TRUE);
170 }
171
172 static void
cbrd_copy_and_xlate(int len,W32_CHAR ** cbrd_ptr,UCHAR * src)173 cbrd_copy_and_xlate(int len, W32_CHAR ** cbrd_ptr, UCHAR * src)
174 {
175 register UINT c;
176 W32_CHAR *dst = *cbrd_ptr;
177 UCHAR *last = (len + src);
178
179 while (src < last) {
180 if ((c = *src) == '\n') {
181 *dst++ = '\r';
182 *dst++ = '\n';
183 }
184 #if USE_UNICODE
185 else {
186 UINT target;
187 int rc = vl_conv_to_utf32(&target, (const char *) src, len);
188
189 if (rc > 1) {
190 *dst++ = (W32_CHAR) target;
191 src += ((size_t) rc - 1);
192 } else {
193 *dst++ = (W32_CHAR) * src;
194 }
195 }
196 #else
197 else if ((c >= _SPC_ && c <= _TILDE_) || (c == _TAB_))
198 *dst++ = (UCHAR) c;
199 else if (c < _SPC_) {
200 *dst++ = '^';
201 *dst++ = ctrldigits[c];
202 } else {
203 /* c > _TILDE_ */
204
205 if (!PASS_HIGH(c)) {
206 *dst++ = '\\';
207 *dst++ = 'x';
208 *dst++ = hexdigits[(c & 0xf0) >> 4];
209 *dst++ = hexdigits[c & 0xf];
210 } else
211 *dst++ = (W32_CHAR) c;
212 }
213 #endif
214 ++src;
215 }
216 *cbrd_ptr = dst;
217 }
218
219 /*
220 * This function is called to process each logical line of data in a
221 * user-selected region. It copies region data to a buffer allocated on
222 * the heap.
223 */
224 static int
copy_rgn_data(void * argp,int l,int r)225 copy_rgn_data(void *argp, int l, int r)
226 {
227 RGN_CPYARG *cpyp;
228 int len;
229 LINE *lp;
230
231 lp = DOT.l;
232
233 /* Rationalize offsets */
234 if (llength(lp) < l)
235 return (TRUE);
236 if (r > llength(lp))
237 r = llength(lp);
238 cpyp = argp;
239 len = r - l;
240 cbrd_copy_and_xlate(len, &cpyp->dst, (UCHAR *) (lvalue(lp) + l));
241 if (r == llength(lp) || regionshape == rgn_RECTANGLE) {
242 /* process implied newline */
243
244 *cpyp->dst++ = '\r';
245 *cpyp->dst++ = '\n';
246 }
247 return (TRUE);
248 }
249
250 /*
251 * Copy contents of [un]named register to Windows clipboard. The control
252 * flow is shamelessly copied from kwrite().
253 */
254 static int
cbrd_reg_copy(void)255 cbrd_reg_copy(void)
256 {
257 HGLOBAL hClipMem;
258 register int i;
259 KILL *kp; /* pointer into [un]named register */
260 UINT nbyte;
261 UINT nline;
262 UCHAR *copy;
263 int rc;
264
265 TRACE((T_CALLED "cbrd_reg_copy()\n"));
266 /* make sure there is something to put */
267 if (kbs[ukb].kbufh == NULL) {
268 mlforce("[Nothing to copy]");
269 returnCode(FALSE); /* not an error, just nothing */
270 }
271
272 print_high = global_g_val(GVAL_PRINT_HIGH);
273 print_low = global_g_val(GVAL_PRINT_LOW);
274
275 /* tell us we're writing */
276 mlwrite(CLIPBOARD_COPYING);
277 nline = 0;
278 nbyte = 0;
279
280 /*
281 * Make 2 passes over the data. 1st pass counts the data and
282 * adjusts for the fact that:
283 *
284 * 1) each '\n' must be warped to "\r\n" to satisfy clipboard APIs.
285 * 2) unprintable data (modulo tabs) must be warped to a printable
286 * equivalent.
287 */
288 for (kp = kbs[ukb].kbufh; kp; kp = kp->d_next) {
289 i = KbSize(ukb, kp);
290 nbyte += i;
291 cbrd_count_meta_data(i, &nbyte, &nline, (char *) kp->d_chunk);
292 }
293 nbyte++; /* Add room for terminating null */
294
295 /* 2nd pass -- alloc storage for data and copy to clipboard. */
296 TRACE(("copying %u bytes to clipboard\n", nbyte));
297 hClipMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, nbyte * sizeof(W32_CHAR));
298 if (hClipMem == NULL) {
299 mlforce(CLIPBOARD_COPY_MEM);
300 rc = FALSE;
301 } else {
302 copy = malloc(nbyte);
303 if (copy != 0) {
304 UCHAR *tmp = copy;
305 W32_CHAR *dst;
306 if ((dst = GlobalLock(hClipMem)) != NULL) {
307 W32_CHAR *old = dst;
308 for (kp = kbs[ukb].kbufh; kp; kp = kp->d_next) {
309 int size = KbSize(ukb, kp);
310 memcpy(tmp, kp->d_chunk, size);
311 tmp += size;
312 }
313 cbrd_copy_and_xlate((int) (tmp - copy), &dst, copy);
314 *dst = '\0';
315 GlobalUnlock(hClipMem);
316 rc = setclipboard(hClipMem, (UINT) (dst - old), nline);
317 } else {
318 mlforce("[Cannot copy]");
319 rc = FALSE;
320 }
321 free(copy);
322 } else {
323 mlforce("[Cannot copy]");
324 rc = FALSE;
325 }
326 }
327 returnCode(rc);
328 }
329
330 /*
331 * Copy contents of unnamed register to Windows clipboard.
332 *
333 * Bound to Alt+Insert.
334 */
335 int
cbrdcpy_unnamed(int unused1 GCC_UNUSED,int unused2 GCC_UNUSED)336 cbrdcpy_unnamed(int unused1 GCC_UNUSED, int unused2 GCC_UNUSED)
337 {
338 int rc;
339
340 if (reading_msg_line) {
341 minibuffer_abort(); /* FIXME -- goes away some day? */
342 mlerase();
343 mlforce(CLIPBOARD_COPY_MB);
344 return (ABORT);
345 }
346 kregcirculate(FALSE);
347 rc = cbrd_reg_copy();
348 ukb = 0;
349 return (rc);
350 }
351
352 /*
353 * Copy the currently-selected region (i.e., the range of lines from DOT to
354 * MK, inclusive) to the windows clipboard. Lots of code has been borrowed
355 * and/or adapted from operyank() and writereg().
356 */
357 static int
cbrdcpy_region(void)358 cbrdcpy_region(void)
359 {
360 RGN_CPYARG cpyarg;
361 DORGNLINES dorgn;
362 HGLOBAL hClipMem;
363 MARK odot;
364 int rc;
365
366 TRACE((T_CALLED "cbrdcpy_region()\n"));
367 mlwrite(CLIPBOARD_COPYING);
368 print_high = global_g_val(GVAL_PRINT_HIGH);
369 print_low = global_g_val(GVAL_PRINT_LOW);
370 odot = DOT; /* do_lines_in_region() moves DOT. */
371 cpyarg.nbyte = cpyarg.nline = 0;
372 dorgn = get_do_lines_rgn();
373
374 /*
375 * Make 2 passes over the data. 1st pass counts the data and
376 * adjusts for the fact that:
377 *
378 * 1) each '\n' must be warped to "\r\n" to satisfy clipboard APIs.
379 * 2) unprintable data (modulo tabs) must be warped to a printable
380 * equivalent.
381 */
382 rc = dorgn(count_rgn_data, &cpyarg, TRUE);
383 DOT = odot;
384 if (!rc)
385 returnCode(FALSE);
386 cpyarg.nbyte++; /* Terminating nul */
387
388 /* 2nd pass -- alloc storage for data and copy to clipboard. */
389 hClipMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cpyarg.nbyte);
390 if (hClipMem == NULL) {
391 mlforce(CLIPBOARD_COPY_MEM);
392 returnCode(FALSE);
393 }
394 if ((cpyarg.dst = GlobalLock(hClipMem)) != NULL) {
395 /*
396 * Pass #2 -> The actual copy. Don't need to restore DOT, that
397 * is handled by opercbrdcpy().
398 */
399 rc = dorgn(copy_rgn_data, &cpyarg, TRUE);
400 GlobalUnlock(hClipMem);
401 } else {
402 rc = FALSE;
403 }
404 if (!rc) {
405 GlobalFree(hClipMem);
406 returnCode(FALSE);
407 }
408 *cpyarg.dst = '\0';
409 returnCode(setclipboard(hClipMem, cpyarg.nbyte, cpyarg.nline));
410 }
411
412 /*
413 * Copy contents of specified region or register to Windows clipboard.
414 * This command is an operator and mimics the functionality of ^W, but
415 * mimics operyank()'s implementation.
416 *
417 * Bound to Ctrl+Insert.
418 */
419 int
opercbrdcpy(int f,int n)420 opercbrdcpy(int f, int n)
421 {
422 if (reading_msg_line) {
423 minibuffer_abort(); /* FIXME -- goes away some day? */
424 mlerase();
425 mlforce(CLIPBOARD_COPY_MB);
426 return (ABORT);
427 }
428 if (ukb != 0)
429 return (cbrd_reg_copy());
430 else {
431 MARK odot;
432 int rc;
433
434 odot = DOT;
435 opcmd = OPDEL;
436 rc = vile_op(f, n, cbrdcpy_region, "Clipboard copy");
437 DOT = odot; /* cursor does not move */
438 return (rc);
439 }
440 }
441
442 /* ------------------- Paste Functionality ----------------------- */
443
444 #define MAX_MAPPED_STR 16 /* fairly conservative :-) */
445
446 static int map_and_insert(UINT, UINT *);
447
448 typedef struct {
449 UINT val;
450 char *str;
451 } MAP;
452
453 /* Keep this table sorted by "val" . */
454 /* *INDENT-OFF* */
455 static MAP cbrdmap[] =
456 {
457 { 0x85, "..." },
458 { 0x8B, "<" },
459 { 0x91, "'" },
460 { 0x92, "'" },
461 { 0x93, "\"" },
462 { 0x94, "\"" },
463 { 0x96, "-" },
464 { 0x97, "--" },
465 { 0x99, "(TM)" },
466 { 0x9B, ">" },
467 { 0xA6, "|" },
468 { 0xA9, "(C)" },
469 { 0xAB, "<<" },
470 { 0xAD, "-" },
471 { 0xAE, "(R)" },
472 { 0xB1, "+/-" },
473 { 0xBB, ">>" },
474 { 0xBC, "1/4" },
475 { 0xBD, "1/2" },
476 { 0xBE, "3/4" },
477 };
478 /* *INDENT-ON* */
479
480 /* --------------------------------------------------------------- */
481
482 static int
map_compare(const void * elem1,const void * elem2)483 map_compare(const void *elem1, const void *elem2)
484 {
485 return (((const MAP *) elem1)->val - ((const MAP *) elem2)->val);
486 }
487
488 static int
map_cbrd_char(UINT c,W32_CHAR mapped_rslt[MAX_MAPPED_STR])489 map_cbrd_char(UINT c, W32_CHAR mapped_rslt[MAX_MAPPED_STR])
490 {
491 MAP key, *rslt_p;
492 int nmapped = 0;
493 char *str;
494
495 key.val = c;
496 rslt_p = bsearch(&key,
497 cbrdmap,
498 sizeof(cbrdmap) / sizeof(cbrdmap[0]),
499 sizeof(cbrdmap[0]),
500 map_compare);
501 if (!rslt_p)
502 mapped_rslt[nmapped++] = (UCHAR) c;
503 else {
504 for (str = rslt_p->str; *str; str++)
505 mapped_rslt[nmapped++] = *str;
506 }
507 mapped_rslt[nmapped] = '\0';
508 return (nmapped);
509 }
510
511 /* paste a single line from the clipboard to the minibuffer. */
512 static int
paste_to_minibuffer(W32_CHAR * cbrddata)513 paste_to_minibuffer(W32_CHAR * cbrddata)
514 {
515 int rc = TRUE;
516 W32_CHAR *cp = cbrddata;
517 #if !USE_UNICODE
518 W32_CHAR one_char[2];
519 W32_CHAR map_str[MAX_MAPPED_STR + 1];
520 #endif
521
522 while (*cp) {
523 if (*cp == '\r' && *(cp + 1) == '\n') {
524 *cp = '\0';
525
526 /*
527 * Don't allow more than one line of data to be pasted into the
528 * minibuffer (to protect the user from seriously bad side
529 * effects when s/he pastes in the wrong buffer). We don't
530 * report an error here in an effort to retain compatibility
531 * with a couple of "significant" win32 apps (e.g., IE and
532 * Outlook) that simply truncate a paste at one line when it
533 * only makes sense to take a single line of input.
534 */
535 break;
536 }
537 cp++;
538 }
539 #if USE_UNICODE
540 rc = w32_keybrd_write(cbrddata);
541 #else
542 one_char[1] = '\0';
543 while (*cbrddata && rc) {
544 if (*cbrddata > _TILDE_) {
545 (void) map_cbrd_char(*cbrddata, map_str);
546 rc = w32_keybrd_write(map_str);
547 } else {
548 one_char[0] = *cbrddata;
549 rc = w32_keybrd_write(one_char);
550 }
551 cbrddata++;
552 }
553 #endif
554 return (rc);
555 }
556
557 #define MAX_UTF8 8 /* buffer-size big enough for any UTF-8 conversion */
558
559 /*
560 * Paste contents of windows clipboard (if TEXT) to current buffer.
561 * Bound to Shift+Insert.
562 */
563 int
cbrdpaste(int f GCC_UNUSED,int n GCC_UNUSED)564 cbrdpaste(int f GCC_UNUSED, int n GCC_UNUSED)
565 {
566 UINT c;
567 W32_CHAR *data;
568 HANDLE hClipMem;
569 int i, rc, suppressnl;
570 UINT nbyte, nline;
571
572 TRACE((T_CALLED "cbrdpaste\n"));
573 for (rc = i = 0; i < 8 && (!rc); i++) {
574 /* Try to open clipboard */
575
576 if (!OpenClipboard(NULL))
577 Sleep(500);
578 else
579 rc = 1;
580 }
581 if (!rc) {
582 if (reading_msg_line) {
583 minibuffer_abort(); /* FIXME -- goes away some day? */
584 rc = ABORT;
585 } else
586 rc = FALSE;
587 mlforce(CLIPBOARD_BUSY);
588 returnCode(rc);
589 }
590 if ((hClipMem = GetClipboardData(myTextFormat)) == NULL) {
591 CloseClipboard();
592 if (reading_msg_line) {
593 minibuffer_abort(); /* FIXME -- goes away some day? */
594 rc = ABORT;
595 } else
596 rc = FALSE;
597 mlforce("[Clipboard empty or not TEXT data]");
598 returnCode(rc);
599 }
600 if ((data = GlobalLock(hClipMem)) == NULL) {
601 CloseClipboard();
602 if (reading_msg_line) {
603 minibuffer_abort(); /* FIXME -- goes away some day? */
604 rc = ABORT;
605 } else
606 rc = FALSE;
607 mlforce("[Can't lock clipboard memory]");
608 returnCode(rc);
609 }
610 if (reading_msg_line) {
611 rc = paste_to_minibuffer(data);
612 GlobalUnlock(hClipMem);
613 CloseClipboard();
614 returnCode(rc);
615 }
616 mlwrite(CLIPBOARD_COPYING);
617 nbyte = nline = 0;
618 rc = TRUE;
619
620 /*
621 * Before stuffing data in the current buffer, save info regarding dot
622 * and mark. The dot/mark manipulation code is more or less cribbed
623 * from doput() and PutChar(). Note also that clipboard data is always
624 * copied into the current region as if it were an "exact" shape, which
625 * should be the most intuitive result for Windows users who work with
626 * the clipboard (I hope).
627 */
628 suppressnl = is_header_line(DOT, curbp);
629 (void) setmark();
630 while (*data && rc) {
631 c = *data;
632
633 if (c == '\n') {
634 nbyte++;
635 nline++;
636 rc = lnewline();
637 } else if (c == '\r' && *(data + 1) == '\n') {
638 /* Clipboard end of line delimiter is crlf. Ignore cr. */
639 ;
640 } else if (!b_is_utfXX(curbp) && (c > _TILDE_)) {
641 rc = map_and_insert(c, &nbyte);
642 } else {
643 int chunk;
644 int c2;
645 int base = DOT.o;
646 #ifdef UNICODE
647 int in_chunk;
648 int chunk_bytes = 0;
649 char *dst;
650 #endif
651
652 for (chunk = 0; data[chunk] != 0; ++chunk) {
653 if ((c2 = data[chunk]) == '\n'
654 || (c2 == '\r' && data[chunk + 1] == '\n')
655 || (!b_is_utfXX(curbp) && (c > _TILDE_))) {
656 break;
657 }
658 }
659
660 #ifdef UNICODE
661 /* sizeof(W32_CHAR) > 1 */
662
663 /* compute 'chunk_bytes' here based on actual bytes */
664 for (in_chunk = 0; in_chunk < chunk; ++in_chunk) {
665 chunk_bytes += vl_conv_to_utf8((UCHAR *) 0, data[in_chunk], MAX_UTF8);
666 }
667
668 rc = lins_bytes(chunk_bytes, (int) c);
669 if (!rc)
670 break;
671
672 nbyte += chunk_bytes;
673 for (in_chunk = 0, dst = lvalue(DOT.l) + base;
674 in_chunk < chunk;
675 ++in_chunk) {
676 UCHAR target[MAX_UTF8];
677 int len = vl_conv_to_utf8(target, data[in_chunk], MAX_UTF8);
678 memcpy(dst, target, len);
679 dst += len;
680 }
681 data += ((size_t) chunk - 1);
682 #else
683 /* sizeof(W32_CHAR) == 1 */
684
685 rc = lins_bytes(chunk, (int) c);
686 if (!rc)
687 break;
688
689 nbyte += chunk;
690 memcpy(lvalue(DOT.l) + base, data, chunk);
691 data += (chunk - 1);
692 #endif
693 }
694 data++;
695 }
696 if (rc) {
697 if (nbyte > 0 && (data[-1] == '\n') && suppressnl) {
698 /*
699 * Last byte inserted was a newline and DOT was originally
700 * pointing at the beginning of the buffer(??). In this
701 * situation, lins_bytes() has added an additional newline to the
702 * buffer. Remove it.
703 */
704
705 (void) ldel_bytes(1, FALSE);
706 }
707 }
708 GlobalUnlock(hClipMem);
709 CloseClipboard();
710 if (!rc)
711 (void) no_memory("cbrdpaste()");
712 else {
713 /*
714 * Success. Fiddle with dot and mark again (another chunk of doput()
715 * code). "Tha' boy shore makes keen use of cut and paste."
716 * Don't swap if inserting - this allows you to continue typing
717 * after a paste operation without additional futzing with DOT.
718 */
719
720 if (!insertmode)
721 swapmark(); /* I understand this. */
722 if (is_header_line(DOT, curbp))
723 DOT.l = lback(DOT.l); /* This is a mystery. */
724 report_cbrdstats(nbyte, nline, TRUE);
725 }
726 returnCode(rc);
727 }
728
729 /*
730 * Map selected characters from the ANSI character set to their ASCII
731 * equivalents and insert same in the current buffer.
732 */
733 static int
map_and_insert(UINT c,UINT * nbyte)734 map_and_insert(UINT c, /* ANSI char to insert */
735 UINT * nbyte /* total #chars inserted */
736 )
737 {
738 W32_CHAR mapped_str[MAX_MAPPED_STR];
739 int i, nmapped, rc;
740
741 nmapped = map_cbrd_char(c, mapped_str);
742 *nbyte += nmapped;
743 for (rc = TRUE, i = 0; i < nmapped && rc; i++)
744 rc = lins_bytes(1, mapped_str[i]);
745 return (rc);
746 }
747
748 /* --------------------- Cut Functionality ----------------------- */
749
750 /*
751 * Cut current [win]vile selection to windows clipboard.
752 * Bound to Shift+Delete.
753 */
754 int
cbrdcut(int f GCC_UNUSED,int n GCC_UNUSED)755 cbrdcut(int f GCC_UNUSED, int n GCC_UNUSED)
756 {
757 return (w32_del_selection(TRUE));
758 }
759