Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /trunk/teraterm/teraterm/buffer.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10354 - (hide annotations) (download) (as text)
Wed Nov 9 14:13:52 2022 UTC (17 months ago) by zmatsuo
File MIME type: text/x-csrc
File size: 138968 byte(s)
ランダムデータを表示させるとクラッシュする

- `cat /dev/urandom` でテスト
- 制御文字(C0,C1)はバッファに入れないようにした
- 全角文字に上書き時にバッファ外へアクセスしていた
- バッファ上で文字のコピーを行ったとき結合などで長くなった文字のコピーを行っていなかった
  - バッファの開放(free())が重複して行われてしまう原因になっていた
- 代替画面バッファを使用した際メモリリークが発生していた
- 全角より大きな文字の扱い(TODO)
  - 全角(=2cellの文字)より大きな文字(3cell以上)が現れることがある
  - 現在3cell以上の文字の扱いをケアしていない
  - IsBuffFullWidth(), AttrKanji など

ticket #45763
1 doda 6806 /*
2     * Copyright (C) 1994-1998 T. Teranishi
3 nmaya 9048 * (C) 2004- TeraTerm Project
4 doda 6806 * All rights reserved.
5     *
6 doda 6841 * Redistribution and use in source and binary forms, with or without
7     * modification, are permitted provided that the following conditions
8     * are met:
9 doda 6806 *
10 doda 6841 * 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 doda 6806 *
18 doda 6841 * 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 doda 6806 */
29 maya 3227
30     /* TERATERM.EXE, scroll buffer routines */
31    
32     #include "teraterm.h"
33     #include <string.h>
34 yutakapon 4707 #include <stdio.h>
35 doda 8445 #include <windows.h>
36     #define _CRTDBG_MAP_ALLOC
37     #include <crtdbg.h>
38     #include <assert.h>
39 maya 3227
40 doda 8445 #include "tttypes.h"
41 maya 3227 #include "ttwinman.h"
42     #include "teraprn.h"
43     #include "vtdisp.h"
44     #include "telnet.h"
45     #include "ttplug.h" /* TTPLUG */
46 doda 8445 #include "codeconv.h"
47     #include "unicode.h"
48 maya 3227 #include "buffer.h"
49 zmatsuo 8584 #include "asprintf.h"
50 zmatsuo 8825 #include "ttcstd.h"
51 maya 3227
52 zmatsuo 10354 #define ENABLE_CELL_INDEX 0
53    
54 doda 8445 // �o�b�t�@�������p1������������
55     typedef struct {
56     char32_t u32;
57     char32_t u32_last;
58 zmatsuo 8766 char WidthProperty; // 'W' or 'F' or 'H' or 'A' or 'n'(Narrow) or 'N'(Neutual) (����������)
59 zmatsuo 10308 char cell; // ������cell�� 1/2/3+=���p,�S�p,3����
60     // 2�����������A����������������padding��cell-1������
61 doda 8445 char Padding; // TRUE = �S�p�������l���� or �s�����l����
62     char Emoji; // TRUE = �G����
63 zmatsuo 8585 unsigned char CombinationCharCount16; // charactor count
64     unsigned char CombinationCharSize16; // buffer size
65     unsigned char CombinationCharCount32;
66     unsigned char CombinationCharSize32;
67 doda 8445 wchar_t *pCombinationChars16;
68     char32_t *pCombinationChars32;
69     wchar_t wc2[2];
70 zmatsuo 8741 unsigned char fg;
71     unsigned char bg;
72 zmatsuo 8742 unsigned char attr;
73     unsigned char attr2;
74 zmatsuo 8744 unsigned short ansi_char;
75 zmatsuo 10354 #if ENABLE_CELL_INDEX
76     int idx; // �Z����������
77     #endif
78 doda 8445 } buff_char_t;
79    
80 maya 3227 #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 zmatsuo 10354 // 1�������������R���r�l�[�V�����o�b�t�@�����T�C�Y
88 zmatsuo 9404 #define MAX_CHAR_SIZE 100
89    
90 maya 3227 // status line
91 doda 6435 int StatusLine; //0: none 1: shown
92 doda 5324 /* top, bottom, left & right margin */
93     int CursorTop, CursorBottom, CursorLeftM, CursorRightM;
94 doda 8400 BOOL Selected, Selecting;
95 maya 3227 BOOL Wrap;
96    
97     static WORD TabStops[256];
98     static int NTabStops;
99    
100     static WORD BuffLock = 0;
101    
102 zmatsuo 8739 static buff_char_t *CodeBuffW;
103 maya 3227 static LONG LinePtr;
104     static LONG BufferSize;
105     static int NumOfLinesInBuff;
106     static int BuffStartAbs, BuffEndAbs;
107 doda 8400 static POINT SelectStart, SelectStartTmp, SelectEnd, SelectEndOld;
108     static DWORD SelectStartTime;
109 maya 3227 static BOOL BoxSelect;
110     static POINT DblClkStart, DblClkEnd;
111    
112 doda 8445 // �`��
113     static int StrChangeStart; // �`���J�n X (Y=CursorY)
114     static int StrChangeCount; // �`���L�����N�^��(���p�P��),0�������`����������������
115 zmatsuo 8748 static BOOL UseUnicodeApi;
116 maya 3227
117     static BOOL SeveralPageSelect; // add (2005.5.15 yutaka)
118    
119     static TCharAttr CurCharAttr;
120    
121 doda 8445 static char *SaveBuff = NULL;
122     static int SaveBuffX;
123     static int SaveBuffY;
124 doda 3743
125 zmatsuo 8770 // ANSI�\���p����������������CodePage
126     static int CodePage = 932;
127    
128 doda 8445 static void BuffDrawLineI(int DrawX, int DrawY, int SY, int IStart, int IEnd);
129 zmatsuo 9040 static void BuffDrawLineIPrn(int SY, int IStart, int IEnd);
130 doda 8445
131 zmatsuo 10354 /**
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 doda 8445 static void BuffSetChar2(buff_char_t *buff, char32_t u32, char property, BOOL half_width, char emoji)
210 maya 3227 {
211 doda 8445 size_t wstr_len;
212     buff_char_t *p = buff;
213 zmatsuo 10354
214     FreeCombinationBuf(p);
215 doda 8445 p->WidthProperty = property;
216 zmatsuo 10308 p->cell = half_width ? 1 : 2;
217 doda 8445 p->u32 = u32;
218     p->u32_last = u32;
219     p->Padding = FALSE;
220     p->Emoji = emoji;
221 zmatsuo 8741 p->fg = AttrDefaultFG;
222     p->bg = AttrDefaultBG;
223 doda 8445
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 zmatsuo 8745
239     if (u32 < 0x80) {
240     p->ansi_char = (unsigned short)u32;
241     }
242     else {
243 zmatsuo 8770 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 zmatsuo 8745 case 0:
254     default:
255 zmatsuo 10345 p->ansi_char = '?';
256 zmatsuo 8745 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 zmatsuo 8770 }
264 zmatsuo 8745 }
265     }
266 doda 8445 }
267    
268 zmatsuo 8742 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 doda 8445 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 zmatsuo 9404 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 doda 8445 }
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 zmatsuo 9404 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 doda 8445 }
313    
314     // UTF-32
315 zmatsuo 9404 if (p->CombinationCharCount32 < p->CombinationCharSize32) {
316     p->u32_last = u32;
317     p->pCombinationChars32[(size_t)p->CombinationCharCount32] = u32;
318     p->CombinationCharCount32++;
319     }
320 doda 8445
321     // UTF-16
322 zmatsuo 9404 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 zmatsuo 9839 p->CombinationCharCount16 += (unsigned char)wlen;
333 zmatsuo 9404 }
334 doda 8445 }
335     }
336    
337     static void memcpyW(buff_char_t *dest, const buff_char_t *src, size_t count)
338     {
339     size_t i;
340 zmatsuo 10354
341     if (dest == src || count == 0) {
342     return;
343 doda 8445 }
344 zmatsuo 10354
345     for (i = 0; i < count; i++) {
346     CopyCombinationBuf(dest, src);
347     dest++;
348     src++;
349     }
350 doda 8445 }
351    
352 zmatsuo 8742 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 doda 8445 {
354     size_t i;
355     for (i=0; i<count; i++) {
356     BuffSetChar(dest, ch, 'H');
357 zmatsuo 8741 dest->fg = fg;
358     dest->bg = bg;
359 zmatsuo 8742 dest->attr = attr;
360     dest->attr2 = attr2;
361 doda 8445 dest++;
362     }
363     }
364    
365     static void memmoveW(buff_char_t *dest, const buff_char_t *src, size_t count)
366     {
367 zmatsuo 10354 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 doda 8445 }
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 zmatsuo 10308 if (b->cell != 1)
402 doda 8445 return TRUE;
403     return FALSE;
404     }
405    
406     static LONG GetLinePtr(int Line)
407     {
408 maya 3393 LONG Ptr;
409 maya 3227
410 maya 3393 Ptr = (LONG)(BuffStartAbs + Line) * (LONG)(NumOfColumns);
411     while (Ptr>=BufferSize) {
412     Ptr = Ptr - BufferSize;
413     }
414     return Ptr;
415 maya 3227 }
416    
417 doda 8445 static LONG NextLinePtr(LONG Ptr)
418 maya 3227 {
419 maya 3393 Ptr = Ptr + (LONG)NumOfColumns;
420     if (Ptr >= BufferSize) {
421     Ptr = Ptr - BufferSize;
422     }
423     return Ptr;
424 maya 3227 }
425    
426 doda 8445 static LONG PrevLinePtr(LONG Ptr)
427 maya 3227 {
428 maya 3393 Ptr = Ptr - (LONG)NumOfColumns;
429     if (Ptr < 0) {
430     Ptr = Ptr + BufferSize;
431     }
432     return Ptr;
433 maya 3227 }
434    
435 zmatsuo 8744 /**
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 zmatsuo 9840 y = y - BuffStartAbs + NumOfLinesInBuff;
448 zmatsuo 8744 }
449     *bx = x;
450     *by = y;
451     }
452    
453 doda 8445 static BOOL ChangeBuffer(int Nx, int Ny)
454 maya 3227 {
455 maya 3393 LONG NewSize;
456     int NxCopy, NyCopy, i;
457     LONG SrcPtr, DestPtr;
458     WORD LockOld;
459 doda 8445 buff_char_t *CodeDestW;
460 maya 3227
461 maya 3393 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 maya 3227
471 maya 3393 if ( (LONG)Nx * (LONG)Ny > BuffSizeMax ) {
472     Ny = BuffSizeMax / Nx;
473     }
474 maya 3227
475 maya 3393 NewSize = (LONG)Nx * (LONG)Ny;
476 maya 3227
477 doda 8445 CodeDestW = NULL;
478     CodeDestW = malloc(NewSize * sizeof(buff_char_t));
479     if (CodeDestW == NULL) {
480     goto allocate_error;
481     }
482 maya 3227
483 doda 8445 memset(&CodeDestW[0], 0, NewSize * sizeof(buff_char_t));
484 zmatsuo 10354 #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 zmatsuo 8742 memsetW(&CodeDestW[0], 0x20, AttrDefaultFG, AttrDefaultBG, AttrDefault, AttrDefault, NewSize);
493 zmatsuo 8744 if ( CodeBuffW != NULL ) {
494 maya 3393 if ( NumOfColumns > Nx ) {
495     NxCopy = Nx;
496     }
497     else {
498     NxCopy = NumOfColumns;
499     }
500 maya 3227
501 maya 3393 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 doda 8445 memcpyW(&CodeDestW[DestPtr],&CodeBuffW[SrcPtr],NxCopy);
513 zmatsuo 8742 if (CodeDestW[DestPtr+NxCopy-1].attr & AttrKanji) {
514 zmatsuo 8744 BuffSetChar(&CodeDestW[DestPtr + NxCopy - 1], ' ', 'H');
515 zmatsuo 8742 CodeDestW[DestPtr+NxCopy-1].attr ^= AttrKanji;
516     }
517 maya 3393 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 maya 3227
528 maya 3393 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 maya 3227
540 maya 3393 Selected = (SelectEnd.y > SelectStart.y) ||
541 zmatsuo 8411 ((SelectEnd.y == SelectStart.y) &&
542 maya 3393 (SelectEnd.x > SelectStart.x));
543     }
544 maya 3227
545 doda 8445 CodeBuffW = CodeDestW;
546 maya 3393 BufferSize = NewSize;
547     NumOfLinesInBuff = Ny;
548     BuffStartAbs = 0;
549     BuffEnd = NyCopy;
550 maya 3227
551 maya 3393 if (BuffEnd==NumOfLinesInBuff) {
552     BuffEndAbs = 0;
553     }
554     else {
555     BuffEndAbs = BuffEnd;
556     }
557 maya 3227
558 maya 3393 PageStart = BuffEnd - NumOfLines;
559    
560     LinePtr = 0;
561     if (LockOld>0) {
562     }
563     else {
564 doda 8445 ;
565 maya 3393 }
566     BuffLock = LockOld;
567    
568     return TRUE;
569 doda 3686
570     allocate_error:
571 doda 8445 if (CodeDestW) free(CodeDestW);
572 doda 3686 return FALSE;
573 maya 3227 }
574    
575 zmatsuo 8748 void InitBuffer(BOOL use_unicode_api)
576 maya 3227 {
577 maya 3393 int Ny;
578 maya 3227
579 zmatsuo 8748 UseUnicodeApi = use_unicode_api;
580    
581 maya 3393 /* setup terminal */
582     NumOfColumns = ts.TerminalWidth;
583     NumOfLines = ts.TerminalHeight;
584 maya 3227
585 doda 6785 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 maya 3393 /* 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 maya 3227
606 maya 3393 if (! ChangeBuffer(NumOfColumns,Ny)) {
607     PostQuitMessage(0);
608     }
609 maya 3227
610 maya 3393 if (ts.EnableScrollBuff>0) {
611     ts.ScrollBuffSize = NumOfLinesInBuff;
612     }
613 maya 3227
614 maya 3393 StatusLine = 0;
615 maya 3227 }
616    
617 doda 8445 static void NewLine(int Line)
618 maya 3227 {
619 maya 3393 LinePtr = GetLinePtr(Line);
620 maya 3227 }
621    
622 zmatsuo 10100 void LockBuffer(void)
623 maya 3227 {
624 maya 3393 BuffLock++;
625     if (BuffLock>1) {
626     return;
627     }
628     NewLine(PageStart+CursorY);
629 maya 3227 }
630    
631 zmatsuo 10100 void UnlockBuffer(void)
632 maya 3227 {
633 maya 3393 if (BuffLock==0) {
634     return;
635     }
636     BuffLock--;
637     if (BuffLock>0) {
638     return;
639     }
640 maya 3227 }
641    
642 zmatsuo 10354 void FreeBuffer(void)
643 zmatsuo 10104 {
644     int i;
645 zmatsuo 10354
646 zmatsuo 10104 for (i = 0; i < NumOfColumns * NumOfLinesInBuff; i++) {
647 zmatsuo 10354 FreeCombinationBuf(&CodeBuffW[i]);
648 zmatsuo 10104 }
649    
650 maya 3393 BuffLock = 1;
651     UnlockBuffer();
652 doda 8445 if (CodeBuffW != NULL) {
653     free(CodeBuffW);
654     CodeBuffW = NULL;
655 maya 3393 }
656 maya 3227 }
657    
658 zmatsuo 10100 void BuffAllSelect(void)
659 maya 3227 {
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 doda 8400 Selecting = TRUE;
667 maya 3227 }
668    
669 zmatsuo 10100 void BuffScreenSelect(void)
670 maya 3227 {
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 doda 8400 Selecting = TRUE;
680 maya 3227 }
681    
682 zmatsuo 10100 void BuffCancelSelection(void)
683 maya 3227 {
684     SelectStart.x = 0;
685     SelectStart.y = 0;
686     SelectEnd.x = 0;
687     SelectEnd.y = 0;
688 doda 8400 Selecting = FALSE;
689 maya 3227 }
690    
691 zmatsuo 10100 void BuffReset(void)
692 maya 3227 // Reset buffer status. don't update real display
693     // called by ResetTerminal()
694     {
695 maya 3393 int i;
696 maya 3227
697 maya 3393 /* Cursor */
698     NewLine(PageStart);
699     WinOrgX = 0;
700     WinOrgY = 0;
701     NewOrgX = 0;
702     NewOrgY = 0;
703 maya 3227
704 maya 3393 /* Top/bottom margin */
705     CursorTop = 0;
706     CursorBottom = NumOfLines-1;
707 doda 5324 CursorLeftM = 0;
708     CursorRightM = NumOfColumns-1;
709 maya 3227
710 maya 3393 /* Tab stops */
711     NTabStops = (NumOfColumns-1) >> 3;
712     for (i=1 ; i<=NTabStops ; i++) {
713 doda 8445 TabStops[i-1] = (WORD)(i*8);
714 maya 3393 }
715 maya 3227
716 maya 3393 /* Initialize text selection region */
717     SelectStart.x = 0;
718     SelectStart.y = 0;
719     SelectEnd = SelectStart;
720     SelectEndOld = SelectStart;
721     Selected = FALSE;
722 maya 3227
723 maya 3393 StrChangeCount = 0;
724     Wrap = FALSE;
725     StatusLine = 0;
726 maya 3227
727 maya 3393 SeveralPageSelect = FALSE; // yutaka
728 doda 3745
729     /* Alternate Screen Buffer */
730     BuffDiscardSavedScreen();
731 maya 3227 }
732    
733 zmatsuo 9839 static void BuffScroll(int Count, int Bottom)
734 maya 3227 {
735 maya 3393 int i, n;
736     LONG SrcPtr, DestPtr;
737     int BuffEndOld;
738 maya 3227
739 maya 3393 if (Count>NumOfLinesInBuff) {
740     Count = NumOfLinesInBuff;
741     }
742 maya 3227
743 maya 3393 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 doda 8445 memcpyW(&(CodeBuffW[DestPtr]),&(CodeBuffW[SrcPtr]),NumOfColumns);
749 zmatsuo 8742 memsetW(&(CodeBuffW[SrcPtr]),0x20,CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, NumOfColumns);
750 maya 3393 SrcPtr = PrevLinePtr(SrcPtr);
751     DestPtr = PrevLinePtr(DestPtr);
752     n--;
753     }
754     }
755     for (i = 1 ; i <= n ; i++) {
756 zmatsuo 8741 buff_char_t *b = &CodeBuffW[DestPtr];
757 zmatsuo 8742 memsetW(b ,0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, NumOfColumns);
758 maya 3393 DestPtr = PrevLinePtr(DestPtr);
759     }
760 maya 3227
761 maya 3393 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 maya 3227
773 maya 3393 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 maya 3227
789 maya 3393 NewLine(PageStart+CursorY);
790 maya 3227 }
791    
792     // If cursor is on left/right half of a Kanji, erase it.
793     // LR: left(0)/right(1) flag
794 doda 8445 // LR 0 �J�[�\��������������
795     // 1 �J�[�\�����������E��
796     static void EraseKanji(int LR)
797     {
798 zmatsuo 8739 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
799    
800 doda 8445 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 zmatsuo 8742 p->attr = CurCharAttr.Attr;
812     p->attr2 = CurCharAttr.Attr2;
813 zmatsuo 8741 p->fg = CurCharAttr.Fore;
814     p->bg = CurCharAttr.Back;
815 doda 8445 if (bx+1 < NumOfColumns) {
816     BuffSetChar(p + 1, ' ', 'H');
817 zmatsuo 8742 (p+1)->attr = CurCharAttr.Attr;
818     (p+1)->attr2 = CurCharAttr.Attr2;
819 zmatsuo 8741 (p+1)->fg = CurCharAttr.Fore;
820     (p+1)->bg = CurCharAttr.Back;
821 doda 8445 }
822     }
823 maya 3227 }
824    
825 zmatsuo 8785 static void EraseKanjiOnLRMargin(LONG ptr, int count)
826 doda 5371 {
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 zmatsuo 8742 if (CursorLeftM>0 && (CodeBuffW[pos].attr & AttrKanji)) {
836 doda 8445 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
837 zmatsuo 8742 CodeBuffW[pos].attr &= ~AttrKanji;
838 doda 5371 pos++;
839 doda 8445 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
840 zmatsuo 8742 CodeBuffW[pos].attr &= ~AttrKanji;
841 doda 5371 }
842     pos = ptr + CursorRightM;
843 zmatsuo 8742 if (CursorRightM < NumOfColumns-1 && (CodeBuffW[pos].attr & AttrKanji)) {
844 doda 8445 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
845 zmatsuo 8742 CodeBuffW[pos].attr &= ~AttrKanji;
846 doda 5371 pos++;
847 doda 8445 BuffSetChar(&CodeBuffW[pos], 0x20, 'H');
848 zmatsuo 8742 CodeBuffW[pos].attr &= ~AttrKanji;
849 doda 5371 }
850     ptr = NextLinePtr(ptr);
851     }
852     }
853    
854 doda 8445 // Insert space characters at the current position
855     // Count: Number of characters to be inserted
856 maya 3227 void BuffInsertSpace(int Count)
857 doda 8445 {
858 zmatsuo 8739 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
859 doda 8445 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 zmatsuo 8742 b->attr &= ~AttrKanji;
876 doda 8445 sx--;
877     extr++;
878     }
879    
880 zmatsuo 8742 if (CursorRightM < NumOfColumns - 1 && (CodeLineW[CursorRightM].attr & AttrKanji)) {
881 doda 8445 BuffSetChar(&CodeLineW[CursorRightM + 1], 0x20, 'H');
882 zmatsuo 8742 CodeLineW[CursorRightM + 1].attr &= ~AttrKanji;
883 doda 8445 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 zmatsuo 8742 memsetW(&(CodeLineW[CursorX]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2, Count);
895 doda 8445 /* last char in current line is kanji first? */
896 zmatsuo 8742 if ((CodeLineW[CursorRightM].attr & AttrKanji) != 0) {
897 doda 8445 /* then delete it */
898     BuffSetChar(&CodeLineW[CursorRightM], 0x20, 'H');
899 zmatsuo 8742 CodeLineW[CursorRightM].attr &= ~AttrKanji;
900 doda 8445 }
901     BuffUpdateRect(sx, CursorY, CursorRightM + extr, CursorY);
902     }
903 doda 5324
904 zmatsuo 10100 void BuffEraseCurToEnd(void)
905 maya 3227 // Erase characters from cursor to the end of screen
906     {
907 maya 3393 LONG TmpPtr;
908     int offset;
909     int i, YEnd;
910 maya 3227
911 maya 3393 NewLine(PageStart+CursorY);
912 doda 3416 if (ts.Language==IdJapanese || ts.Language==IdKorean || ts.Language==IdUtf8) {
913 maya 3393 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 doda 5324 if (StatusLine && !isCursorOnStatusLine) {
919 maya 3393 YEnd--;
920     }
921     for (i = CursorY ; i <= YEnd ; i++) {
922 zmatsuo 8742 memsetW(&(CodeBuffW[TmpPtr+offset]),0x20,CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, NumOfColumns-offset);
923 maya 3393 offset = 0;
924     TmpPtr = NextLinePtr(TmpPtr);
925     }
926     /* update window */
927 zmatsuo 10338 DispEraseCurToEnd(YEnd, &CurCharAttr);
928 maya 3227 }
929    
930 zmatsuo 10100 void BuffEraseHomeToCur(void)
931 maya 3227 // Erase characters from home to cursor
932     {
933 maya 3393 LONG TmpPtr;
934     int offset;
935     int i, YHome;
936 maya 3227
937 maya 3393 NewLine(PageStart+CursorY);
938 doda 3416 if (ts.Language==IdJapanese || ts.Language==IdKorean || ts.Language==IdUtf8) {
939 maya 3393 EraseKanji(0); /* if cursor is on left half of a kanji, erase the kanji */
940     }
941     offset = NumOfColumns;
942 doda 5324 if (isCursorOnStatusLine) {
943 maya 3393 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 zmatsuo 8742 memsetW(&(CodeBuffW[TmpPtr]),0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, offset);
954 maya 3393 TmpPtr = NextLinePtr(TmpPtr);
955     }
956 maya 3227
957 maya 3393 /* update window */
958 zmatsuo 10338 DispEraseHomeToCur(YHome, &CurCharAttr);
959 maya 3227 }
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 doda 5324 int i, linelen;
967 doda 5371 int extl=0, extr=0;
968 maya 3393 LONG SrcPtr, DestPtr;
969 maya 3227
970 maya 3393 BuffUpdateScroll();
971 maya 3227
972 doda 5371 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 doda 5324 SrcPtr = GetLinePtr(PageStart+YEnd-Count) + CursorLeftM;
980     DestPtr = GetLinePtr(PageStart+YEnd) + CursorLeftM;
981     linelen = CursorRightM - CursorLeftM + 1;
982 maya 3393 for (i= YEnd-Count ; i>=CursorY ; i--) {
983 doda 8445 memcpyW(&(CodeBuffW[DestPtr]), &(CodeBuffW[SrcPtr]), linelen);
984 maya 3393 SrcPtr = PrevLinePtr(SrcPtr);
985     DestPtr = PrevLinePtr(DestPtr);
986     }
987     for (i = 1 ; i <= Count ; i++) {
988 zmatsuo 8742 memsetW(&(CodeBuffW[DestPtr]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, linelen);
989 maya 3393 DestPtr = PrevLinePtr(DestPtr);
990     }
991 maya 3227
992 doda 5324 if (CursorLeftM > 0 || CursorRightM < NumOfColumns-1 || !DispInsertLines(Count, YEnd)) {
993 doda 5371 BuffUpdateRect(CursorLeftM-extl, CursorY, CursorRightM+extr, YEnd);
994 maya 3393 }
995 maya 3227 }
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 zmatsuo 8739 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
1003 maya 3393 BOOL LineContinued=FALSE;
1004 doda 3312
1005 zmatsuo 8742 if (ts.EnableContinuedLineCopy && XStart == 0 && (CodeLineW[0].attr & AttrLineContinued)) {
1006 maya 3393 LineContinued = TRUE;
1007     }
1008 doda 3312
1009 doda 3416 if (ts.Language==IdJapanese || ts.Language==IdKorean || ts.Language==IdUtf8) {
1010 maya 3393 EraseKanji(1); /* if cursor is on right half of a kanji, erase the kanji */
1011     }
1012 maya 3227
1013 maya 3393 NewLine(PageStart+CursorY);
1014 zmatsuo 8742 memsetW(&(CodeLineW[XStart]),0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, Count);
1015 maya 3227
1016 maya 3393 if (ts.EnableContinuedLineCopy) {
1017     if (LineContinued) {
1018     BuffLineContinued(TRUE);
1019     }
1020    
1021     if (XStart + Count >= NumOfColumns) {
1022 zmatsuo 8742 CodeBuffW[NextLinePtr(LinePtr)].attr &= ~AttrLineContinued;
1023 maya 3393 }
1024     }
1025 doda 3312
1026 zmatsuo 10338 DispEraseCharsInLine(XStart, Count, &CurCharAttr);
1027 maya 3227 }
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 doda 5324 int i, linelen;
1035 doda 5371 int extl=0, extr=0;
1036 maya 3393 LONG SrcPtr, DestPtr;
1037 maya 3227
1038 maya 3393 BuffUpdateScroll();
1039 maya 3227
1040 doda 5371 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 doda 5324 SrcPtr = GetLinePtr(PageStart+CursorY+Count) + (LONG)CursorLeftM;
1048     DestPtr = GetLinePtr(PageStart+CursorY) + (LONG)CursorLeftM;
1049     linelen = CursorRightM - CursorLeftM + 1;
1050 maya 3393 for (i=CursorY ; i<= YEnd-Count ; i++) {
1051 doda 8445 memcpyW(&(CodeBuffW[DestPtr]), &(CodeBuffW[SrcPtr]), linelen);
1052 maya 3393 SrcPtr = NextLinePtr(SrcPtr);
1053     DestPtr = NextLinePtr(DestPtr);
1054     }
1055     for (i = YEnd+1-Count ; i<=YEnd ; i++) {
1056 zmatsuo 8742 memsetW(&(CodeBuffW[DestPtr]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, linelen);
1057 maya 3393 DestPtr = NextLinePtr(DestPtr);
1058     }
1059 maya 3227
1060 doda 5324 if (CursorLeftM > 0 || CursorRightM < NumOfColumns-1 || ! DispDeleteLines(Count,YEnd)) {
1061 doda 5371 BuffUpdateRect(CursorLeftM-extl, CursorY, CursorRightM+extr, YEnd);
1062 maya 3393 }
1063 maya 3227 }
1064    
1065     // Delete characters in current line from cursor
1066     // Count: number of characters to be deleted
1067 doda 8445 void BuffDeleteChars(int Count)
1068 maya 3227 {
1069 zmatsuo 8739 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
1070 doda 5325 int MoveLen;
1071 doda 8445 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 zmatsuo 8742 if (CursorRightM < NumOfColumns - 1 && (CodeLineW[CursorRightM].attr & AttrKanji)) {
1104 doda 8445 BuffSetChar(&CodeLineW[CursorRightM], 0x20, 'H');
1105 zmatsuo 8742 CodeLineW[CursorRightM].attr &= ~AttrKanji;
1106 doda 8445 BuffSetChar(&CodeLineW[CursorRightM + 1], 0x20, 'H');
1107 zmatsuo 8742 CodeLineW[CursorRightM + 1].attr &= ~AttrKanji;
1108 doda 8445 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 zmatsuo 8742 memsetW(&(CodeLineW[CursorX + MoveLen]), ' ', CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, Count);
1117 doda 8445
1118     BuffUpdateRect(CursorX, CursorY, CursorRightM + extr, CursorY);
1119     }
1120 doda 5325
1121 maya 3227 // Erase characters in current line from cursor
1122     // Count: number of characters to be deleted
1123 doda 8445 void BuffEraseChars(int Count)
1124 maya 3227 {
1125 zmatsuo 8739 buff_char_t * CodeLineW = &CodeBuffW[LinePtr];
1126 doda 8445 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 zmatsuo 8742 memsetW(&(CodeLineW[CursorX]), 0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, Count);
1162 doda 8445
1163     /* update window */
1164 zmatsuo 10338 DispEraseCharsInLine(sx, Count + extr, &CurCharAttr);
1165 doda 8445 }
1166 maya 3227
1167 zmatsuo 10100 void BuffFillWithE(void)
1168 maya 3227 // Fill screen with 'E' characters
1169     {
1170 maya 3393 LONG TmpPtr;
1171     int i;
1172 maya 3227
1173 maya 3393 TmpPtr = GetLinePtr(PageStart);
1174     for (i = 0 ; i <= NumOfLines-1-StatusLine ; i++) {
1175 zmatsuo 8742 memsetW(&(CodeBuffW[TmpPtr]),'E', AttrDefaultFG, AttrDefaultBG, AttrDefault, AttrDefault, NumOfColumns);
1176 maya 3393 TmpPtr = NextLinePtr(TmpPtr);
1177     }
1178     BuffUpdateRect(WinOrgX,WinOrgY,WinOrgX+WinWidth-1,WinOrgY+WinHeight-1);
1179 maya 3227 }
1180    
1181     void BuffDrawLine(TCharAttr Attr, int Direction, int C)
1182     { // IO-8256 terminal
1183 maya 3393 LONG Ptr;
1184     int i, X, Y;
1185 maya 3227
1186 maya 3393 if (C==0) {
1187     return;
1188     }
1189     Attr.Attr |= AttrSpecial;
1190 maya 3227
1191 maya 3393 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 zmatsuo 8742 memsetW(&(CodeBuffW[Ptr+CursorX]),'q', Attr.Fore, Attr.Back, Attr.Attr, Attr.Attr2, C);
1211 maya 3393 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 zmatsuo 8744 BuffSetChar4(&CodeBuffW[Ptr+X], 'x', Attr.Fore, Attr.Back, Attr.Attr, Attr.Attr2, 'H');
1235 maya 3393 Ptr = NextLinePtr(Ptr);
1236     }
1237     BuffUpdateRect(X,CursorY,X,CursorY+C-1);
1238     break;
1239     }
1240 maya 3227 }
1241    
1242 zmatsuo 8742 void BuffEraseBox(int XStart, int YStart, int XEnd, int YEnd)
1243 maya 3227 {
1244 maya 3393 int C, i;
1245     LONG Ptr;
1246 maya 3227
1247 maya 3393 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 zmatsuo 8742 ((CodeBuffW[Ptr+XStart-1].attr & AttrKanji) != 0)) {
1264     BuffSetChar4(&CodeBuffW[Ptr+XStart-1], 0x20, CurCharAttr.Fore, CurCharAttr.Back, CurCharAttr.Attr, CurCharAttr.Attr2, 'H');
1265 maya 3393 }
1266     if ((XStart+C<NumOfColumns) &&
1267 zmatsuo 8742 ((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 maya 3393 }
1270 zmatsuo 8742 memsetW(&(CodeBuffW[Ptr+XStart]),0x20, CurCharAttr.Fore, CurCharAttr.Back, AttrDefault, CurCharAttr.Attr2 & Attr2ColorMask, C);
1271 maya 3393 Ptr = NextLinePtr(Ptr);
1272     }
1273     BuffUpdateRect(XStart,YStart,XEnd,YEnd);
1274 maya 3227 }
1275    
1276 doda 5090 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 zmatsuo 8742 ((CodeBuffW[Ptr+XStart-1].attr & AttrKanji) != 0)) {
1298 doda 8446 BuffSetChar(&CodeBuffW[Ptr + XStart - 1], 0x20, 'H');
1299 zmatsuo 8742 CodeBuffW[Ptr+XStart-1].attr ^= AttrKanji;
1300 doda 5090 }
1301     if ((XStart+Cols<NumOfColumns) &&
1302 zmatsuo 8742 ((CodeBuffW[Ptr+XStart+Cols-1].attr & AttrKanji) != 0)) {
1303 doda 8446 BuffSetChar(&CodeBuffW[Ptr + XStart + Cols], 0x20, 'H');
1304 doda 5090 }
1305 zmatsuo 8742 memsetW(&(CodeBuffW[Ptr+XStart]), ch, CurCharAttr.Fore, CurCharAttr.Back, CurCharAttr.Attr, CurCharAttr.Attr2, Cols);
1306 doda 5090 Ptr = NextLinePtr(Ptr);
1307     }
1308     BuffUpdateRect(XStart, YStart, XEnd, YEnd);
1309     }
1310    
1311 doda 6174 //
1312     // TODO: 1 origin �������������� 0 origin ������
1313     //
1314 doda 5089 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 doda 8445 memcpyW(&(CodeBuffW[DPtr+DstX]), &(CodeBuffW[SPtr+SrcXStart]), C);
1357 doda 5089 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 doda 8445 memcpyW(&(CodeBuffW[DPtr+DstX]), &(CodeBuffW[SPtr+SrcXStart]), C);
1366 doda 5089 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 doda 8445 memmoveW(&(CodeBuffW[DPtr+DstX]), &(CodeBuffW[SPtr+SrcXStart]), C);
1375 doda 5089 SPtr = NextLinePtr(SPtr);
1376     DPtr = NextLinePtr(DPtr);
1377     }
1378     }
1379     BuffUpdateRect(DstX,DstY,DstX+C-1,DstY+L-1);
1380     }
1381    
1382 doda 5095 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 zmatsuo 8742 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 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[j].fg = attr->Fore; }
1406     if (mask->Attr2 & Attr2Back) { CodeBuffW[j].bg = attr->Back; }
1407 doda 5095 }
1408 doda 7083 while (++j < Ptr+XStart+C) {
1409 zmatsuo 8742 CodeBuffW[j].attr = (CodeBuffW[j].attr & ~mask->Attr) | attr->Attr;
1410     CodeBuffW[j].attr2 = (CodeBuffW[j].attr2 & ~mask->Attr2) | attr->Attr2;
1411 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[j].fg = attr->Fore; }
1412     if (mask->Attr2 & Attr2Back) { CodeBuffW[j].bg = attr->Back; }
1413 doda 5095 }
1414 zmatsuo 8742 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 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[j].fg = attr->Fore; }
1418     if (mask->Attr2 & Attr2Back) { CodeBuffW[j].bg = attr->Back; }
1419 doda 5095 }
1420     Ptr = NextLinePtr(Ptr);
1421     }
1422     }
1423     else { // DECRARA
1424     for (i=YStart; i<=YEnd; i++) {
1425     j = Ptr+XStart-1;
1426 zmatsuo 8742 if (XStart>0 && (CodeBuffW[j].attr & AttrKanji)) {
1427     CodeBuffW[j].attr ^= attr->Attr;
1428 doda 5095 }
1429 doda 7083 while (++j < Ptr+XStart+C) {
1430 zmatsuo 8742 CodeBuffW[j].attr ^= attr->Attr;
1431 doda 5095 }
1432 zmatsuo 8742 if (XStart+C<NumOfColumns && (CodeBuffW[j-1].attr & AttrKanji)) {
1433     CodeBuffW[j].attr ^= attr->Attr;
1434 doda 5095 }
1435     Ptr = NextLinePtr(Ptr);
1436     }
1437     }
1438     BuffUpdateRect(XStart, YStart, XEnd, YEnd);
1439     }
1440    
1441 doda 7086 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 zmatsuo 8742 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1464 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1465     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1466 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1467     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1468 doda 7086 }
1469     while (++i < endp) {
1470 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1471     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1472 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1473     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1474 doda 7086 }
1475 zmatsuo 8742 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1476 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1477     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1478 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1479     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1480 doda 7086 }
1481     }
1482     else {
1483     i = Ptr + XStart - 1;
1484     endp = Ptr + NumOfColumns;
1485    
1486 zmatsuo 8742 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1487 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1488     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1489 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1490     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1491 doda 7086 }
1492     while (++i < endp) {
1493 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1494     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1495 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1496     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1497 doda 7086 }
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 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1506     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1507 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1508     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1509 doda 7086 i++;
1510     }
1511     }
1512    
1513     Ptr = NextLinePtr(Ptr);
1514     i = Ptr;
1515     endp = Ptr + XEnd + 1;
1516    
1517     while (i < endp) {
1518 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1519     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1520 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1521     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1522 doda 7086 i++;
1523     }
1524 zmatsuo 8742 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1525 zmatsuo 10101 CodeBuffW[i].attr = (CodeBuffW[i].attr & ~mask->Attr) | attr->Attr;
1526     CodeBuffW[i].attr2 = (CodeBuffW[i].attr2 & ~mask->Attr2) | attr->Attr2;
1527 zmatsuo 8741 if (mask->Attr2 & Attr2Fore) { CodeBuffW[i].fg = attr->Fore; }
1528     if (mask->Attr2 & Attr2Back) { CodeBuffW[i].bg = attr->Back; }
1529 doda 7086 }
1530     }
1531     }
1532     else { // DECRARA
1533     if (YStart == YEnd) {
1534     i = Ptr + XStart - 1;
1535     endp = Ptr + XEnd + 1;
1536    
1537 zmatsuo 8742 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1538     CodeBuffW[i].attr ^= attr->Attr;
1539 doda 7086 }
1540     while (++i < endp) {
1541 zmatsuo 8742 CodeBuffW[i].attr ^= attr->Attr;
1542 doda 7086 }
1543 zmatsuo 8742 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1544     CodeBuffW[i].attr ^= attr->Attr;
1545 doda 7086 }
1546     }
1547     else {
1548     i = Ptr + XStart - 1;
1549     endp = Ptr + NumOfColumns;
1550    
1551 zmatsuo 8742 if (XStart > 0 && (CodeBuffW[i].attr & AttrKanji)) {
1552     CodeBuffW[i].attr ^= attr->Attr;
1553 doda 7086 }
1554     while (++i < endp) {
1555 zmatsuo 8742 CodeBuffW[i].attr ^= attr->Attr;
1556 doda 7086 }
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 zmatsuo 8742 CodeBuffW[i].attr ^= attr->Attr;
1565 doda 7086 i++;
1566     }
1567     }
1568    
1569     Ptr = NextLinePtr(Ptr);
1570     i = Ptr;
1571     endp = Ptr + XEnd + 1;
1572    
1573     while (i < endp) {
1574 zmatsuo 8742 CodeBuffW[i].attr ^= attr->Attr;
1575 doda 7086 i++;
1576     }
1577 zmatsuo 8742 if (XEnd < NumOfColumns-1 && (CodeBuffW[i-1].attr & AttrKanji)) {
1578     CodeBuffW[i].attr ^= attr->Attr;
1579 doda 7086 }
1580     Ptr = NextLinePtr(Ptr);
1581     }
1582     }
1583     BuffUpdateRect(0, YStart, NumOfColumns-1, YEnd);
1584     }
1585    
1586 zmatsuo 10308 /**
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 doda 8445 static int LeftHalfOfDBCS(LONG Line, int CharPtr)
1598 maya 3227 {
1599 zmatsuo 10308 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 maya 3393 }
1608 zmatsuo 10308 return x;
1609 maya 3227 }
1610    
1611 doda 8445 static int MoveCharPtr(LONG Line, int *x, int dx)
1612 maya 3227 // 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 maya 3393 // One DBCS character is counted as one character.
1618 maya 3227 // 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 maya 3393 int i;
1625 maya 3227
1626 maya 3393 *x = LeftHalfOfDBCS(Line,*x);
1627     i = 0;
1628     while (dx!=0) {
1629     if (dx>0) { // move right
1630 zmatsuo 8742 if ((CodeBuffW[Line+*x].attr & AttrKanji) != 0) {
1631 maya 3393 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 maya 3227 }
1651 maya 3393 return i;
1652 maya 3227 }
1653    
1654 doda 8445 /**
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 zmatsuo 10061 str_size = (NumOfColumns + 2) * (ey - sy + 1);
1673 doda 8445 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 zmatsuo 10030 int IStart; // �J�n
1682     int IEnd; // �I��
1683     BOOL LineContinued;
1684    
1685 doda 8445 if (box_select) {
1686 zmatsuo 10030 IStart = sx;
1687     IEnd = ex - 1;
1688     LineContinued = FALSE;
1689 doda 8445 }
1690     else {
1691 zmatsuo 10030 // �s�I��
1692     IStart = (y == sy) ? sx : 0;
1693 zmatsuo 10061 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 doda 8445
1704 zmatsuo 10061 // �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 doda 8445 }
1712     }
1713     }
1714    
1715 zmatsuo 10062 // IEnd=�R�s�[���K�v�����������u
1716     if (LineContinued) {
1717     // �s���������������R�s�[����
1718     IEnd++;
1719     }
1720     else {
1721 zmatsuo 10061 // �����s���p�����������������A�X�y�[�X����������
1722 zmatsuo 10030 while (IEnd >= IStart) {
1723     // �R�s�[�s�v��" "(0x20)������
1724 doda 8445 const buff_char_t *b = &CodeBuffW[TmpPtr + IEnd];
1725 zmatsuo 10030 if (b->u32 != 0x20) {
1726     // �X�y�[�X���O������
1727 zmatsuo 10062 IEnd++;
1728 zmatsuo 10030 break;
1729 doda 8445 }
1730 zmatsuo 10030 if (IEnd == 0) {
1731 doda 8445 break;
1732     }
1733 zmatsuo 10030 // �����l����
1734     MoveCharPtr(TmpPtr,&IEnd,-1);
1735 doda 8445 }
1736     }
1737    
1738 zmatsuo 10030 // 1���C�����������R�s�[����
1739 zmatsuo 10062 // IEnd=�R�s�[���K�v�����������u+1
1740 doda 8445 x = IStart;
1741 zmatsuo 10062 while (x < IEnd) {
1742 doda 8445 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 zmatsuo 8678 * 1�Z������wchar_t���������W�J����
1789     * @param[in] b 1�Z�������������������|�C���^
1790     * @param[in,out] buf �������W�J�� NULL���������W�J��������
1791 zmatsuo 8744 * @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 zmatsuo 8745 *
1799     * TODO
1800     * GetWCS() ������?
1801 zmatsuo 8678 */
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 zmatsuo 8908 return len;
1837 zmatsuo 8678 }
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 doda 8445 * (x,y) ��1������ str��������������
1856     * *�� 1������������wchar_t�����\������������
1857     *
1858 zmatsuo 8744 * @param b
1859     * @param str ���r������(wchar_t)
1860     * @param len ���r��������
1861     * @retval �}�b�`������������
1862     * 0=�}�b�`����������
1863 doda 8445 */
1864 zmatsuo 8744 static size_t MatchOneStringPtr(const buff_char_t *b, const wchar_t *str, size_t len)
1865 doda 8445 {
1866 zmatsuo 8747 int match_pos = 0;
1867 zmatsuo 8744 if (len == 0) {
1868     return 0;
1869     }
1870 doda 8445 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 zmatsuo 8744 * (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 zmatsuo 10311 #if 0
1931 zmatsuo 8744 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 zmatsuo 8747 size_t match_len;
1943 zmatsuo 8744 if (IsBuffPadding(b)) {
1944     b++;
1945     continue;
1946     }
1947     // 1����������������
1948 zmatsuo 8747 match_len = MatchOneString(x, y, str, len);
1949 zmatsuo 8744 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 zmatsuo 10311 #endif
1984 zmatsuo 8744
1985     /**
1986 doda 8445 * (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 zmatsuo 8742 if (LineContinued && (CodeBuffW[TmpPtr+0].attr & AttrLineContinued) == 0) {
2004 doda 8445 // �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 zmatsuo 8742 if (LineContinued && (CodeBuffW[TmpPtr+NumOfColumns-1].attr & AttrLineContinued) == 0) {
2014 doda 8445 // �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 zmatsuo 8742 if (LineContinued && (CodeBuffW[TmpPtr+NumOfColumns-1].attr & AttrLineContinued) != 0) {
2041 doda 8445 // �����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 zmatsuo 8676 /**
2135     * �N���b�v�{�[�h�p����������
2136     * @return ������
2137     * �g�p���� free() ��������
2138     */
2139     wchar_t *BuffCBCopyUnicode(BOOL Table)
2140 doda 8445 {
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 zmatsuo 8676 return str_ptr;
2157 doda 8445 }
2158    
2159 maya 3227 void BuffPrint(BOOL ScrollRegion)
2160     // Print screen or selected text
2161     {
2162 maya 3393 int Id;
2163     POINT PrintStart, PrintEnd;
2164 zmatsuo 9040 int j;
2165 maya 3393 int IStart, IEnd;
2166     LONG TmpPtr;
2167 maya 3227
2168 maya 3393 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 maya 3227
2181 maya 3393 /* 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 maya 3227
2205 maya 3393 LockBuffer();
2206 maya 3227
2207 maya 3393 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 maya 3227
2222 zmatsuo 9040 BuffDrawLineIPrn(j, IStart, IEnd);
2223 maya 3393 PrnNewLine();
2224     TmpPtr = NextLinePtr(TmpPtr);
2225     }
2226 maya 3227
2227 maya 3393 UnlockBuffer();
2228     VTPrintEnd();
2229 maya 3227 }
2230    
2231 zmatsuo 8744 // TODO ���������� ANSI ������
2232 maya 3227 // 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 zmatsuo 9115 void BuffDumpCurrentLine(PrintFile *handle, BYTE TERM)
2237 maya 3227 {
2238 maya 3393 int i, j;
2239 zmatsuo 8744 buff_char_t *b = &CodeBuffW[LinePtr];
2240     char bufA[TermWidthMax+1];
2241     char *p = bufA;
2242 maya 3227
2243 maya 3393 i = NumOfColumns;
2244 zmatsuo 8744 while ((i>0) && (b[i-1].ansi_char == 0x20)) {
2245 maya 3393 i--;
2246     }
2247 zmatsuo 8744 p = bufA;
2248 maya 3393 for (j=0; j<i; j++) {
2249 zmatsuo 8744 unsigned short c = b[j].ansi_char;
2250     *p++ = (c & 0xff);
2251     if (c > 0x100) {
2252     *p++ = (c & 0xff);
2253     }
2254 maya 3393 }
2255 zmatsuo 8744 p = bufA;
2256     for (j=0; j<i; j++) {
2257 zmatsuo 9115 WriteToPrnFile(handle, bufA[j],FALSE);
2258 zmatsuo 8744 }
2259 zmatsuo 9115 WriteToPrnFile(handle, 0,TRUE);
2260 maya 3393 if ((TERM>=LF) && (TERM<=FF)) {
2261 zmatsuo 9115 WriteToPrnFile(handle, 0x0d,FALSE);
2262     WriteToPrnFile(handle, TERM,TRUE);
2263 maya 3393 }
2264 maya 3227 }
2265    
2266 doda 8445 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, -