Develop and Download Open Source Software

Browse Subversion Repository

Contents of /branches/ttcomtester/teraterm/teraterm/buffer.c

Parent Directory Parent Directory | Revision Log Revision Log


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