Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/teraterm/teraterm/buffer.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10806 - (show annotations) (download) (as text)
Sun Jul 23 07:07:41 2023 UTC (8 months, 2 weeks ago) by zmatsuo
File MIME type: text/x-csrc
File size: 138881 byte(s)
文字を拡大縮小して描画できるようにした

- 拡大縮小して描画できるようにした
  - 2cell幅の文字を1cell幅に縮小して描画
  - 1cell幅の文字を2cell幅に拡大して描画,等
- フォントプロパティーページに設定を追加
  - "Drawing resized font to fit cell width" checkbox
- compat_win.cpp に TransparentBlt() (msimg32.dll) を追加
- ヘルプ追加(enはjaのコピー)
1 /*
2 * Copyright (C) 1994-1998 T. Teranishi
3 * (C) 2004- TeraTerm Project
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /* TERATERM.EXE, scroll buffer routines */
31
32 #include "teraterm.h"
33 #include <string.h>
34 #include <stdio.h>
35 #include <windows.h>
36 #define _CRTDBG_MAP_ALLOC
37 #include <crtdbg.h>
38 #include <assert.h>
39
40 #include "tttypes.h"
41 #include "ttwinman.h"
42 #include "teraprn.h"
43 #include "vtdisp.h"
44 #include "telnet.h"
45 #include "ttplug.h" /* TTPLUG */
46 #include "codeconv.h"
47 #include "unicode.h"
48 #include "buffer.h"
49 #include "asprintf.h"
50 #include "ttcstd.h"
51
52 #define ENABLE_CELL_INDEX 0
53
54 // �o�b�t�@�������p1������������
55 typedef struct {
56 char32_t u32;
57 char32_t u32_last;
58 char WidthProperty; // 'W' or 'F' or 'H' or 'A' or 'n'(Narrow) or 'N'(Neutual) (����������)
59 char cell; // ������cell�� 1/2/3+=���p,�S�p,3����
60 // 2�����������A����������������padding��cell-1������
61 char Padding; // TRUE = �S�p�������l���� or �s�����l����
62 char Emoji; // TRUE = �G����
63 unsigned char CombinationCharCount16; // charactor count
64 unsigned char CombinationCharSize16; // buffer size
65 unsigned char CombinationCharCount32;
66 unsigned char CombinationCharSize32;
67 wchar_t *pCombinationChars16;
68 char32_t *pCombinationChars32;
69 wchar_t wc2[2];
70 unsigned char fg;
71 unsigned char bg;
72 unsigned char attr;
73 unsigned char attr2;
74 unsigned short ansi_char;
75 #if ENABLE_CELL_INDEX
76 int idx; // �Z����������
77 #endif
78 } buff_char_t;
79
80 #define BuffXMax TermWidthMax
81 //#define BuffYMax 100000
82 //#define BuffSizeMax 8000000
83 // �X�N���[���o�b�t�@�����������g�� (2004.11.28 yutaka)
84 #define BuffYMax 500000
85 #define BuffSizeMax (BuffYMax * 80)
86
87 // 1�������������R���r�l�[�V�����o�b�t�@�����T�C�Y
88 #define MAX_CHAR_SIZE 100
89
90 // status line
91 int StatusLine; //0: none 1: shown
92 /* top, bottom, left & right margin */
93 int CursorTop, CursorBottom, CursorLeftM, CursorRightM;
94 static BOOL Selected; // TRUE=�����I�����s����������
95 static BOOL Selecting;
96 BOOL Wrap;
97
98 static WORD TabStops[256];
99 static int NTabStops;
100
101 static WORD BuffLock = 0;
102
103 static buff_char_t *CodeBuffW;
104 static LONG LinePtr;
105 static LONG BufferSize;
106 static int NumOfLinesInBuff;
107 static int BuffStartAbs, BuffEndAbs;
108 static POINT SelectStart, SelectStartTmp, SelectEnd, SelectEndOld;
109 static DWORD SelectStartTime;
110 static BOOL BoxSelect;
111 static POINT DblClkStart, DblClkEnd;
112
113 // �`��
114 static int StrChangeStart; // �`���J�n X (Y=CursorY)
115 static int StrChangeCount; // �`���L�����N�^��(���p�P��),0�������`����������������
116 static BOOL UseUnicodeApi;
117
118 static BOOL SeveralPageSelect; // add (2005.5.15 yutaka)
119
120 static TCharAttr CurCharAttr;
121
122 static char *SaveBuff = NULL;
123 static int SaveBuffX;
124 static int SaveBuffY;
125
126 // ANSI�\���p����������������CodePage
127 static int CodePage = 932;
128
129 static void BuffDrawLineI(int DrawX, int DrawY, int SY, int IStart, int IEnd);
130 static void BuffDrawLineIPrn(int SY, int IStart, int IEnd);
131
132 /**
133 * buff_char_t �� rel�Z����������
134 *
135 * @param CodeBuffW_ �����o�b�t�@�������|�C���^
136 * @param BufferSize_ �����o�b�t�@���T�C�Y(buff_char_t�P��)
137 * @param p �����������|�C���^
138 * @param rel ������
139 * @retval ���������|�C���^
140 */
141 static buff_char_t *GetPtrRel(buff_char_t *CodeBuffW_, size_t BufferSize_, buff_char_t *p, int rel)
142 {
143 ptrdiff_t idx = (ptrdiff_t)(p - CodeBuffW_) + rel;
144 for (;;) {
145 if (idx < 0) {
146 idx += BufferSize_;
147 }
148 else if (idx >= (ptrdiff_t)BufferSize_) {
149 idx -= BufferSize_;
150 }
151 else {
152 break;
153 }
154 }
155 p = &CodeBuffW_[(int)idx];
156 return p;
157 }
158
159 static void FreeCombinationBuf(buff_char_t *b)
160 {
161 if (b->pCombinationChars16 != NULL) {
162 free(b->pCombinationChars16);
163 b->pCombinationChars16 = NULL;
164 }
165 b->CombinationCharSize16 = 0;
166 b->CombinationCharCount16 = 0;
167
168 if (b->pCombinationChars32 != NULL) {
169 free(b->pCombinationChars32);
170 b->pCombinationChars32 = NULL;
171 }
172 b->CombinationCharSize32 = 0;
173 b->CombinationCharCount32 = 0;
174 }
175
176 static void DupCombinationBuf(buff_char_t *b)
177 {
178 size_t size;
179
180 size = b->CombinationCharSize16;
181 if (size > 0) {
182 wchar_t *new_buf = malloc(sizeof(wchar_t) * size);
183 memcpy(new_buf, b->pCombinationChars16, sizeof(wchar_t) * size);
184 b->pCombinationChars16 = new_buf;
185 }
186 size = b->CombinationCharSize32;
187 if (size > 0) {
188 char32_t *new_buf = malloc(sizeof(char32_t) * size);
189 memcpy(new_buf, b->pCombinationChars32, sizeof(char32_t) * size);
190 b->pCombinationChars32 = new_buf;
191 }
192 }
193
194 static void CopyCombinationBuf(buff_char_t *dest, const buff_char_t *src)
195 {
196 FreeCombinationBuf(dest);
197
198 // �\�������R�s�[����
199 #if ENABLE_CELL_INDEX
200 int idx = dest->idx;
201 #endif
202 *dest = *src;
203 #if ENABLE_CELL_INDEX
204 dest->idx = idx;
205 #endif
206
207 DupCombinationBuf(dest);
208 }
209
210 static void BuffSetChar2(buff_char_t *buff, char32_t u32, char property, BOOL half_width, char emoji)
211 {
212 size_t wstr_len;
213 buff_char_t *p = buff;
214
215 FreeCombinationBuf(p);
216 p->WidthProperty = property;
217 p->cell = half_width ? 1 : 2;
218 p->u32 = u32;
219 p->u32_last = u32;
220 p->Padding = FALSE;
221 p->Emoji = emoji;
222 p->fg = AttrDefaultFG;
223 p->bg = AttrDefaultBG;
224
225 //
226 wstr_len = UTF32ToUTF16(u32, &p->wc2[0], 2);
227 switch (wstr_len) {
228 case 0:
229 default:
230 p->wc2[0] = 0;
231 p->wc2[1] = 0;
232 break;
233 case 1:
234 p->wc2[1] = 0;
235 break;
236 case 2:
237 break;
238 }
239
240 if (u32 < 0x80) {
241 p->ansi_char = (unsigned short)u32;
242 }
243 else {
244 if (u32 == 0x203e && CodePage == 932) {
245 // U+203e OVERLINE ��������
246 // U+203e��0x7e'~'������
247 //p->ansi_char = 0x7e7e;
248 p->ansi_char = 0x7e;
249 }
250 else {
251 char strA[4];
252 size_t lenA = UTF32ToMBCP(u32, CodePage, strA, sizeof(strA));
253 switch (lenA) {
254 case 0:
255 default:
256 p->ansi_char = '?';
257 break;
258 case 1:
259 p->ansi_char = (unsigned char)strA[0];
260 break;
261 case 2:
262 p->ansi_char = (unsigned char)strA[1] | ((unsigned char)strA[0] << 8);
263 break;
264 }
265 }
266 }
267 }
268
269 static void BuffSetChar4(buff_char_t *buff, char32_t u32, unsigned char fg, unsigned char bg, unsigned char attr, unsigned char attr2, char property)
270 {
271 buff_char_t *p = buff;
272 BuffSetChar2(p, u32, property, TRUE, FALSE);
273 p->fg = fg;
274 p->bg = bg;
275 p->attr = attr;
276 p->attr2 = attr2;
277 }
278
279 static void BuffSetChar(buff_char_t *buff, char32_t u32, char property)
280 {
281 BuffSetChar2(buff, u32, property, TRUE, FALSE);
282 }
283
284 /**
285 * �����������A�R���r�l�[�V����
286 */
287 static void BuffAddChar(buff_char_t *buff, char32_t u32)
288 {
289 buff_char_t *p = buff;
290 assert(p->u32 != 0);
291 // �������������������g������
292 if (p->CombinationCharSize16 < p->CombinationCharCount16 + 2) {
293 size_t new_size = p->CombinationCharSize16;
294 new_size = new_size == 0 ? 5 : new_size * 2;
295 if (new_size > MAX_CHAR_SIZE) {
296 new_size = MAX_CHAR_SIZE;
297 }
298 if (p->CombinationCharSize16 != new_size) {
299 p->pCombinationChars16 = realloc(p->pCombinationChars16, sizeof(wchar_t) * new_size);
300 p->CombinationCharSize16 = (char)new_size;
301 }
302 }
303 if (p->CombinationCharSize32 < p->CombinationCharCount32 + 2) {
304 size_t new_size = p->CombinationCharSize32;
305 new_size = new_size == 0 ? 5 : new_size * 2;
306 if (new_size > MAX_CHAR_SIZE) {
307 new_size = MAX_CHAR_SIZE;
308 }
309 if (p->CombinationCharSize32 != new_size) {
310 p->pCombinationChars32 = realloc(p->pCombinationChars32, sizeof(char32_t) * new_size);
311 p->CombinationCharSize32 = (char)new_size;
312 }
313 }
314
315 // UTF-32
316 if (p->CombinationCharCount32 < p->CombinationCharSize32) {
317 p->u32_last = u32;
318 p->pCombinationChars32[(size_t)p->CombinationCharCount32] = u32;
319 p->CombinationCharCount32++;
320 }
321
322 // UTF-16
323 if (p->CombinationCharCount16 < p->CombinationCharSize16) {
324 wchar_t u16_str[2];
325 size_t wlen = UTF32ToUTF16(u32, &u16_str[0], 2);
326 if (p->CombinationCharCount16 + wlen <= p->CombinationCharSize16) {
327 size_t i = (size_t)p->CombinationCharCount16;
328 p->pCombinationChars16[i] = u16_str[0];
329 if (wlen == 2) {
330 i++;
331 p->pCombinationChars16[i] = u16_str[1];
332 }
333 p->CombinationCharCount16 += (unsigned char)wlen;
334 }
335 }
336 }
337
338 static void memcpyW(buff_char_t *dest, const buff_char_t *src, size_t count)
339 {
340 size_t i;
341
342 if (dest == src || count == 0) {
343 return;
344 }
345
346 for (i = 0; i < count; i++) {
347 CopyCombinationBuf(dest, src);
348 dest++;
349 src++;
350 }
351 }
352
353 static void memsetW(buff_char_t *dest, wchar_t ch, unsigned char fg, unsigned char bg, unsigned char attr, unsigned char attr2, size_t count)
354 {
355 size_t i;
356 for (i=0; i<count; i++) {
357 BuffSetChar(dest, ch, 'H');
358 dest->fg = fg;
359 dest->bg = bg;
360 dest->attr = attr;
361 dest->attr2 = attr2;
362 dest++;
363 }
364 }
365
366 static void memmoveW(buff_char_t *dest, const buff_char_t *src, size_t count)
367 {
368 size_t i;
369
370 if (dest == src || count == 0) {
371 return;
372 }
373
374
375 if (dest < src) {
376 // �O�����R�s�[����? -> memcpyW() ��ok
377 memcpyW(dest, src, count);
378 }
379 else {
380 // ���������R�s�[����
381 dest += count - 1;
382 src += count - 1;
383 for (i = 0; i < count; i++) {
384 CopyCombinationBuf(dest, src);
385 dest--;
386 src--;
387 }
388 }
389 }
390
391 static BOOL IsBuffPadding(const buff_char_t *b)
392 {
393 if (b->Padding == TRUE)
394 return TRUE;
395 if (b->u32 == 0)
396 return TRUE;
397 return FALSE;
398 }
399
400 static BOOL IsBuffFullWidth(const buff_char_t *b)
401 {
402 if (b->cell != 1)
403 return TRUE;
404 return FALSE;
405 }
406
407 static LONG GetLinePtr(int Line)
408 {
409 LONG Ptr;
410
411 Ptr = (LONG)(BuffStartAbs + Line) * (LONG)(NumOfColumns);
412 while (Ptr>=BufferSize) {
413 Ptr = Ptr - BufferSize;
414 }
415 return Ptr;
416 }
417
418 static LONG NextLinePtr(LONG Ptr)
419 {
420 Ptr = Ptr + (LONG)NumOfColumns;
421 if (Ptr >= BufferSize) {
422 Ptr = Ptr - BufferSize;
423 }
424 return Ptr;
425 }
426
427 static LONG PrevLinePtr(LONG Ptr)
428 {
429 Ptr = Ptr - (LONG)NumOfColumns;
430 if (Ptr < 0) {
431 Ptr = Ptr + BufferSize;
432 }
433 return Ptr;
434 }
435
436 /**
437 * �|�C���^�����u���� x,y ��������
438 */
439 static void GetPosFromPtr(const buff_char_t *b, int *bx, int *by)
440 {
441 size_t index = b - CodeBuffW;
442 int x = (int)(index % NumOfColumns);
443 int y = (int)(index / NumOfColumns);
444 if (y >= BuffStartAbs) {
445 y -= BuffStartAbs;
446 }
447 else {
448 y = y - BuffStartAbs + NumOfLinesInBuff;
449 }
450 *bx = x;
451 *by = y;
452 }
453
454 static BOOL ChangeBuffer(int Nx, int Ny)
455 {
456 LONG NewSize;
457 int NxCopy, NyCopy, i;
458 LONG SrcPtr, DestPtr;
459 WORD LockOld;
460 buff_char_t *CodeDestW;
461
462 if (Nx > BuffXMax) {
463 Nx = BuffXMax;
464 }
465 if (ts.ScrollBuffMax > BuffYMax) {
466 ts.ScrollBuffMax = BuffYMax;
467 }
468 if (Ny > ts.ScrollBuffMax) {
469 Ny = ts.ScrollBuffMax;
470 }
471
472 if ( (LONG)Nx * (LONG)Ny > BuffSizeMax ) {
473 Ny = BuffSizeMax / Nx;
474 }
475
476 NewSize = (LONG)Nx * (LONG)Ny;
477
478 CodeDestW = NULL;
479 CodeDestW = malloc(NewSize * sizeof(buff_char_t));
480 if (CodeDestW == NULL) {
481 goto allocate_error;
482 }
483
484 memset(&CodeDestW[0], 0, NewSize * sizeof(buff_char_t));
485 #if ENABLE_CELL_INDEX
486 {
487 int i;
488 for (i = 0; i < NewSize; i++) {
489 CodeDestW[i].idx = i;
490 }
491 }
492 #endif
493 memsetW(&CodeDestW[0], 0x20, AttrDefaultFG, AttrDefaultBG, AttrDefault, AttrDefault, NewSize);
494 if ( CodeBuffW != NULL ) {
495 if ( NumOfColumns > Nx ) {
496 NxCopy = Nx;
497 }
498 else {
499 NxCopy = NumOfColumns;
500 }
501
502 if ( BuffEnd > Ny ) {
503 NyCopy = Ny;
504 }
505 else {
506 NyCopy = BuffEnd;
507 }
508 LockOld = BuffLock;
509 LockBuffer();
510 SrcPtr = GetLinePtr(BuffEnd-NyCopy);
511 DestPtr = 0;
512 for (i = 1 ; i <= NyCopy ; i++) {
513 memcpyW(&CodeDestW[DestPtr],&CodeBuffW[SrcPtr],NxCopy);
514 if (CodeDestW[DestPtr+NxCopy-1].attr & AttrKanji) {
515 BuffSetChar(&CodeDestW[DestPtr + NxCopy - 1], ' ', 'H');
516 CodeDestW[DestPtr+NxCopy-1].attr ^= AttrKanji;
517 }
518 SrcPtr = NextLinePtr(SrcPtr);
519 DestPtr = DestPtr + (LONG)Nx;
520 }
521 FreeBuffer();
522 }
523 else {
524 LockOld = 0;
525 NyCopy = NumOfLines;
526 Selected = FALSE;
527 }
528
529 if (Selected) {
530 SelectStart.y = SelectStart.y - BuffEnd + NyCopy;
531 SelectEnd.y = SelectEnd.y - BuffEnd + NyCopy;
532 if (SelectStart.y < 0) {
533 SelectStart.y = 0;
534 SelectStart.x = 0;
535 }
536 if (SelectEnd.y<0) {
537 SelectEnd.x = 0;
538 SelectEnd.y = 0;
539 }
540
541 Selected = (SelectEnd.y > SelectStart.y) ||
542 ((SelectEnd.y == SelectStart.y) &&
543 (SelectEnd.x > SelectStart.x));
544 }
545
546 CodeBuffW = CodeDestW;
547 BufferSize = NewSize;
548 NumOfLinesInBuff = Ny;
549 BuffStartAbs = 0;
550 BuffEnd = NyCopy;
551
552 if (BuffEnd==NumOfLinesInBuff) {
553 BuffEndAbs = 0;
554 }
555 else {
556 BuffEndAbs = BuffEnd;
557 }
558
559 PageStart = BuffEnd - NumOfLines;
560
561 LinePtr = 0;
562 if (LockOld>0) {
563 }
564 else {
565 ;
566 }
567 BuffLock = LockOld;
568
569 return TRUE;
570
571 allocate_error:
572 if (CodeDestW) free(CodeDestW);
573 return FALSE;
574 }
575
576 void InitBuffer(BOOL use_unicode_api)
577 {
578 int Ny;
579
580 UseUnicodeApi = use_unicode_api;
581
582 /* setup terminal */
583 NumOfColumns = ts.TerminalWidth;
584 NumOfLines = ts.TerminalHeight;
585
586 if (NumOfColumns <= 0)
587 NumOfColumns = 80;
588 else if (NumOfColumns > TermWidthMax)
589 NumOfColumns = TermWidthMax;
590
591 if (NumOfLines <= 0)
592 NumOfLines = 24;
593 else if (NumOfLines > TermHeightMax)
594 NumOfLines = TermHeightMax;
595
596 /* setup window */
597 if (ts.EnableScrollBuff>0) {
598 if (ts.ScrollBuffSize < NumOfLines) {
599 ts.ScrollBuffSize = NumOfLines;
600 }
601 Ny = ts.ScrollBuffSize;
602 }
603 else {
604 Ny = NumOfLines;
605 }
606
607 if (! ChangeBuffer(NumOfColumns,Ny)) {
608 PostQuitMessage(0);
609 }
610
611 if (ts.EnableScrollBuff>0) {
612 ts.ScrollBuffSize = NumOfLinesInBuff;
613 }
614
615 StatusLine = 0;
616 }
617
618 static void NewLine(int Line)
619 {
620 LinePtr = GetLinePtr(Line);
621 }
622
623 void LockBuffer(void)
624 {
625 BuffLock++;
626 if (BuffLock>1) {
627 return;
628 }
629 NewLine(PageStart+CursorY);
630 }
631
632 void UnlockBuffer(void)
633 {
634 if (BuffLock==0) {
635 return;
636 }
637 BuffLock--;
638 if (BuffLock>0) {
639 return;
640 }
641 }
642
643 void FreeBuffer(void)
644 {
645 int i;
646
647 for (i = 0; i < NumOfColumns * NumOfLinesInBuff; i++) {
648 FreeCombinationBuf(&CodeBuffW[i]);
649 }
650
651 BuffLock = 1;
652 UnlockBuffer();
653 if (CodeBuffW != NULL) {
654 free(CodeBuffW);
655 CodeBuffW = NULL;
656 }
657 }
658
659 void BuffAllSelect(void)
660 {
661 SelectStart.x = 0;
662 SelectStart.y = 0;
663 SelectEnd.x = 0;
664 SelectEnd.y = BuffEnd;
665 // SelectEnd.x = NumOfColumns;
666 // SelectEnd.y = BuffEnd - 1;
667 Selecting = TRUE;
668 }
669
670 void BuffScreenSelect(void)
671 {
672 int X, Y;
673 DispConvWinToScreen(0, 0, &X, &Y, NULL);
674 SelectStart.x = X;
675 SelectStart.y = Y + PageStart;
676 SelectEnd.x = 0;
677 SelectEnd.y = SelectStart.y + NumOfLines;
678 // SelectEnd.x = X + NumOfColumns;
679 // SelectEnd.y = Y + PageStart + NumOfLines - 1;
680 Selecting = TRUE;
681 }
682
683 void BuffCancelSelection(void)
684 {
685 SelectStart.x = 0;
686 SelectStart.y = 0;
687 SelectEnd.x = 0;
688 SelectEnd.y = 0;
689 Selecting = FALSE;
690 }
691
692 void BuffReset(void)
693 // Reset buffer status. don't update real display
694 // called by ResetTerminal()
695 {
696 int i;
697
698 /* Cursor */
699 NewLine(PageStart);
700 WinOrgX = 0;
701 WinOrgY = 0;
702 NewOrgX = 0;
703 NewOrgY = 0;
704
705 /* Top/bottom margin */
706 CursorTop = 0;
707 CursorBottom = NumOfLines-1;
708 CursorLeftM = 0;
709 CursorRightM = NumOfColumns-1;
710
711 /* Tab stops */
712 NTabStops = (NumOfColumns-1) >> 3;
713 for (i=1 ; i<=NTabStops ; i++) {
714 TabStops[i-1] = (WORD)(i*8);
715 }
716
717 /* Initialize text selection region */
718 SelectStart.x = 0;
719 SelectStart.y = 0;
720 SelectEnd = SelectStart;
721 SelectEndOld = SelectStart;
722 Selected = FALSE;
723
724 StrChangeCount = 0;
725 Wrap = FALSE;
726 StatusLine = 0;
727
728 SeveralPageSelect = FALSE; // yutaka
729
730 /* Alternate Screen Buffer */
731 BuffDiscardSavedScreen();
732 }
733
734 static void BuffScroll(int Count, int Bottom)
735 {
736 int i, n;
737 LONG SrcPtr, DestPtr;
738 int BuffEndOld;
739
740 if (Count>NumOfLinesInBuff) {
741 Count = NumOfLinesInBuff;
742 }
743
744 DestPtr = GetLinePtr(PageStart+NumOfLines-1+Count);
745 n = Count;
746 if (Bottom<NumOfLines-1) {
747 SrcPtr = GetLinePtr(PageStart+NumOfLines-1);
748 for (i=NumOfLines-1; i>=Bottom+1; i--) {
749 memcpyW(&(CodeBuffW[DestPtr]),&(CodeBuffW[SrcPtr]),NumOfColumns);
750 memsetW(&(CodeBuffW[SrcPtr]),0x20,CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, NumOfColumns);
751 SrcPtr = PrevLinePtr(SrcPtr);
752 DestPtr = PrevLinePtr(DestPtr);
753 n--;
754 }
755 }
756 for (i = 1 ; i <= n ; i++) {
757 buff_char_t *b = &CodeBuffW[DestPtr];
758 memsetW(b ,0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, NumOfColumns);
759 DestPtr = PrevLinePtr(DestPtr);
760 }
761
762 BuffEndAbs = BuffEndAbs + Count;
763 if (BuffEndAbs >= NumOfLinesInBuff) {
764 BuffEndAbs = BuffEndAbs - NumOfLinesInBuff;
765 }
766 BuffEndOld = BuffEnd;
767 BuffEnd = BuffEnd + Count;
768 if (BuffEnd >= NumOfLinesInBuff) {
769 BuffEnd = NumOfLinesInBuff;
770 BuffStartAbs = BuffEndAbs;
771 }
772 PageStart = BuffEnd-NumOfLines;
773
774 if (Selected) {
775 SelectStart.y = SelectStart.y - Count + BuffEnd - BuffEndOld;
776 SelectEnd.y = SelectEnd.y - Count + BuffEnd - BuffEndOld;
777 if ( SelectStart.y<0 ) {
778 SelectStart.x = 0;
779 SelectStart.y = 0;
780 }
781 if ( SelectEnd.y<0 ) {
782 SelectEnd.x = 0;
783 SelectEnd.y = 0;
784 }
785 Selected = (SelectEnd.y > SelectStart.y) ||
786 ((SelectEnd.y==SelectStart.y) &&
787 (SelectEnd.x > SelectStart.x));
788 }
789
790 NewLine(PageStart+CursorY);
791 }
792
793 /**
794 * If cursor is on left/right half of a Kanji, erase it.
795 * @param LR left(0)/right(1) flag
796 * 0 �J�[�\��������������
797 * 1 �J�[�\�����������E��
798 * @return ��������cell��
799 * 0 ��������������
800 * 1,2 ��������
801 */
802 static int EraseKanji(int LR)
803 {
804 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
805 buff_char_t *p;
806 int bx;
807 int cell = 0;
808
809 if (CursorX < LR) {
810 // �S�p������������
811 return 0;
812 }
813 bx = CursorX-LR;
814 p = &CodeLineW[bx];
815 if (IsBuffFullWidth(p)) {
816 // �S�p��������
817 BuffSetChar(p, ' ', 'H');
818 p->attr = CurCharAttr.Attr;
819 p->attr2 = CurCharAttr.Attr2;
820 p->fg = CurCharAttr.Fore;
821 p->bg = CurCharAttr.Back;
822 if (bx+1 < NumOfColumns) {
823 BuffSetChar(p + 1, ' ', 'H');
824 (p+1)->attr = CurCharAttr.Attr;
825 (p+1)->attr2 = CurCharAttr.Attr2;
826 (p+1)->fg = CurCharAttr.Fore;
827 (p+1)->bg = CurCharAttr.Back;
828 cell = 2;
829 }
830 else {
831 cell = 1;
832 }
833 }
834 return cell;
835 }
836
837 static void EraseKanjiOnLRMargin(LONG ptr, int count)
838 {
839 int i;
840 LONG pos;
841
842 if (count < 1)
843 return;
844
845 for (i=0; i<count; i++) {
846 pos = ptr + CursorLeftM-1;
847 if (CursorLeftM>0 && (CodeBuffW[pos].attr & AttrKanji)) {
848 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
849 CodeBuffW[pos].attr &= ~AttrKanji;
850 pos++;
851 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
852 CodeBuffW[pos].attr &= ~AttrKanji;
853 }
854 pos = ptr + CursorRightM;
855 if (CursorRightM < NumOfColumns-1 && (CodeBuffW[pos].attr & AttrKanji)) {
856 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
857 CodeBuffW[pos].attr &= ~AttrKanji;
858 pos++;
859 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
860 CodeBuffW[pos].attr &= ~AttrKanji;
861 }
862 ptr = NextLinePtr(ptr);
863 }
864 }
865
866 // Insert space characters at the current position
867 // Count: Number of characters to be inserted
868 void BuffInsertSpace(int Count)
869 {
870 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
871 int MoveLen;
872 int extr = 0;
873 int sx;
874 buff_char_t *b;
875
876 if (CursorX < CursorLeftM || CursorX > CursorRightM)
877 return;
878
879 NewLine(PageStart + CursorY);
880
881 sx = CursorX;
882 b = &CodeLineW[CursorX];
883 if (IsBuffPadding(b)) {
884 /* if cursor is on right half of a kanji, erase the kanji */
885 BuffSetChar(b - 1, ' ', 'H');
886 BuffSetChar(b, ' ', 'H');
887 b->attr &= ~AttrKanji;
888 sx--;
889 extr++;
890 }
891
892 if (CursorRightM < NumOfColumns - 1 && (CodeLineW[CursorRightM].attr & AttrKanji)) {
893 BuffSetChar(&CodeLineW[CursorRightM + 1], 0x20, 'H');
894 CodeLineW[CursorRightM + 1].attr &= ~AttrKanji;
895 extr++;
896 }
897
898 if (Count > CursorRightM + 1 - CursorX)
899 Count = CursorRightM + 1 - CursorX;
900
901 MoveLen = CursorRightM + 1 - CursorX - Count;
902
903 if (MoveLen > 0) {
904 memmoveW(&(CodeLineW[CursorX + Count]), &(CodeLineW[CursorX]), MoveLen);
905 }
906 memsetW(&(CodeLineW[CursorX]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2, Count);
907 /* last char in current line is kanji first? */
908 if ((CodeLineW[CursorRightM].attr & AttrKanji) != 0) {
909 /* then delete it */
910 BuffSetChar(&CodeLineW[CursorRightM], 0x20, 'H');
911 CodeLineW[CursorRightM].attr &= ~AttrKanji;
912 }
913 BuffUpdateRect(sx, CursorY, CursorRightM + extr, CursorY);
914 }
915
916 /**
917 * Erase characters from cursor to the end of screen
918 */
919 void BuffEraseCurToEnd(void)
920 {
921 LONG TmpPtr;
922 int offset;
923 int i, YEnd;
924 int XStart = CursorX;
925 int head = 0;
926
927 NewLine(PageStart+CursorY);
928 /* if cursor is on right half of a kanji, erase the kanji */
929 if (EraseKanji(1) != 0) {
930 head = 1;
931 }
932 offset = CursorX;
933 TmpPtr = GetLinePtr(PageStart+CursorY);
934 YEnd = NumOfLines-1;
935 if (StatusLine && !isCursorOnStatusLine) {
936 YEnd--;
937 }
938 for (i = CursorY ; i <= YEnd ; i++) {
939 memsetW(&(CodeBuffW[TmpPtr+offset]),0x20,CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, NumOfColumns-offset);
940 offset = 0;
941 TmpPtr = NextLinePtr(TmpPtr);
942 }
943
944 /* update window */
945 if (head == 1) {
946 XStart--;
947 }
948 BuffDrawLineI(-1, -1, CursorY + PageStart, XStart, NumOfColumns);
949 for (i = CursorY + 1; i <= YEnd; i++) {
950 BuffDrawLineI(-1, -1, i + PageStart, 0, NumOfColumns);
951 }
952 }
953
954 /**
955 * Erase characters from home to cursor
956 */
957 void BuffEraseHomeToCur(void)
958 {
959 LONG TmpPtr;
960 int offset;
961 int i, YHome;
962 int tail = 0;
963 int draw_len;
964
965 NewLine(PageStart+CursorY);
966 /* if cursor is on left half of a kanji, erase the kanji */
967 if (EraseKanji(0) != 0) {
968 tail++;
969 }
970 offset = NumOfColumns;
971 if (isCursorOnStatusLine) {
972 YHome = CursorY;
973 }
974 else {
975 YHome = 0;
976 }
977 TmpPtr = GetLinePtr(PageStart+YHome);
978 for (i = YHome ; i <= CursorY ; i++) {
979 if (i==CursorY) {
980 offset = CursorX+1;
981 }
982 memsetW(&(CodeBuffW[TmpPtr]),0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, offset);
983 TmpPtr = NextLinePtr(TmpPtr);
984 }
985
986 /* update window */
987 draw_len = tail == 0 ? CursorX : CursorX + 1;
988 for (i = YHome; i < CursorY; i++) {
989 BuffDrawLineI(-1, -1, i + PageStart, 0, NumOfColumns);
990 }
991 BuffDrawLineI(-1, -1, CursorY + PageStart, 0, draw_len);
992 }
993
994 void BuffInsertLines(int Count, int YEnd)
995 // Insert lines at current position
996 // Count: number of lines to be inserted
997 // YEnd: bottom line number of scroll region (screen coordinate)
998 {
999 int i, linelen;
1000 int extl=0, extr=0;
1001 LONG SrcPtr, DestPtr;
1002
1003 BuffUpdateScroll();
1004
1005 if (CursorLeftM > 0)
1006 extl = 1;
1007 if (CursorRightM < NumOfColumns-1)
1008 extr = 1;
1009 if (extl || extr)
1010 EraseKanjiOnLRMargin(GetLinePtr(PageStart+CursorY), YEnd-CursorY+1);
1011
1012 SrcPtr = GetLinePtr(PageStart+YEnd-Count) + CursorLeftM;
1013 DestPtr = GetLinePtr(PageStart+YEnd) + CursorLeftM;
1014 linelen = CursorRightM - CursorLeftM + 1;
1015 for (i= YEnd-Count ; i>=CursorY ; i--) {
1016 memcpyW(&(CodeBuffW[DestPtr]), &(CodeBuffW[SrcPtr]), linelen);
1017 SrcPtr = PrevLinePtr(SrcPtr);
1018 DestPtr = PrevLinePtr(DestPtr);
1019 }
1020 for (i = 1 ; i <= Count ; i++) {
1021 memsetW(&(CodeBuffW[DestPtr]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, linelen);
1022 DestPtr = PrevLinePtr(DestPtr);
1023 }
1024
1025 if (CursorLeftM > 0 || CursorRightM < NumOfColumns-1 || !DispInsertLines(Count, YEnd)) {
1026 BuffUpdateRect(CursorLeftM-extl, CursorY, CursorRightM+extr, YEnd);
1027 }
1028 }
1029
1030 /**
1031 * erase characters in the current line
1032 * @param start position of erasing
1033 * @param Count: number of characters to be erased
1034 */
1035 void BuffEraseCharsInLine(int XStart, int Count)
1036 {
1037 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
1038 BOOL LineContinued=FALSE;
1039 int head = 0;
1040 int tail = 0;
1041
1042 if (ts.EnableContinuedLineCopy && XStart == 0 && (CodeLineW[0].attr & AttrLineContinued)) {
1043 LineContinued = TRUE;
1044 }
1045
1046 /* if cursor is on right half of a kanji, erase the kanji */
1047 if (EraseKanji(1) != 0) {
1048 head = 1;
1049 }
1050
1051 if (XStart + Count < NumOfColumns) {
1052 int CursorXSave = CursorX;
1053 CursorX = XStart + Count;
1054 if (EraseKanji(1) != 0) {
1055 tail = 1;
1056 }
1057 CursorX = CursorXSave;
1058 }
1059
1060 NewLine(PageStart+CursorY);
1061 memsetW(&(CodeLineW[XStart]),0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, Count);
1062
1063 if (ts.EnableContinuedLineCopy) {
1064 if (LineContinued) {
1065 BuffLineContinued(TRUE);
1066 }
1067
1068 if (XStart + Count >= NumOfColumns) {
1069 CodeBuffW[NextLinePtr(LinePtr)].attr &= ~AttrLineContinued;
1070 }
1071 }
1072
1073 if (head != 0) {
1074 XStart -= 1;
1075 Count += 1;
1076 }
1077 if (tail != 0) {
1078 Count += 1;
1079 }
1080 BuffDrawLineI(-1, -1, CursorY + PageStart, XStart, XStart + Count);
1081 }
1082
1083 void BuffDeleteLines(int Count, int YEnd)
1084 // Delete lines from current line
1085 // Count: number of lines to be deleted
1086 // YEnd: bottom line number of scroll region (screen coordinate)
1087 {
1088 int i, linelen;
1089 int extl=0, extr=0;
1090 LONG SrcPtr, DestPtr;
1091
1092 BuffUpdateScroll();
1093
1094 if (CursorLeftM > 0)
1095 extl = 1;
1096 if (CursorRightM < NumOfColumns-1)
1097 extr = 1;
1098 if (extl || extr)
1099 EraseKanjiOnLRMargin(GetLinePtr(PageStart+CursorY), YEnd-CursorY+1);
1100
1101 SrcPtr = GetLinePtr(PageStart+CursorY+Count) + (LONG)CursorLeftM;
1102 DestPtr = GetLinePtr(PageStart+CursorY) + (LONG)CursorLeftM;
1103 linelen = CursorRightM - CursorLeftM + 1;
1104 for (i=CursorY ; i<= YEnd-Count ; i++) {
1105 memcpyW(&(CodeBuffW[DestPtr]), &(CodeBuffW[SrcPtr]), linelen);
1106 SrcPtr = NextLinePtr(SrcPtr);
1107 DestPtr = NextLinePtr(DestPtr);
1108 }
1109 for (i = YEnd+1-Count ; i<=YEnd ; i++) {
1110 memsetW(&(CodeBuffW[DestPtr]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, linelen);
1111 DestPtr = NextLinePtr(DestPtr);
1112 }
1113
1114 if (CursorLeftM > 0 || CursorRightM < NumOfColumns-1 || ! DispDeleteLines(Count,YEnd)) {
1115 BuffUpdateRect(CursorLeftM-extl, CursorY, CursorRightM+extr, YEnd);
1116 }
1117 }
1118
1119 // Delete characters in current line from cursor
1120 // Count: number of characters to be deleted
1121 void BuffDeleteChars(int Count)
1122 {
1123 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
1124 int MoveLen;
1125 int extr = 0;
1126 buff_char_t *b;
1127
1128 if (Count > CursorRightM + 1 - CursorX)
1129 Count = CursorRightM + 1 - CursorX;
1130
1131 if (CursorX < CursorLeftM || CursorX > CursorRightM)
1132 return;
1133
1134 NewLine(PageStart + CursorY);
1135
1136 b = &CodeLineW[CursorX];
1137
1138 if (IsBuffPadding(b)) {
1139 // �S�p���E���A�S�p���X�y�[�X���u��������
1140 BuffSetChar(b - 1, ' ', 'H');
1141 BuffSetChar(b, ' ', 'H');
1142 }
1143 if (IsBuffFullWidth(b)) {
1144 // �S�p�������A�S�p���X�y�[�X���u��������
1145 BuffSetChar(b, ' ', 'H');
1146 BuffSetChar(b + 1, ' ', 'H');
1147 }
1148 if (Count > 1) {
1149 // �I�[���`�F�b�N
1150 if (IsBuffPadding(b + Count)) {
1151 // �S�p���E���A�S�p���X�y�[�X���u��������
1152 BuffSetChar(b + Count - 1, ' ', 'H');
1153 BuffSetChar(b + Count, ' ', 'H');
1154 }
1155 }
1156
1157 if (CursorRightM < NumOfColumns - 1 && (CodeLineW[CursorRightM].attr & AttrKanji)) {
1158 BuffSetChar(&CodeLineW[CursorRightM], 0x20, 'H');
1159 CodeLineW[CursorRightM].attr &= ~AttrKanji;
1160 BuffSetChar(&CodeLineW[CursorRightM + 1], 0x20, 'H');
1161 CodeLineW[CursorRightM + 1].attr &= ~AttrKanji;
1162 extr = 1;
1163 }
1164
1165 MoveLen = CursorRightM + 1 - CursorX - Count;
1166
1167 if (MoveLen > 0) {
1168 memmoveW(&(CodeLineW[CursorX]), &(CodeLineW[CursorX + Count]), MoveLen);
1169 }
1170 memsetW(&(CodeLineW[CursorX + MoveLen]), ' ', CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, Count);
1171
1172 BuffUpdateRect(CursorX, CursorY, CursorRightM + extr, CursorY);
1173 }
1174
1175 /**
1176 * Erase characters in current line from cursor
1177 * @param Count number of characters to be deleted
1178 */
1179 void BuffEraseChars(int Count)
1180 {
1181 BuffEraseCharsInLine(CursorX, Count);
1182 }
1183
1184 void BuffFillWithE(void)
1185 // Fill screen with 'E' characters
1186 {
1187 LONG TmpPtr;
1188 int i;
1189
1190 TmpPtr = GetLinePtr(PageStart);
1191 for (i = 0 ; i <= NumOfLines-1-StatusLine ; i++) {
1192 memsetW(&(CodeBuffW[TmpPtr]),'E', AttrDefaultFG, AttrDefaultBG, AttrDefault, AttrDefault, NumOfColumns);
1193 TmpPtr = NextLinePtr(TmpPtr);
1194 }
1195 BuffUpdateRect(WinOrgX,WinOrgY,WinOrgX+WinWidth-1,WinOrgY+WinHeight-1);
1196 }
1197
1198 void BuffDrawLine(TCharAttr Attr, int Direction, int C)
1199 { // IO-8256 terminal
1200 LONG Ptr;
1201 int i, X, Y;
1202
1203 if (C==0) {
1204 return;
1205 }
1206 Attr.Attr |= AttrSpecial;
1207
1208 switch (Direction) {
1209 case 3:
1210 case 4:
1211 if (Direction==3) {
1212 if (CursorY==0) {
1213 return;
1214 }
1215 Y = CursorY-1;
1216 }
1217 else {
1218 if (CursorY==NumOfLines-1-StatusLine) {
1219 return;
1220 }
1221 Y = CursorY+1;
1222 }
1223 if (CursorX+C > NumOfColumns) {
1224 C = NumOfColumns-CursorX;
1225 }
1226 Ptr = GetLinePtr(PageStart+Y);
1227 memsetW(&(CodeBuffW[Ptr+CursorX]),'q', Attr.Fore, Attr.Back, Attr.Attr, Attr.Attr2, C);
1228 BuffUpdateRect(CursorX,Y,CursorX+C-1,Y);
1229 break;
1230 case 5:
1231 case 6:
1232 if (Direction==5) {
1233 if (CursorX==0) {
1234 return;
1235 }
1236 X = CursorX - 1;
1237 }
1238 else {
1239 if (CursorX==NumOfColumns-1) {
1240 X = CursorX-1;
1241 }
1242 else {
1243 X = CursorX+1;
1244 }
1245 }
1246 Ptr = GetLinePtr(PageStart+CursorY);
1247 if (CursorY+C > NumOfLines-StatusLine) {
1248 C = NumOfLines-StatusLine-CursorY;
1249 }
1250 for (i=1; i<=C; i++) {
1251 BuffSetChar4(&CodeBuffW[Ptr+X], 'x', Attr.Fore, Attr.Back, Attr.Attr, Attr.Attr2, 'H');
1252 Ptr = NextLinePtr(Ptr);
1253 }
1254 BuffUpdateRect(X,CursorY,X,CursorY+C-1);
1255 break;
1256 }
1257 }
1258
1259 void BuffEraseBox(int XStart, int YStart, int XEnd, int YEnd)
1260 {
1261 int C, i;
1262 LONG Ptr;
1263
1264 if (XEnd>NumOfColumns-1) {
1265 XEnd = NumOfColumns-1;
1266 }
1267 if (YEnd>NumOfLines-1-StatusLine) {
1268 YEnd = NumOfLines-1-StatusLine;
1269 }
1270 if (XStart>XEnd) {
1271 return;
1272 }
1273 if (YStart>YEnd) {
1274 return;
1275 }
1276 C = XEnd-XStart+1;
1277 Ptr = GetLinePtr(PageStart+YStart);
1278 for (i=YStart; i<=YEnd; i++) {
1279 if ((XStart>0) &&
1280 ((CodeBuffW[Ptr+XStart-1].attr & AttrKanji) != 0)) {
1281 BuffSetChar4(&CodeBuffW[Ptr+XStart-1], 0x20, CurCharAttr.Fore, CurCharAttr.Back, CurCharAttr.Attr, CurCharAttr.Attr2, 'H');
1282 }
1283 if ((XStart+C<NumOfColumns) &&
1284 ((CodeBuffW[Ptr+XStart+C-1].attr & AttrKanji) != 0)) {
1285 BuffSetChar4(&CodeBuffW[Ptr+XStart+C], 0x20, CurCharAttr.Fore, CurCharAttr.Back, CurCharAttr.Attr, CurCharAttr.Attr2, 'H');
1286 }
1287 memsetW(&(CodeBuffW[Ptr+XStart]),0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, C);
1288 Ptr = NextLinePtr(Ptr);
1289 }
1290 BuffUpdateRect(XStart,YStart,XEnd,YEnd);
1291 }
1292
1293 void BuffFillBox(char ch, int XStart, int YStart, int XEnd, int YEnd)
1294 {
1295 int Cols, i;
1296 LONG Ptr;
1297
1298 if (XEnd>NumOfColumns-1) {
1299 XEnd = NumOfColumns-1;
1300 }
1301 if (YEnd>NumOfLines-1-StatusLine) {
1302 YEnd = NumOfLines-1-StatusLine;
1303 }
1304 if (XStart>XEnd) {
1305 return;
1306 }
1307 if (YStart>YEnd) {
1308 return;
1309 }
1310 Cols = XEnd-XStart+1;
1311 Ptr = GetLinePtr(PageStart+YStart);
1312 for (i=YStart; i<=YEnd; i++) {
1313 if ((XStart>0) &&
1314 ((CodeBuffW[Ptr+XStart-1].attr & AttrKanji) != 0)) {
1315 BuffSetChar(&CodeBuffW[Ptr + XStart - 1], 0x20, 'H');
1316 CodeBuffW[Ptr+XStart-1].attr ^= AttrKanji;
1317 }
1318 if ((XStart+Cols<NumOfColumns) &&
1319 ((CodeBuffW[Ptr+XStart+Cols-1].attr & AttrKanji) != 0)) {
1320 BuffSetChar(&CodeBuffW[Ptr + XStart + Cols], 0x20, 'H');
1321 }
1322 memsetW(&(CodeBuffW[Ptr+XStart]), ch, CurCharAttr.Fore, CurCharAttr.Back, CurCharAttr.Attr, CurCharAttr.Attr2, Cols);
1323 Ptr = NextLinePtr(Ptr);
1324 }
1325 BuffUpdateRect(XStart, YStart, XEnd, YEnd);
1326 }
1327
1328 //
1329 // TODO: 1 origin �������������� 0 origin ������
1330 //
1331 void BuffCopyBox(
1332 int SrcXStart, int SrcYStart, int SrcXEnd, int SrcYEnd, int SrcPage,
1333 int DstX, int DstY, int DstPage)
1334 {
1335 int i, C, L;
1336 LONG SPtr, DPtr;
1337
1338 SrcXStart--;
1339 SrcYStart--;
1340 SrcXEnd--;
1341 SrcYEnd--;
1342 SrcPage--;
1343 DstX--;
1344 DstY--;
1345 DstPage--;
1346
1347 if (SrcXEnd > NumOfColumns - 1) {
1348 SrcXEnd = NumOfColumns-1;
1349 }
1350 if (SrcYEnd > NumOfLines-1-StatusLine) {
1351 SrcYEnd = NumOfColumns-1;
1352 }
1353 if (SrcXStart > SrcXEnd ||
1354 SrcYStart > SrcYEnd ||
1355 DstX > NumOfColumns-1 ||
1356 DstY > NumOfLines-1-StatusLine) {
1357 return;
1358 }
1359
1360 C = SrcXEnd - SrcXStart + 1;
1361 if (DstX + C > NumOfColumns) {
1362 C = NumOfColumns - DstX;
1363 }
1364 L = SrcYEnd - SrcYStart + 1;
1365 if (DstY + C > NumOfColumns) {
1366 C = NumOfColumns - DstX;
1367 }
1368
1369 if (SrcXStart > DstX) {
1370 SPtr = GetLinePtr(PageStart+SrcYStart);
1371 DPtr = GetLinePtr(PageStart+DstY);
1372 for (i=0; i<L; i++) {
1373 memcpyW(&(CodeBuffW[DPtr+DstX]), &(CodeBuffW[SPtr+SrcXStart]), C);
1374 SPtr = NextLinePtr(SPtr);
1375 DPtr = NextLinePtr(DPtr);
1376 }
1377 }
1378 else if (SrcXStart < DstX) {
1379 SPtr = GetLinePtr(PageStart+SrcYEnd);
1380 DPtr = GetLinePtr(PageStart+DstY+L-1);
1381 for (i=L; i>0; i--) {
1382 memcpyW(&(CodeBuffW[DPtr+DstX]), &(CodeBuffW[SPtr+SrcXStart]), C);
1383 SPtr = PrevLinePtr(SPtr);
1384 DPtr = PrevLinePtr(DPtr);
1385 }
1386 }
1387 else if (SrcYStart != DstY) {
1388 SPtr = GetLinePtr(PageStart+SrcYStart);
1389 DPtr = GetLinePtr(PageStart+DstY);
1390 for (i=0; i<L; i++) {
1391 memmoveW(&(CodeBuffW[DPtr+DstX]), &(CodeBuffW[SPtr+SrcXStart]), C);
1392 SPtr = NextLinePtr(SPtr);
1393 DPtr = NextLinePtr(DPtr);
1394 }
1395 }
1396 BuffUpdateRect(DstX,DstY,DstX+C-1,DstY+L-1);
1397 }
1398
1399 void BuffChangeAttrBox(int XStart, int YStart, int XEnd, int YEnd, PCharAttr attr, PCharAttr mask)
1400 {
1401 int C, i, j;
1402 LONG Ptr;
1403
1404 if (XEnd>NumOfColumns-1) {
1405 XEnd = NumOfColumns-1;
1406 }
1407 if (YEnd>NumOfLines-1-StatusLine) {
1408 YEnd = NumOfLines-1-StatusLine;
1409 }
1410 if (XStart>XEnd || YStart>YEnd) {
1411 return;
1412 }
1413 C = XEnd-XStart+1;
1414 Ptr = GetLinePtr(PageStart+YStart);
1415
1416 if (mask) { // DECCARA
1417 for (i=YStart; i<=YEnd; i++) {
1418 j = Ptr+XStart-1;
1419 if (XStart>0 && (CodeBuffW[j].attr & AttrKanji)) {
1420 CodeBuffW[j].attr = (CodeBuffW[j].attr & ~mask->Attr) | attr->Attr;
1421 CodeBuffW[j].attr2 = (CodeBuffW[j].attr2 & ~mask->Attr2) | attr->Attr2;
1422 if (mask->Attr2 & Attr2Fore) { CodeBuffW[j].fg = attr->Fore; }
1423 if (mask->Attr2 & Attr2Back) { CodeBuffW[j].bg = attr->Back; }
1424 }
1425 while (++j < Ptr+XStart+C) {
1426 CodeBuffW[j].attr = (CodeBuffW[j].attr & ~mask->Attr) | attr->Attr;
1427 CodeBuffW[j].attr2 = (CodeBuffW[j].attr2 & ~mask->Attr2) | attr->Attr2;
1428 if (mask->Attr2 & Attr2Fore) { CodeBuffW[j].fg = attr->Fore; }
1429 if (mask->Attr2 & Attr2Back) { CodeBuffW[j].bg = attr->Back; }
1430 }
1431 if (XStart+C<NumOfColumns && (CodeBuffW[j-1].attr & AttrKanji)) {
1432 CodeBuffW[j].attr = (CodeBuffW[j].attr & ~mask->Attr) | attr->Attr;
1433 CodeBuffW[j].attr2 = (CodeBuffW[j].attr2 & ~mask->Attr2) | attr->Attr2;
1434 if (mask->Attr2 & Attr2Fore) { CodeBuffW[j].fg = attr->Fore; }
1435 if (mask->Attr2 & Attr2Back) { CodeBuffW[j].bg = attr->Back; }
1436 }
1437 Ptr = NextLinePtr(Ptr);
1438 }
1439 }
1440 else { // DECRARA
1441 for (i=YStart; i<=YEnd; i++) {
1442 j = Ptr+XStart-1;
1443 if (XStart>0 && (CodeBuffW[j].attr & AttrKanji)) {
1444 CodeBuffW[j].attr ^= attr->Attr;
1445 }
1446 while (++j < Ptr+XStart+C) {
1447 CodeBuffW[j].attr ^= attr->Attr;
1448 }
1449 if (XStart+C<NumOfColumns && (CodeBuffW[j-1].attr & AttrKanji)) {
1450 CodeBuffW[j].attr ^= attr->Attr;
1451 }
1452 Ptr = NextLinePtr(Ptr);
1453 }
1454 }
1455 BuffUpdateRect(XStart, YStart, XEnd, YEnd);
1456 }
1457
1458 void BuffChangeAttrStream(int XStart, int YStart, int XEnd, int YEnd, PCharAttr attr, PCharAttr mask)
1459 {
1460 int i, j, endp;
1461 LONG Ptr;
1462
1463 if (XEnd>NumOfColumns-1) {
1464 XEnd = NumOfColumns-1;
1465 }
1466 if (YEnd>NumOfLines-1-StatusLine) {
1467 YEnd = NumOfLines-1-StatusLine;
1468 }
1469 if (XStart>XEnd || YStart>YEnd) {
1470 return;
1471 }
1472
1473 Ptr = GetLinePtr(PageStart+YStart);
1474
1475 if (mask) { // DECCARA
1476 if (YStart == YEnd) {
1477 i = Ptr + XStart - 1;
1478 endp = Ptr + XEnd + 1;
1479
1480 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1481 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1482 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1483 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1484 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1485 }
1486 while (++i < endp) {
1487 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1488 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1489 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1490 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1491 }
1492 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1493 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1494 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1495 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1496 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1497 }
1498 }
1499 else {
1500 i = Ptr + XStart - 1;
1501 endp = Ptr + NumOfColumns;
1502
1503 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1504 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1505 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1506 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1507 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1508 }
1509 while (++i < endp) {
1510 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1511 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1512 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1513 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1514 }
1515
1516 for (j=0; j < YEnd-YStart-1; j++) {
1517 Ptr = NextLinePtr(Ptr);
1518 i = Ptr;
1519 endp = Ptr + NumOfColumns;
1520
1521 while (i < endp) {
1522 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1523 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1524 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1525 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1526 i++;
1527 }
1528 }
1529
1530 Ptr = NextLinePtr(Ptr);
1531 i = Ptr;
1532 endp = Ptr + XEnd + 1;
1533
1534 while (i < endp) {
1535 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1536 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1537 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1538 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1539 i++;
1540 }
1541 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1542 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1543 CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1544 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1545 if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1546 }
1547 }
1548 }
1549 else { // DECRARA
1550 if (YStart == YEnd) {
1551 i = Ptr + XStart - 1;
1552 endp = Ptr + XEnd + 1;
1553
1554 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1555 CodeBuffW[i].attr ^= attr->Attr;
1556 }
1557 while (++i < endp) {
1558 CodeBuffW[i].attr ^= attr->Attr;
1559 }
1560 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1561 CodeBuffW[i].attr ^= attr->Attr;
1562 }
1563 }
1564 else {
1565 i = Ptr + XStart - 1;
1566 endp = Ptr + NumOfColumns;
1567
1568 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1569 CodeBuffW[i].attr ^= attr->Attr;
1570 }
1571 while (++i < endp) {
1572 CodeBuffW[i].attr ^= attr->Attr;
1573 }
1574
1575 for (j=0; j < YEnd-YStart-1; j++) {
1576 Ptr = NextLinePtr(Ptr);
1577 i = Ptr;
1578 endp = Ptr + NumOfColumns;
1579
1580 while (i < endp) {
1581 CodeBuffW[i].attr ^= attr->Attr;
1582 i++;
1583 }
1584 }
1585
1586 Ptr = NextLinePtr(Ptr);
1587 i = Ptr;
1588 endp = Ptr + XEnd + 1;
1589
1590 while (i < endp) {
1591 CodeBuffW[i].attr ^= attr->Attr;
1592 i++;
1593 }
1594 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1595 CodeBuffW[i].attr ^= attr->Attr;
1596 }
1597 Ptr = NextLinePtr(Ptr);
1598 }
1599 }
1600 BuffUpdateRect(0, YStart, NumOfColumns-1, YEnd);
1601 }
1602
1603 /**
1604 * (Line,CharPtr)���u���S�p���E��(��������N cell��1cell����������)����
1605 * ���������������u������
1606 *
1607 * If CharPtr is on the right half of a DBCS character
1608 * return pointer to the left half
1609 *
1610 * @param Line points to a line in CodeBuff
1611 * @param CharPtr points to a char
1612 * @return points to the left half of the DBCS
1613 */
1614 static int LeftHalfOfDBCS(LONG Line, int CharPtr)
1615 {
1616 int x = CharPtr;
1617 while(x > 0) {
1618 if ((CodeBuffW[Line+x].Padding) == FALSE) {
1619 // padding��������
1620 break;
1621 }
1622 assert(x > 0); // �s���� padding?
1623 x--;
1624 }
1625 return x;
1626 }
1627
1628 static int MoveCharPtr(LONG Line, int *x, int dx)
1629 // move character pointer x by dx character unit
1630 // in the line specified by Line
1631 // Line: points to a line in CodeBuff
1632 // x: points to a character in the line
1633 // dx: moving distance in character unit (-: left, +: right)
1634 // One DBCS character is counted as one character.
1635 // The pointer stops at the beginning or the end of line.
1636 // Output
1637 // x: new pointer. x points to a SBCS character or
1638 // the left half of a DBCS character.
1639 // return: actual moving distance in character unit
1640 {
1641 int i;
1642
1643 *x = LeftHalfOfDBCS(Line,*x);
1644 i = 0;
1645 while (dx!=0) {
1646 if (dx>0) { // move right
1647 if ((CodeBuffW[Line+*x].attr & AttrKanji) != 0) {
1648 if (*x<NumOfColumns-2) {
1649 i++;
1650 *x = *x + 2;
1651 }
1652 }
1653 else if (*x<NumOfColumns-1) {
1654 i++;
1655 (*x)++;
1656 }
1657 dx--;
1658 }
1659 else { // move left
1660 if (*x>0) {
1661 i--;
1662 (*x)--;
1663 }
1664 *x = LeftHalfOfDBCS(Line,*x);
1665 dx++;
1666 }
1667 }
1668 return i;
1669 }
1670
1671 /**
1672 * (�N���b�v�{�[�h�p��)������������
1673 * @param[in] sx,sy,ex,ey �I������
1674 * @param[in] box_select TRUE=���^(���`)�I��
1675 * FALSE=�s�I��
1676 * @param[out] _str_len ��������(�����[L'\0'������)
1677 * NULL����������������
1678 * @return ������
1679 * �g�p���� free() ��������
1680 */
1681 static wchar_t *BuffGetStringForCB(int sx, int sy, int ex, int ey, BOOL box_select, size_t *_str_len)
1682 {
1683 wchar_t *str_w;
1684 size_t str_size; // �m�������T�C�Y
1685 size_t k;
1686 LONG TmpPtr;
1687 int x, y;
1688
1689 str_size = (NumOfColumns + 2) * (ey - sy + 1);
1690 str_w = malloc(sizeof(wchar_t) * str_size);
1691
1692 LockBuffer();
1693
1694 str_w[0] = 0;
1695 TmpPtr = GetLinePtr(sy);
1696 k = 0;
1697 for (y = sy; y<=ey ; y++) {
1698 int IStart; // �J�n
1699 int IEnd; // �I��
1700 BOOL LineContinued;
1701
1702 if (box_select) {
1703 IStart = sx;
1704 IEnd = ex - 1;
1705 LineContinued = FALSE;
1706 }
1707 else {
1708 // �s�I��
1709 IStart = (y == sy) ? sx : 0;
1710 LineContinued = FALSE;
1711 if (y == ey) {
1712 // 1�s�I�����A����
1713 // �����s�I�������������s
1714 IEnd = ex - 1;
1715 }
1716 else {
1717 // �����s�I�������r�����s
1718 // �s�������I������������
1719 IEnd = NumOfColumns - 1;
1720
1721 // �p���s�R�s�[����
1722 if (ts.EnableContinuedLineCopy) {
1723 LONG NextTmpPtr = NextLinePtr(TmpPtr);
1724 if ((CodeBuffW[NextTmpPtr].attr & AttrLineContinued) != 0) {
1725 // �����s���p����������
1726 LineContinued = TRUE;
1727 }
1728 }
1729 }
1730 }
1731
1732 // IEnd=�R�s�[���K�v�����������u
1733 if (LineContinued) {
1734 // �s���������������R�s�[����
1735 IEnd++;
1736 }
1737 else {
1738 // �����s���p�����������������A�X�y�[�X����������
1739 while (IEnd >= IStart) {
1740 // �R�s�[�s�v��" "(0x20)������
1741 const buff_char_t *b = &CodeBuffW[TmpPtr + IEnd];
1742 if (b->u32 != 0x20) {
1743 // �X�y�[�X���O������
1744 IEnd++;
1745 break;
1746 }
1747 if (IEnd == 0) {
1748 break;
1749 }
1750 // �����l����
1751 MoveCharPtr(TmpPtr,&IEnd,-1);
1752 }
1753 }
1754
1755 // 1���C�����������R�s�[����
1756 // IEnd=�R�s�[���K�v�����������u+1
1757 x = IStart;
1758 while (x < IEnd) {
1759 const buff_char_t *b = &CodeBuffW[TmpPtr + x];
1760 if (b->u32 != 0) {
1761 str_w[k++] = b->wc2[0];
1762 if (b->wc2[1] != 0) {
1763 str_w[k++] = b->wc2[1];
1764 }
1765 if (k + 2 >= str_size) {
1766 str_size *= 2;
1767 str_w = realloc(str_w, sizeof(wchar_t) * str_size);
1768 }
1769 {
1770 int i;
1771 // �R���r�l�[�V����
1772 if (k + b->CombinationCharCount16 >= str_size) {
1773 str_size += + b->CombinationCharCount16;
1774 str_w = realloc(str_w, sizeof(wchar_t) * str_size);
1775 }
1776 for (i = 0 ; i < (int)b->CombinationCharCount16; i++) {
1777 str_w[k++] = b->pCombinationChars16[i];
1778 }
1779 }
1780 }
1781 x++;
1782 }
1783
1784 if (y < ey) {
1785 // ���s��������(�������s���O������)
1786 if (!LineContinued) {
1787 str_w[k++] = 0x0d;
1788 str_w[k++] = 0x0a;
1789 }
1790 }
1791
1792 TmpPtr = NextLinePtr(TmpPtr);
1793 }
1794 str_w[k++] = 0;
1795
1796 UnlockBuffer();
1797
1798 if (_str_len != NULL) {
1799 *_str_len = k;
1800 }
1801 return str_w;
1802 }
1803
1804 /**
1805 * 1�Z������wchar_t���������W�J����
1806 * @param[in] b 1�Z�������������������|�C���^
1807 * @param[in,out] buf �������W�J�� NULL���������W�J��������
1808 * @param[in] buf_size buf��������(buff == NULL���������Q����������)
1809 * @param[out] too_small NULL ��������������������
1810 * TRUE �o�b�t�@�T�C�Y�s��
1811 * �����l���K�v��������������
1812 * FALSE �������W�J������
1813 * @retrun ������ �o��������
1814 * 0�������A�����o������
1815 *
1816 * TODO
1817 * GetWCS() ������?
1818 */
1819 static size_t expand_wchar(const buff_char_t *b, wchar_t *buf, size_t buf_size, BOOL *too_samll)
1820 {
1821 size_t len;
1822
1823 if (IsBuffPadding(b)) {
1824 if (too_samll != NULL) {
1825 *too_samll = FALSE;
1826 }
1827 return 0;
1828 }
1829
1830 // ����������
1831 len = 0;
1832 if (b->wc2[1] == 0) {
1833 // �T���Q�[�g�y�A��������
1834 len++;
1835 } else {
1836 // �T���Q�[�g�y�A
1837 len += 2;
1838 }
1839 // �R���r�l�[�V����
1840 len += b->CombinationCharCount16;
1841
1842 if (buf == NULL) {
1843 // ��������������
1844 return len;
1845 }
1846
1847 // �o�b�t�@��������?
1848 if (len > buf_size) {
1849 // �o�b�t�@������������
1850 if (too_samll != NULL) {
1851 *too_samll = TRUE;
1852 }
1853 return len;
1854 }
1855 if (too_samll != NULL) {
1856 *too_samll = FALSE;
1857 }
1858
1859 // �W�J��������
1860 *buf++ = b->wc2[0];
1861 if (b->wc2[1] != 0) {
1862 *buf++ = b->wc2[1];
1863 }
1864 if (b->CombinationCharCount16 != 0) {
1865 memcpy(buf, b->pCombinationChars16, b->CombinationCharCount16 * sizeof(wchar_t));
1866 }
1867
1868 return len;
1869 }
1870
1871 /**
1872 * (x,y) ��1������ str��������������
1873 * *�� 1������������wchar_t�����\������������
1874 *
1875 * @param b
1876 * @param str ���r������(wchar_t)
1877 * @param len ���r��������
1878 * @retval �}�b�`������������
1879 * 0=�}�b�`����������
1880 */
1881 static size_t MatchOneStringPtr(const buff_char_t *b, const wchar_t *str, size_t len)
1882 {
1883 int match_pos = 0;
1884 if (len == 0) {
1885 return 0;
1886 }
1887 if (b->wc2[1] == 0) {
1888 // �T���Q�[�g�y�A��������
1889 if (str[match_pos] != b->wc2[0]) {
1890 return 0;
1891 }
1892 match_pos++;
1893 len--;
1894 } else {
1895 // �T���Q�[�g�y�A
1896 if (len < 2) {
1897 return 0;
1898 }
1899 if (str[match_pos+0] != b->wc2[0] ||
1900 str[match_pos+1] != b->wc2[1]) {
1901 return 0;
1902 }
1903 match_pos+=2;
1904 len-=2;
1905 }
1906 if (b->CombinationCharCount16 > 0) {
1907 // �R���r�l�[�V����
1908 int i;
1909 if (len < b->CombinationCharCount16) {
1910 return 0;
1911 }
1912 for (i = 0 ; i < (int)b->CombinationCharCount16; i++) {
1913 if (str[match_pos++] != b->pCombinationChars16[i]) {
1914 return 0;
1915 }
1916 }
1917 len -= b->CombinationCharCount16;
1918 }
1919 return match_pos;
1920 }
1921
1922 /**
1923 * (x,y) ��1������ str��������������
1924 * *�� 1������������wchar_t�����\������������
1925 *
1926 * @param y PageStart + CursorY
1927 * @param str 1����(wchar_t��)
1928 * @param len ��������
1929 * @retval 0=�}�b�`����������
1930 * �}�b�`������������
1931 */
1932 static size_t MatchOneString(int x, int y, const wchar_t *str, size_t len)
1933 {
1934 int TmpPtr = GetLinePtr(y);
1935 const buff_char_t *b = &CodeBuffW[TmpPtr + x];
1936 return MatchOneStringPtr(b, str, len);
1937 }
1938
1939 /**
1940 * b ���� str��������������
1941 *
1942 * @param b �o�b�t�@�����|�C���^�A����������������
1943 * @param LineCntinued TRUE=�s���p�����l������
1944 * @retval TRUE �}�b�`����
1945 * @retval FALSE �}�b�`����������
1946 */
1947 #if 0
1948 static BOOL MatchStringPtr(const buff_char_t *b, const wchar_t *str, BOOL LineContinued)
1949 {
1950 int x;
1951 int y;
1952 BOOL result;
1953 size_t len = wcslen(str);
1954 if (len == 0) {
1955 return FALSE;
1956 }
1957 GetPosFromPtr(b, &x, &y);
1958 for(;;) {
1959 size_t match_len;
1960 if (IsBuffPadding(b)) {
1961 b++;
1962 continue;
1963 }
1964 // 1����������������
1965 match_len = MatchOneString(x, y, str, len);
1966 if (match_len == 0) {
1967 result = FALSE;
1968 break;
1969 }
1970 len -= match_len;
1971 if (len == 0) {
1972 // �S���������I������
1973 result = TRUE;
1974 break;
1975 }
1976 str += match_len;
1977
1978 // ��������
1979 x++;
1980 if (x == NumOfColumns) {
1981 if (LineContinued && ((b->attr & AttrLineContinued) != 0)) {
1982 // �����s��
1983 y++;
1984 if (y == NumOfLines) {
1985 // �o�b�t�@���I�[
1986 return 0;
1987 }
1988 x = 0;
1989 b = &CodeBuffW[GetLinePtr(y)];
1990 } else {
1991 // �s��
1992 result = FALSE;
1993 break;
1994 }
1995 }
1996 }
1997
1998 return result;
1999 }
2000 #endif
2001
2002 /**
2003 * (x,y)���� str��������������
2004 *
2005 * @param x �}�C�i�X�����A�����s������������
2006 * @param y PageStart + CursorY
2007 * @param LineCntinued TRUE=�s���p�����l������
2008 * @retval TRUE �}�b�`����
2009 * @retval FALSE �}�b�`����������
2010 */
2011 static BOOL MatchString(int x, int y, const wchar_t *str, BOOL LineContinued)
2012 {
2013 BOOL result;
2014 int TmpPtr = GetLinePtr(y);
2015 size_t len = wcslen(str);
2016 if (len == 0) {
2017 return FALSE;
2018 }
2019 while(x < 0) {
2020 if (LineContinued && (CodeBuffW[TmpPtr+0].attr & AttrLineContinued) == 0) {
2021 // �s���p�������������l�� & �p������������
2022 x = 0; // �s������������
2023 break;
2024 }
2025 TmpPtr = PrevLinePtr(TmpPtr);
2026 x += NumOfColumns;
2027 y--;
2028 }
2029 while(x > NumOfColumns) {
2030 if (LineContinued && (CodeBuffW[TmpPtr+NumOfColumns-1].attr & AttrLineContinued) == 0) {
2031 // �s���p�������������l�� & �p������������
2032 x = 0; // �s������������
2033 break;
2034 }
2035 TmpPtr = NextLinePtr(TmpPtr);
2036 x -= NumOfColumns;
2037 }
2038
2039 for(;;) {
2040 // 1����������������
2041 size_t match_len = MatchOneString(x, y, str, len);
2042 if (match_len == 0) {
2043 result = FALSE;
2044 break;
2045 }
2046 len -= match_len;
2047 if (len == 0) {
2048 // �S���������I������
2049 result = TRUE;
2050 break;
2051 }
2052 str += match_len;
2053
2054 // ��������
2055 x++;
2056 if (x == NumOfColumns) {
2057 if (LineContinued && (CodeBuffW[TmpPtr+NumOfColumns-1].attr & AttrLineContinued) != 0) {
2058 // �����s��
2059 x = 0;
2060 TmpPtr = NextLinePtr(TmpPtr);
2061 y++;
2062 } else {
2063 // �s��
2064 result = FALSE;
2065 break;
2066 }
2067 }
2068 }
2069
2070 return result;
2071 }
2072
2073 /**
2074 * (sx,sy)����(ex,ey)������ str ���}�b�`�����������T����
2075 * ���u������
2076 *
2077 * @param sy,ex PageStart + CursorY
2078 * @param[out] x �}�b�`�������u
2079 * @param[out] y �}�b�`�������u
2080 * @retval TRUE �}�b�`����
2081 */
2082 static BOOL BuffGetMatchPosFromString(
2083 int sx, int sy, int ex, int ey, const wchar_t *str,
2084 int *match_x, int *match_y)
2085 {
2086 int IStart, IEnd;
2087 int x, y;
2088
2089 for (y = sy; y<=ey ; y++) {
2090 IStart = 0;
2091 IEnd = NumOfColumns-1;
2092 if (y== sy) {
2093 IStart = sx;
2094 }
2095 if (y== ey) {
2096 IEnd = ex;
2097 }
2098
2099 x = IStart;
2100 while (x <= IEnd) {
2101 if (MatchString(x, y, str, TRUE)) {
2102 // �}�b�`����
2103 if (match_x != NULL) {
2104 *match_x = x;
2105 }
2106 if (match_y != NULL) {
2107 *match_y = y;
2108 }
2109 return TRUE;
2110 }
2111 x++;
2112 }
2113 }
2114 return FALSE;
2115 }
2116
2117
2118 /**
2119 * �A�������X�y�[�X���^�u1�����u������
2120 * @param[out] _str_len ��������(L'\0'������)
2121 * @return ������
2122 * �g�p���� free() ��������
2123 */
2124 static wchar_t *ConvertTable(const wchar_t *src, size_t src_len, size_t *str_len)
2125 {
2126 wchar_t *dest_top = malloc(sizeof(wchar_t) * src_len);
2127 wchar_t *dest = dest_top;
2128 BOOL WhiteSpace = FALSE;
2129 while (*src != '\0') {
2130 wchar_t c = *src++;
2131 if (c == 0x0d || c == 0x0a) {
2132 *dest++ = c;
2133 WhiteSpace = FALSE;
2134 } else if (c <= L' ') {
2135 if (!WhiteSpace) {
2136 // insert tab
2137 *dest++ = 0x09;
2138 WhiteSpace = TRUE;
2139 }
2140 } else {
2141 *dest++ = c;
2142 WhiteSpace = FALSE;
2143 }
2144 }
2145 *dest = L'\0';
2146 *str_len = dest - dest_top + 1;
2147 return dest_top;
2148 }
2149
2150
2151 /**
2152 * �N���b�v�{�[�h�p����������
2153 * @return ������
2154 * �g�p���� free() ��������
2155 */
2156 wchar_t *BuffCBCopyUnicode(BOOL Table)
2157 {
2158 wchar_t *str_ptr;
2159 size_t str_len;
2160 str_ptr = BuffGetStringForCB(
2161 SelectStart.x, SelectStart.y,
2162 SelectEnd.x, SelectEnd.y, BoxSelect,
2163 &str_len);
2164
2165 // �e�[�u���`��������
2166 if (Table) {
2167 size_t table_len;
2168 wchar_t *table_ptr = ConvertTable(str_ptr, str_len, &table_len);
2169 free(str_ptr);
2170 str_ptr = table_ptr;
2171 str_len = table_len;
2172 }
2173 return str_ptr;
2174 }
2175
2176 void BuffPrint(BOOL ScrollRegion)
2177 // Print screen or selected text
2178 {
2179 int Id;
2180 POINT PrintStart, PrintEnd;
2181 int j;
2182 int IStart, IEnd;
2183 LONG TmpPtr;
2184
2185 if (ScrollRegion) {
2186 Id = VTPrintInit(IdPrnScrollRegion);
2187 }
2188 else if (Selected) {
2189 Id = VTPrintInit(IdPrnScreen | IdPrnSelectedText);
2190 }
2191 else {
2192 Id = VTPrintInit(IdPrnScreen);
2193 }
2194 if (Id==IdPrnCancel) {
2195 return;
2196 }
2197
2198 /* set print region */
2199 if (Id==IdPrnSelectedText) {
2200 /* print selected region */
2201 PrintStart = SelectStart;
2202 PrintEnd = SelectEnd;
2203 }
2204 else if (Id==IdPrnScrollRegion) {
2205 /* print scroll region */
2206 PrintStart.x = 0;
2207 PrintStart.y = PageStart + CursorTop;
2208 PrintEnd.x = NumOfColumns;
2209 PrintEnd.y = PageStart + CursorBottom;
2210 }
2211 else {
2212 /* print current screen */
2213 PrintStart.x = 0;
2214 PrintStart.y = PageStart;
2215 PrintEnd.x = NumOfColumns;
2216 PrintEnd.y = PageStart + NumOfLines - 1;
2217 }
2218 if (PrintEnd.y > BuffEnd-1) {
2219 PrintEnd.y = BuffEnd-1;
2220 }
2221
2222 LockBuffer();
2223
2224 TmpPtr = GetLinePtr(PrintStart.y);
2225 for (j = PrintStart.y ; j <= PrintEnd.y ; j++) {
2226 if (j==PrintStart.y) {
2227 IStart = PrintStart.x;
2228 }
2229 else {
2230 IStart = 0;
2231 }
2232 if (j == PrintEnd.y) {
2233 IEnd = PrintEnd.x - 1;
2234 }
2235 else {
2236 IEnd = NumOfColumns - 1;
2237 }
2238
2239 BuffDrawLineIPrn(j, IStart, IEnd);
2240 PrnNewLine();
2241 TmpPtr = NextLinePtr(TmpPtr);
2242 }
2243
2244 UnlockBuffer();
2245 VTPrintEnd();
2246 }
2247
2248 // TODO ���������� ANSI ������
2249 // Dumps current line to the file (for path through printing)
2250 // HFile: file handle
2251 // TERM: terminator character
2252 // = LF or VT or FF
2253 void BuffDumpCurrentLine(PrintFile *handle, BYTE TERM)
2254 {
2255 int i, j;
2256 buff_char_t *b = &CodeBuffW[LinePtr];
2257 char bufA[TermWidthMax+1];
2258 char *p = bufA;
2259
2260 i = NumOfColumns;
2261 while ((i>0) && (b[i-1].ansi_char == 0x20)) {
2262 i--;
2263 }
2264 p = bufA;
2265 for (j=0; j<i; j++) {
2266 unsigned short c = b[j].ansi_char;
2267 *p++ = (c & 0xff);
2268 if (c > 0x100) {
2269 *p++ = (c & 0xff);
2270 }
2271 }
2272 p = bufA;
2273 for (j=0; j<i; j++) {
2274 WriteToPrnFile(handle, bufA[j],FALSE);
2275 }
2276 WriteToPrnFile(handle, 0,TRUE);
2277 if ((TERM>=LF) && (TERM<=FF)) {
2278 WriteToPrnFile(handle, 0x0d,FALSE);
2279 WriteToPrnFile(handle, TERM,TRUE);
2280 }
2281 }
2282
2283 static BOOL isURLchar(unsigned int u32)
2284 {
2285 // RFC3986(Uniform Resource Identifier (URI): Generic Syntax)����������
2286 // by sakura editor 1.5.2.1: etc_uty.cpp
2287 static const char url_char[] = {
2288 /* +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F */
2289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* +00: */
2290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* +10: */
2291 0, -1, 0, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1, /* +20: " !"#$%&'()*+,-./" */
2292 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, /* +30: "0123456789:;<=>?" */
2293 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* +40: "@ABCDEFGHIJKLMNO" */
2294 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, 0, -1, /* +50: "PQRSTUVWXYZ[\]^_" */
2295 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* +60: "`abcdefghijklmno" */
2296 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, -1, 0, /* +70: "pqrstuvwxyz{|}~ " */
2297 /* 0 : not url char
2298 * -1 : url char
2299 * other: url head char --> url_table array number + 1
2300 */
2301 };
2302
2303 if (u32 >= 0x80) {
2304 return FALSE;
2305 }
2306 return url_char[u32] == 0 ? FALSE : TRUE;
2307 }
2308
2309 static BOOL BuffIsHalfWidthFromPropery(const TTTSet *ts_, char width_property)
2310 {
2311 switch (width_property) {
2312 case 'H': // Halfwidth
2313 case 'n': // Narrow
2314 case 'N': // Neutral
2315 default:
2316 return TRUE;
2317 case 'A': // Ambiguous �B��
2318 if (ts_->UnicodeAmbiguousWidth == 2) {
2319 // �S�p����������
2320 return FALSE;
2321 }
2322 return TRUE;
2323 case 'W':
2324 case 'F':
2325 return FALSE; // �S�p
2326 }
2327 }
2328
2329 static BOOL BuffIsHalfWidthFromCode(const TTTSet *ts_, unsigned int u32, char *width_property, char *emoji)
2330 {
2331 *width_property = UnicodeGetWidthProperty(u32);
2332 *emoji = (char)UnicodeIsEmoji(u32);
2333 if (ts_->UnicodeEmojiOverride) {
2334 if (*emoji) {
2335 // �G��������������
2336 if (u32 < 0x1f000) {
2337 if (ts_->UnicodeEmojiWidth == 2) {
2338 // �S�p
2339 return FALSE;
2340 }
2341 else {
2342 // ���p
2343 return TRUE;
2344 }
2345 }
2346 else {
2347 // �����S�p
2348 return FALSE;
2349 }
2350 }
2351 }
2352 return BuffIsHalfWidthFromPropery(ts_, *width_property);
2353 }
2354
2355 /**
2356 * �J�[�\�����u����URL�A�g���r���[�g�����������������v�Z����
2357 */
2358 static int get_url_len(int cur_x, int cur_y)
2359 {
2360 int sp = cur_x + cur_y * NumOfColumns;
2361 int cp;
2362 int dp;
2363 {
2364 int p = sp;
2365 p--;
2366 while (p > 0) {
2367 int sy = p / NumOfColumns;
2368 int sx = p % NumOfColumns;
2369 int ptr = GetLinePtr(PageStart + sy) + sx;
2370 if ((CodeBuffW[ptr].attr & AttrURL) == 0) {
2371 break;
2372 }
2373 p--;
2374 }
2375 sp = p;
2376 }
2377 cp = cur_x + cur_y * NumOfColumns;
2378 dp = cp - sp;
2379 return dp;
2380 }
2381
2382 static const struct schemes_t {
2383 const wchar_t *str;
2384 int len;
2385 } schemes[] = {
2386 // clang-format off
2387 {L"https://", 8},
2388 {L"http://", 7},
2389 {L"sftp://", 7},
2390 {L"tftp://", 7},
2391 {L"news://", 7},
2392 {L"ftp://", 6},
2393 {L"mms://", 6},
2394 // clang-format on
2395 };
2396
2397 static BOOL mark_url_w_sub(int sx_s, int sx_e, int sy_s, int sy_e, int *sx_match_s, int *sx_match_e, int *sy_match_s,
2398 int *sy_match_e)
2399 {
2400 int i;
2401 int match_x, match_y;
2402 int x;
2403 int y;
2404 int rx;
2405 LONG TmpPtr;
2406
2407 if (sx_s >= sx_e && sy_s >= sy_e) {
2408 return FALSE;
2409 }
2410
2411 for (i = 0; i < _countof(schemes); i++) {
2412 const wchar_t *prefix = schemes[i].str;
2413 // �}�b�`������?
2414 if (BuffGetMatchPosFromString(sx_s, PageStart + sy_s, sx_s, PageStart + sy_s, prefix, &match_x, &match_y)) {
2415 // �}�b�`����
2416 break;
2417 }
2418 }
2419
2420 if (i == _countof(schemes)) {
2421 // �}�b�`����������
2422 return FALSE;
2423 }
2424
2425 // �}�b�`����
2426 *sx_match_s = match_x;
2427 *sy_match_s = match_y - PageStart;
2428 rx = match_x;
2429 for (y = match_y; y <= PageStart + sy_e; y++) {
2430 int sx_s_i = 0;
2431 int sx_e_i = NumOfColumns - 1; // ���������s������
2432 if (y == PageStart + sy_s) {
2433 sx_s_i = match_x;
2434 }
2435 *sy_match_e = y - PageStart;
2436 TmpPtr = GetLinePtr(y);
2437 for (x = sx_s_i; x <= sx_e_i; x++) {
2438 const buff_char_t *b = &CodeBuffW[TmpPtr + x];
2439 if (!isURLchar(b->u32)) {
2440 *sx_match_e = rx;
2441 return TRUE;
2442 }
2443 rx = x;
2444 CodeBuffW[TmpPtr + x].attr |= AttrURL;
2445 }
2446 }
2447 *sx_match_e = rx;
2448 return TRUE;
2449 }
2450
2451 /**
2452 * �J�[�\�����u����������URL��������
2453 * �����������R�[�������������A�J�[�\�����u��1���O��URL��������������
2454 *
2455 * @param cur_x �J�[�\�����u
2456 * @param cur_y �J�[�\�����u(!�o�b�t�@���u)
2457 */
2458 static void mark_url_line_w(int cur_x, int cur_y)
2459 {
2460 int sx;
2461 int sy;
2462 int ex;
2463 int ey;
2464 LONG TmpPtr;
2465 const buff_char_t *b;
2466
2467 // URL�������������T��
2468 TmpPtr = GetLinePtr(PageStart + cur_y) + cur_x - 1; // �J�[�\�����u���|�C���^��
2469 while ((CodeBuffW[TmpPtr].attr & AttrURL) != 0) {
2470 if (TmpPtr == 0) {
2471 break;
2472 }
2473 TmpPtr--;
2474 }
2475 TmpPtr++;
2476
2477 // �|�C���^���J�[�\�����u��
2478 GetPosFromPtr(&CodeBuffW[TmpPtr], &sx, &sy);
2479 if (sy >= PageStart) {
2480 sy = sy - PageStart;
2481 } else {
2482 sy = sy - PageStart;
2483 sy = sy + NumOfLinesInBuff;
2484 }
2485
2486 // �s�����T��
2487 ex = NumOfColumns - 1;
2488 ey = cur_y;
2489 if (cur_y <= NumOfLines - 1) {
2490 TmpPtr = GetLinePtr(PageStart + ey);
2491 while ((CodeBuffW[TmpPtr + NumOfColumns - 1].attr & AttrLineContinued) != 0) {
2492 ey++;
2493 TmpPtr = NextLinePtr(TmpPtr);
2494 }
2495 }
2496 b = &CodeBuffW[TmpPtr + ex];
2497 for (;;) {
2498 if (b->u32 != ' ') {
2499 break;
2500 }
2501 b--;
2502 ex--;
2503 }
2504
2505 // URL�A�g���r���[�g��������
2506 {
2507 int x;
2508 int y;
2509 for (y = sy; y <= ey; y++) {
2510 int sx_i = 0;
2511 int ex_i = NumOfColumns - 1;
2512 if (y == sy) {
2513 sx_i = sx;
2514 }
2515 if (y == ey) {
2516 ex_i = ex;
2517 }
2518 TmpPtr = GetLinePtr(PageStart + y);
2519 for (x = sx_i; x < ex_i; x++) {
2520 CodeBuffW[TmpPtr + x].attr &= ~AttrURL;
2521 }
2522 }
2523 }
2524
2525 // �}�[�N����
2526 {
2527 int sx_i = sx;
2528 int sy_i = sy;
2529 int i;
2530 for (i=0; i<1000000; i++) {
2531 int sx_match_s, sx_match_e;
2532 int sy_match_s, sy_match_e;
2533 BOOL match;
2534
2535 if ((sy_i > ey) || (sy_i == ey && sx_i >= ex)) {
2536 break;
2537 }
2538
2539 match = mark_url_w_sub(sx_i, ex, sy_i, ey, &sx_match_s, &sx_match_e, &sy_match_s, &sy_match_e);
2540 if (match) {
2541 if (sy_match_s == sy_match_e) {
2542 BuffDrawLineI(-1, -1, sy_match_s, sx_match_s, sx_match_e);
2543 }
2544 else {
2545 BuffDrawLineI(-1, -1, sy_match_s, sx_match_s, sx_match_e);
2546 }
2547 sx_i = sx_match_e;
2548 sy_i = sy_match_e;
2549 }
2550
2551 // �����Z����
2552 if (sx_i == NumOfColumns - 1) {
2553 if (sy_i == NumOfLines - 1) {
2554 break;
2555 }
2556 sx_i = 0;
2557 sy_i++;
2558 }
2559 else {
2560 sx_i++;
2561 }
2562 }
2563 }
2564
2565 // �`������
2566 {
2567 int y;
2568 for (y = sy; y <= ey; y++) {
2569 int sx_i = 0;
2570 int ex_i = NumOfColumns - 1;
2571 if (y == sy) {
2572 sx_i = sx;
2573 }
2574 else if (y == ey) {
2575 ex_i = ex;
2576 }
2577 BuffDrawLineI(-1, -1, y + PageStart, sx_i, ex_i);
2578 }
2579 }
2580 }
2581
2582 /**
2583 * (cur_x, cur_y)���u����URL�������s��
2584 */
2585 static void mark_url_w(int cur_x, int cur_y)
2586 {
2587 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
2588 buff_char_t *b = &CodeLineW[cur_x];
2589 const char32_t u32 = b->u32;
2590 int x = cur_x;
2591 BOOL prev = FALSE;
2592 BOOL next = FALSE;
2593 int i;
2594 BOOL match_flag = FALSE;
2595 int sx;
2596 int sy;
2597 int ey;
2598 int len;
2599
2600 // 1���O���Z����URL?
2601 if (x == 0) {
2602 // �������������A�O���s�����p�����������A�O���s��������URL��������
2603 if ((CodeLineW[0].attr & AttrLineContinued) != 0) {
2604 const LONG TmpPtr = GetLinePtr(PageStart + cur_y - 1);
2605 if ((CodeBuffW[TmpPtr + NumOfColumns - 1].attr & AttrURL) != 0) {
2606 prev = TRUE;
2607 }
2608 }
2609 }
2610 else {
2611 if (CodeLineW[x - 1].attr & AttrURL) {
2612 prev = TRUE;
2613 }
2614 }
2615
2616 // 1���������Z����URL?
2617 if (x == NumOfColumns - 1) {
2618 // ����x�������E?
2619 if ((cur_y + 1) < NumOfLines) {
2620 if ((CodeLineW[x].attr & AttrLineContinued) != 0) {
2621 const LONG TmpPtr = GetLinePtr(PageStart + cur_y + 1);
2622 if ((CodeBuffW[TmpPtr + NumOfColumns - 1].attr & AttrURL) != 0) {
2623 next = TRUE;
2624 }
2625 }
2626 }
2627 }
2628 else {
2629 if (CodeLineW[x + 1].attr & AttrURL) {
2630 next = TRUE;
2631 }
2632 }
2633
2634 if (prev == TRUE) {
2635 if (next == TRUE) {
2636 if (isURLchar(u32)) {
2637 // URL�����������������AURL�����������L�����N�^
2638 int ptr = GetLinePtr(PageStart + cur_y) + cur_x;
2639 CodeBuffW[ptr].attr |= AttrURL;
2640 return;
2641 }
2642 // 1line����
2643 mark_url_line_w(cur_x, cur_y);
2644 return;
2645 }
2646
2647 len = get_url_len(cur_x, cur_y);
2648 if (len >= 9) {
2649 // URL�A�g���r���[�g���������������������A
2650 // 9������������������������
2651 // ��������������������URL������������������
2652 // �� �J�[�\�����u��URL�A�g���r���[�g��������
2653 if (isURLchar(u32)) {
2654 // URL���L����
2655 CodeLineW[x].attr |= AttrURL;
2656 }
2657 return;
2658 }
2659 mark_url_line_w(cur_x, cur_y);
2660 return;
2661 }
2662
2663 // '/' �������������������n����
2664 if (u32 != '/') {
2665 return;
2666 }
2667 if (!MatchString(x - 2, PageStart + CursorY, L"://", TRUE)) {
2668 // "://" ��������������
2669 return;
2670 }
2671
2672 // �{�i�I���T��
2673 for (i = 0; i < _countof(schemes); i++) {
2674 const wchar_t *prefix = schemes[i].str;
2675 len = schemes[i].len - 1;
2676 sx = x - len;
2677 sy = PageStart + CursorY;
2678 ey = sy;
2679 if (x < len) {
2680 // �Z��
2681 if ((CodeLineW[0].attr & AttrLineContinued) == 0) {
2682 // �O���s���A������������
2683 continue;
2684 }
2685 // �O���s��������������
2686 sx = NumOfColumns + sx;
2687 sy = PageStart + CursorY - 1;
2688 }
2689 // �}�b�`������?
2690 if (BuffGetMatchPosFromString(sx, sy, x, ey, prefix, NULL, NULL)) {
2691 match_flag = TRUE;
2692 break;
2693 }
2694 }
2695 if (!match_flag) {
2696 return;
2697 }
2698
2699 // �}�b�`��������URL�������t����
2700 if (sy == ey) {
2701 for (i = 0; i <= len; i++) {
2702 CodeLineW[sx + i].attr |= AttrURL;
2703 }
2704 if (StrChangeStart > sx) {
2705 StrChangeStart = sx;
2706 StrChangeCount += len;
2707 }
2708 }
2709 else {
2710 LONG TmpPtr = GetLinePtr(sy);
2711 int xx = sx;
2712 size_t left = len + 1;
2713 while (left > 0) {
2714 CodeBuffW[TmpPtr + xx].attr |= AttrURL;
2715 xx++;
2716 if (xx == NumOfColumns) {
2717 int draw_x = sx;
2718 int draw_y = CursorY - 1;
2719 if (IsLineVisible(&draw_x, &draw_y)) {
2720 BuffDrawLineI(draw_x, draw_y, PageStart + CursorY - 1, sx, NumOfColumns - 1);
2721 }
2722 TmpPtr = NextLinePtr(TmpPtr);
2723 xx = 0;
2724 }
2725 left--;
2726 }
2727 StrChangeStart = 0;
2728 StrChangeCount = xx;
2729 }
2730 }
2731
2732 /**
2733 * 1�Z������wchar_t���������W�J����
2734 * @param[in] b 1�Z�������������������|�C���^
2735 * @retval �W�J����������
2736 *
2737 * TODO
2738 * expand_wchar() ������?
2739 */
2740 static wchar_t *GetWCS(const buff_char_t *b)
2741 {
2742 size_t len = (b->wc2[1] == 0) ? 2 : 3;
2743 wchar_t *strW;
2744 wchar_t *p;
2745 int i;
2746
2747 len += b->CombinationCharCount16;
2748 strW = malloc(sizeof(wchar_t) * len);
2749 p = strW;
2750 *p++ = b->wc2[0];
2751 if (b->wc2[1] != 0) {
2752 *p++ = b->wc2[1];
2753 }
2754 for (i=0; i<b->CombinationCharCount16; i++) {
2755 *p++ = b->pCombinationChars16[i];
2756 }
2757 *p = L'\0';
2758 return strW;
2759 }
2760
2761 /**
2762 * (x,y)��u32�������������A����������?
2763 * @param[in] wrap TRUE wrap��
2764 * @param[in] u32 Unicode
2765 * @param[in,out] combine u32��������������(NULL ��������������)
2766 * 0 ����������
2767 * 1 ��������,Nonspacing Mark, �J�[�\��������������
2768 * 2 ��������,Spacing Mark, �J�[�\���� +1 ��������
2769 * @return �����������������|�C���^
2770 * 1(���p) or 2(�S�p) or N �Z���O
2771 * �������Z�� (x ���s���� wrap == TRUE ��)
2772 * @return NULL ����������
2773 */
2774 static buff_char_t *IsCombiningChar(int x, int y, BOOL wrap, unsigned int u32, int *combine)
2775 {
2776 buff_char_t *p = NULL; // NULL�������A�O������������
2777 LONG LinePtr_ = GetLinePtr(PageStart+y);
2778 buff_char_t *CodeLineW = &CodeBuffW[LinePtr_];
2779 int combine_type; // 0 or 1 or 2
2780
2781 combine_type = (u32 == 0x200d) ? 1 : 0; // U+200d = �[���������q,ZERO WIDTH JOINER(ZWJ)
2782 if (combine_type == 0) {
2783 combine_type = UnicodeIsCombiningCharacter(u32);
2784 }
2785 if (combine != NULL) {
2786 *combine = combine_type;
2787 }
2788
2789 if (x == NumOfColumns - 1 && wrap) {
2790 // �������u����������
2791 p = &CodeLineW[x];
2792 if (IsBuffPadding(p)){
2793 p--;
2794 }
2795 }
2796 else {
2797 if (x == 0) {
2798 // �O������������
2799 p = NULL;
2800 }
2801 else {
2802 // padding���������Z�����T��
2803 x = LeftHalfOfDBCS(LinePtr_, x - 1); // 1cell�O����������
2804 if (!IsBuffPadding(&CodeLineW[x])) {
2805 p = &CodeLineW[x];
2806 }
2807 else {
2808 // �O������������
2809 p = NULL;
2810 }
2811 }
2812 }
2813
2814 // padding���������O���Z������?
2815 if (p == NULL) {
2816 // �O����������������������
2817 return NULL;
2818 }
2819
2820 // ��������?
2821 // 1���O�� ZWJ
2822 if (combine_type != 0 || (p->u32_last == 0x200d)) {
2823 return p;
2824 }
2825
2826 // ���B���[�}����
2827 if (UnicodeIsVirama(p->u32_last) != 0) {
2828 // 1���O�����B���[�}������ block ������������
2829 int block_index_last = UnicodeBlockIndex(p->u32_last);
2830 int block_index = UnicodeBlockIndex(u32);
2831 #if 0
2832 OutputDebugPrintf("U+%06x, %d, %s\n", p->u32_last, block_index_last, UnicodeBlockName(block_index_last));
2833 OutputDebugPrintf("U+%06x, %d, %s\n", u32, block_index, UnicodeBlockName(block_index));
2834 #endif
2835 if (block_index_last == block_index) {
2836 return p;
2837 }
2838 }
2839 return NULL;
2840 }
2841
2842 BOOL BuffIsCombiningCharacter(int x, int y, unsigned int u32)
2843 {
2844 buff_char_t *p = IsCombiningChar(x, y, Wrap, u32, NULL);
2845 return p != NULL;
2846 }
2847
2848 /**
2849 * Unicode���� ANSI ����������
2850 * ��������(combining character)���s��
2851 */
2852 static unsigned short ConvertACPChar(const buff_char_t *b)
2853 {
2854 char *strA;
2855 unsigned short chA;
2856 size_t lenA;
2857 size_t pool_lenW = 128;
2858 wchar_t *strW = (wchar_t *)malloc(pool_lenW * sizeof(wchar_t));
2859 BOOL too_small = FALSE;
2860 size_t lenW = expand_wchar(b, strW, pool_lenW, &too_small);
2861 if (too_small) {
2862 strW = (wchar_t *)realloc(strW, lenW * sizeof(wchar_t));
2863 expand_wchar(b, strW, lenW, &too_small);
2864 }
2865
2866 if (lenW >= 2) {
2867 // WideCharToMultiByte() ���������������s��������
2868 // �����������������s���B�������A������2��������
2869 // ��1:
2870 // U+307B(��) + U+309A(�K) ��
2871 // Shift jis �� 0x82d9(��) �� 0x814b(�K) ����������
2872 // 0x82db(��) ����������������
2873 // �\�� U+307D(��)�����K����������
2874 // ��2:
2875 // U+0061 U+0302 -> U+00E2 (latin small letter a with circumflex) (a+^)
2876 unsigned short c = UnicodeCombining(strW[0], strW[1]);
2877 if (c != 0) {
2878 // ����������
2879 strW[0] = c;
2880 strW[1] = 0;
2881 }
2882 }
2883 strA = _WideCharToMultiByte(strW, lenW, CodePage, &lenA);
2884 chA = *(unsigned char *)strA;
2885 if (!IsDBCSLeadByte((BYTE)chA)) {
2886 // 1byte����
2887 chA = strA[0];
2888 }
2889 else {
2890 // 2byte����
2891 chA = (chA << 8) | ((unsigned char)strA[1]);
2892 }
2893 free(strA);
2894 free(strW);
2895
2896 return chA;
2897 }
2898
2899 /**
2900 * ���j�R�[�h�L�����N�^��1�����o�b�t�@����������
2901 * @param[in] u32 unicode character(UTF-32)
2902 * @param[in] Attr attributes
2903 * @param[in] Insert Insert flag
2904 * @return �J�[�\��������(0 or 1 or 2)
2905 */
2906 int BuffPutUnicode(unsigned int u32, TCharAttr Attr, BOOL Insert)
2907 {
2908 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
2909 int move_x = 0;
2910 static BOOL show_str_change = FALSE;
2911 buff_char_t *p;
2912 int combining_type;
2913
2914 assert(Attr.Attr == (Attr.AttrEx & 0xff));
2915
2916 #if 0
2917 OutputDebugPrintfW(L"BuffPutUnicode(U+%06x,(%d,%d)\n", u32, CursorX, CursorY);
2918 #endif
2919
2920 if (u32 < 0x20 || (0x80 <= u32 && u32 <= 0x9f)) {
2921 // C0/C1 Controls ����������������������
2922 //assert(FALSE); // ����������������������
2923 return 0;
2924 }
2925
2926 if (ts.EnableContinuedLineCopy && CursorX == 0 && (CodeLineW[0].attr & AttrLineContinued)) {
2927 Attr.Attr |= AttrLineContinued;
2928 }
2929
2930 // �������� or 1���O���������e������������?
2931 combining_type = 0;
2932 p = IsCombiningChar(CursorX, CursorY, Wrap, u32, &combining_type);
2933 if (p != NULL || combining_type != 0) {
2934 // ��������
2935 BOOL add_base_char = FALSE;
2936 move_x = 0; // �J�[�\��������=0
2937
2938 if (p == NULL) {
2939 // �O������(��������)���������������������o����������
2940 // NBSP(non-breaking space) U+00A0 ������������
2941 add_base_char = TRUE;
2942 p = &CodeLineW[CursorX];
2943 BuffSetChar(p, 0xa0, 'H');
2944
2945 move_x = 1; // �J�[�\��������=1
2946 }
2947
2948 // �����������ANonspacing mark ���O?
2949 // �J�[�\����+1, ��������+1����
2950 if (p->u32_last != 0x200d && combining_type != 1) {
2951 // �J�[�\����������1
2952 move_x = 1;
2953
2954 p->cell++;
2955 if(StrChangeCount == 0) {
2956 // �`���������N���A�����������A���x��������
2957 StrChangeCount = p->cell;
2958 if (CursorX == 0) {
2959 // �J�[�\�������[����
2960 StrChangeStart = 0;
2961 }
2962 else {
2963 StrChangeStart = CursorX - StrChangeCount + 1;
2964 }
2965 }
2966 else {
2967 // �`��������1cell������
2968 StrChangeCount++;
2969 }
2970
2971 // �J�[�\�����u�������� Padding������
2972 // �������������� Padding ����������
2973 // - �s�������� (TODO �����������s�v?)
2974 // - ���������������������ASpacing Mark����(�J�[�\����+1����������������)����������������
2975 if (CursorX < NumOfColumns - 1) {
2976 if (add_base_char == FALSE) {
2977 BuffSetChar(&CodeLineW[CursorX], 0, 'H');
2978 CodeLineW[CursorX].Padding = TRUE;
2979 CodeLineW[CursorX].attr = Attr.Attr;
2980 CodeLineW[CursorX].attr2 = Attr.Attr2;
2981 CodeLineW[CursorX].fg = Attr.Fore;
2982 CodeLineW[CursorX].bg = Attr.Back;
2983 }
2984 }
2985 }
2986
2987 // �O������������������
2988 BuffAddChar(p, u32);
2989
2990 // �����`��
2991 if (StrChangeCount == 0) {
2992 // �`���\��������(StrChangeCount==0)�����A
2993 // �������������M���������A�`������
2994 if (Wrap) {
2995 if (!BuffIsHalfWidthFromPropery(&ts, p->WidthProperty)) {
2996 // �s����2�Z�����������`�������A2�Z�����E�����J�[�\������������
2997 StrChangeStart = CursorX - 1;
2998 StrChangeCount = 2;
2999 }
3000 else {
3001 // �s����1�Z�����������`�������������A���������J�[�\������������
3002 StrChangeStart = CursorX;
3003 StrChangeCount = 1;
3004 }
3005 }
3006 else {
3007 StrChangeCount = p->cell;
3008 if (CursorX == 0) {
3009 // �J�[�\�������[����
3010 StrChangeStart = 0;
3011 }
3012 else {
3013 StrChangeStart = CursorX - StrChangeCount + 1;
3014 }
3015 }
3016 }
3017
3018 // ANSI�����R�[�h���X�V
3019 p->ansi_char = ConvertACPChar(p);
3020 }
3021 else {
3022 char width_property;
3023 char emoji;
3024 BOOL half_width = BuffIsHalfWidthFromCode(&ts, u32, &width_property, &emoji);
3025
3026 p = &CodeLineW[CursorX];
3027 // ���������u���S�p���E��?
3028 if (IsBuffPadding(p)) {
3029 // �S�p���O�����X�y�[�X���u��������
3030 assert(CursorX > 0); // �s�����S�p���E��������
3031 BuffSetChar(p - 1, ' ', 'H');
3032 BuffSetChar(p, ' ', 'H');
3033 if (StrChangeCount == 0) {
3034 StrChangeCount = 3;
3035 StrChangeStart = CursorX - 1;
3036 }
3037 else {
3038 if (StrChangeStart < CursorX) {
3039 StrChangeCount += (CursorX - StrChangeStart) + 1;
3040 }
3041 else {
3042 StrChangeStart = CursorX;
3043 StrChangeCount += CursorX - StrChangeStart;
3044 }
3045 }
3046 }
3047 // ���������u���S�p������ && �������������p ?
3048 if (half_width && IsBuffFullWidth(p)) {
3049 // �s�����S�p(2cell)�����������������������\��������
3050 BuffSetChar(p, ' ', 'H');
3051 if (CursorX < NumOfColumns - 1) {
3052 BuffSetChar(p + 1, ' ', 'H');
3053 }
3054 if (StrChangeCount == 0) {
3055 StrChangeCount = 3;
3056 StrChangeStart = CursorX;
3057 }
3058 else {
3059 if (CursorX < StrChangeStart) {
3060 assert(FALSE);
3061 }
3062 else {
3063 StrChangeCount += 2;
3064 }
3065 }
3066 }
3067
3068 {
3069 buff_char_t *p1 = GetPtrRel(CodeBuffW, BufferSize, p, 1);
3070
3071 // �����������S�p && �����������S�p ?
3072 if (!Insert && !half_width && IsBuffFullWidth(p1)) {
3073 // �S�p������
3074 buff_char_t *p2 = GetPtrRel(CodeBuffW, BufferSize, p1, 1);
3075 BuffSetChar(p1, ' ', 'H');
3076 BuffSetChar(p2, ' ', 'H');
3077 }
3078 }
3079
3080 if (Insert) {
3081 // �}�����[�h
3082 // TODO ���`�F�b�N
3083 int XStart, LineEnd, MoveLen;
3084 int extr = 0;
3085 if (CursorX > CursorRightM)
3086 LineEnd = NumOfColumns - 1;
3087 else
3088 LineEnd = CursorRightM;
3089
3090 if (half_width) {
3091 // ���p����������
3092 move_x = 1;
3093 }
3094 else {
3095 // �S�p����������
3096 move_x = 2;
3097 if (CursorX + 1 > LineEnd) {
3098 // �����o��
3099 return -1;
3100 }
3101 }
3102
3103 // �����������������S�p�������A
3104 if (LineEnd <= NumOfColumns - 1 && (CodeLineW[LineEnd - 1].attr & AttrKanji)) {
3105 BuffSetChar(&CodeLineW[LineEnd - 1], 0x20, 'H');
3106 CodeLineW[LineEnd].attr &= ~AttrKanji;
3107 // CodeLine[LineEnd+1] = 0x20;
3108 // AttrLine[LineEnd+1] &= ~AttrKanji;
3109 extr = 1;
3110 }
3111
3112 if (!half_width) {
3113 MoveLen = LineEnd - CursorX - 1;
3114 if (MoveLen > 0) {
3115 memmoveW(&(CodeLineW[CursorX + 2]), &(CodeLineW[CursorX]), MoveLen);
3116 }
3117 }
3118 else {
3119 MoveLen = LineEnd - CursorX;
3120 if (MoveLen > 0)