~lidaobing/+junk/zhcon

« back to all changes in this revision

Viewing changes to src/console.cpp

  • Committer: LI Daobing
  • Date: 2008-11-04 04:39:18 UTC
  • Revision ID: lidaobing@gmail.com-20081104043918-nfwwvgfb0uied0mt
importĀ 1:0.2.6-5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vi:ts=4:shiftwidth=4:expandtab
 
2
/***************************************************************************
 
3
                          console.cpp  -  description
 
4
                             -------------------
 
5
    begin                : Sun Mar 18 2001
 
6
    copyright            : (C) 2001 by ejoy
 
7
    email                : ejoy@users.sourceforge.net
 
8
 ***************************************************************************/
 
9
 
 
10
/***************************************************************************
 
11
 *                                                                         *
 
12
 *   This program is free software; you can redistribute it and/or modify  *
 
13
 *   it under the terms of the GNU General Public License as published by  *
 
14
 *   the Free Software Foundation; either version 2 of the License, or     *
 
15
 *   (at your option) any later version.                                   *
 
16
 *                                                                         *
 
17
 ***************************************************************************/
 
18
 
 
19
#include <cassert>
 
20
#include "debug.h"
 
21
#include <unistd.h>
 
22
#include <string.h>
 
23
#include <algorithm>
 
24
#include "console.h"
 
25
int Console::mColorTable[16] =
 
26
{ 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 };
 
27
 
 
28
Console::Console(int x1, int y1, int x2, int y2)
 
29
:Window(x1, y1, x2, y2, WS_DEF), // set window console pointer
 
30
mHistMode(false),
 
31
mDefColor(0x07),
 
32
mUlColor(0x0f),
 
33
mHalfColor(0x08),
 
34
mEscState(NORMAL)
 
35
{
 
36
    mConMaxCols = mMaxCols;
 
37
    mConMaxRows = mMaxRows;
 
38
    mConEndCol = mEndCol;
 
39
    mConEndRow = mEndRow;
 
40
    int size = mMaxCols * mMaxRows;
 
41
    mpSavTextBuf = new char[size];
 
42
    mpSavAttrBuf = new char[size];
 
43
    mpSavFlagBuf = new char[size];
 
44
 
 
45
    Reset();
 
46
    Show();
 
47
    CursorShow();
 
48
 
 
49
    size = mMaxCols * HISTORY_LINES;
 
50
    mpHistText = new char[size];
 
51
    mpHistAttr = new char[size];
 
52
    mpHistFlag = new char[size];
 
53
    memset(mpHistText, ' ', size);
 
54
    memset(mpHistAttr, mAttr, size);
 
55
    memset(mpHistFlag, txtASCII | txtUpdated, size);
 
56
    mHistCurRow = 0;
 
57
 
 
58
    mMouseMask = 0x77;  // 0x80 when mono
 
59
    mMouseIdx = -1;
 
60
    mSelStart = -1;  // cleared by clear_selection
 
61
    mpSelBuf = NULL;
 
62
}
 
63
 
 
64
Console::~Console() {
 
65
    delete[] mpHistText;
 
66
    delete[] mpHistAttr;
 
67
    delete[] mpHistFlag;
 
68
    delete[] mpSavTextBuf;
 
69
    delete[] mpSavAttrBuf;
 
70
    delete[] mpSavFlagBuf;
 
71
    delete[] mpSelBuf;
 
72
}
 
73
 
 
74
/** handle ansi esc command */
 
75
void Console::DoEscape(char c) {
 
76
 
 
77
    if (mEscIntro == '\0') {
 
78
        //ESC seen
 
79
        switch (c) {
 
80
            case 'D':
 
81
                Lf();
 
82
                break;
 
83
            case 'E':
 
84
                Cr();
 
85
                Lf();
 
86
                break;
 
87
            case 'H':  // Set Tab <ESC>H
 
88
                mTabStop[Row() >> 5] |= (1 << (Row() & 31));
 
89
                break;
 
90
            case 'M':  // Reverse Index,Scroll Up
 
91
            case 'T':  // FreeBSD, cons25
 
92
                if (Row() == mScrollStart)
 
93
                    ScrollScr(DOWN);
 
94
                else if (Row())
 
95
                    ConGoto(Col(), Row() - 1);
 
96
                mNeedWrap = false;
 
97
                break;
 
98
            case 'c':
 
99
                Reset();
 
100
                // Redraw(); // why need? called by write
 
101
                break;
 
102
            case '>':
 
103
                assert(!">");
 
104
                break;
 
105
            case '=':
 
106
                assert(!"=");
 
107
                break;
 
108
            case '7':  // Save Cursor & Attrs <ESC>7
 
109
                SaveCursor();
 
110
                break;
 
111
            case '8':  // Restore Cursor & Attrs  <ESC>8
 
112
                UnSaveCursor();
 
113
                break;
 
114
            default:
 
115
                break;
 
116
        }
 
117
    }
 
118
    else if (mEscIntro == '[') {
 
119
        //ESC [ seen
 
120
        int num;
 
121
                                       //param count
 
122
        num = mpEscParam - mEscParam + 1;
 
123
        switch (c) {
 
124
            case 'A':  // Restore Cursor & Attrs  <ESC>8
 
125
                if (!mEscParam[0])
 
126
                    mEscParam[0]++;
 
127
                ConGoto(Col(), Row() - mEscParam[0]);
 
128
                break;
 
129
            case 'B':  // Cursor Down <ESC>[{COUNT}B
 
130
            case 'e':
 
131
                if (!mEscParam[0])
 
132
                    mEscParam[0]++;
 
133
                ConGoto(Col(), Row() + mEscParam[0]);
 
134
                break;
 
135
            case 'C':  // Cursor Forward <ESC>[{COUNT}C
 
136
            case 'a':
 
137
                if (!mEscParam[0])
 
138
                    mEscParam[0]++;
 
139
                ConGoto(Col() + mEscParam[0], Row());
 
140
                break;
 
141
            case 'D':  // Cursor Backward <ESC>[{COUNT}D
 
142
                if (!mEscParam[0])
 
143
                    mEscParam[0]++;
 
144
                ConGoto(Col() - mEscParam[0], Row());
 
145
                break;
 
146
            case 'E':
 
147
                if (!mEscParam[0])
 
148
                    mEscParam[0]++;
 
149
                ConGoto(0, Row() + mEscParam[0]);
 
150
                break;
 
151
            case 'F':
 
152
                if (!mEscParam[0])
 
153
                    mEscParam[0]++;
 
154
                ConGoto(0, Row() - mEscParam[0]);
 
155
                break;
 
156
            case 'G':  // Cursor Horizontal Absolute
 
157
            case '`':
 
158
                if (mEscParam[0])
 
159
                    mEscParam[0]--;
 
160
                ConGoto(mEscParam[0], Row());
 
161
                break;
 
162
            case 'H':  // ESC [m;nH moves cursor to (m,n)
 
163
            case 'f':
 
164
                if (mEscParam[0])
 
165
                    mEscParam[0]--;
 
166
                if (mEscParam[1])
 
167
                    mEscParam[1]--;
 
168
                AbsGoto(mEscParam[1], mEscParam[0]);
 
169
                break;
 
170
            case 'J':  // ESC [sJ clears in display
 
171
                switch (mEscParam[0]) {
 
172
                    case 0:  // clear from cursor to end of screen
 
173
                        Clear(Col(), Row(), mConEndCol, Row(), mAttr);
 
174
                        if (Row() < mConEndRow)
 
175
                            Clear(0, Row() + 1, mConEndCol, mConEndRow, mAttr);
 
176
                        break;
 
177
                    case 1:  // clear from start to cursor
 
178
                        Clear(0, Row(), Col(), Row(), mAttr);
 
179
                        if (Row() > 0)
 
180
                            Clear(0, 0, mConEndCol, Row() - 1, mAttr);
 
181
                        break;
 
182
                    case 2:  // clear whole screen
 
183
                        Clear(0, 0, mConEndCol, mConEndRow, mAttr);
 
184
                        break;
 
185
                    default:  // do nothing
 
186
                        break;
 
187
                }
 
188
                mNeedWrap = false;
 
189
                break;
 
190
            case 'K':  // ESC [sK clears lines from cursor
 
191
                switch (mEscParam[0]) {
 
192
                    case 0:  // clear from cursor to end of line
 
193
                        Clear(Col(), Row(), mConEndCol, Row(), mAttr);
 
194
                        break;
 
195
                    case 1:  // clear from beinning of line to cursor
 
196
                        Clear(0, Row(), Col(), Row(), mAttr);
 
197
                        break;
 
198
                    case 2:  // clear whole line
 
199
                        Clear(0, Row(), mConEndCol, Row(), mAttr);
 
200
                        break;
 
201
                    default:  // do nothing
 
202
                        break;
 
203
                }
 
204
                mNeedWrap = false;
 
205
                break;
 
206
            case 'L':  // ESC [nL inserts n lines at cursor
 
207
                InsertLine(mEscParam[0]);
 
208
                break;
 
209
            case 'M':  // ESC [nM deletes n lines at cursor
 
210
                DeleteLine(mEscParam[0]);
 
211
                break;
 
212
            case 'P':  // ESC [nP deletes n chars at cursor
 
213
                DeleteChar(mEscParam[0]);
 
214
                break;
 
215
            case 'X':
 
216
                {
 
217
                    int n = mEscParam[0];
 
218
                    if (!n)
 
219
                        n++;
 
220
                    Clear(Col(), Row(),
 
221
                          Col() + n > mConEndCol ? mConEndCol : Col() + n,
 
222
                          Row(),
 
223
                          mAttr);
 
224
                    mNeedWrap = false;
 
225
                }
 
226
                break;
 
227
            case '@':  // ESC [n@ insert n chars at cursor
 
228
                InsertBlank(mEscParam[0]);
 
229
                break;
 
230
            case ']':
 
231
                assert(!"]");
 
232
                break;
 
233
            case 'c':
 
234
                if (mEscQuestion) {
 
235
                    if (mEscParam[0])
 
236
                        SetCursorType(mEscParam[0] | (mEscParam[1]<<8) | (mEscParam[2]<<16));
 
237
                    else
 
238
                        SetCursorType(CUR_DEFAULT);
 
239
                }
 
240
                break;
 
241
            case 'd':
 
242
                if (mEscParam[0])
 
243
                    mEscParam[0]--;
 
244
                AbsGoto(Col(), mEscParam[0]);
 
245
                break;
 
246
            case 'g':  // Clear Tab  <ESC>[{3}g
 
247
                if (num == 0)
 
248
                    mTabStop[Col() >> 5] &= ~(1 << (Col() & 31));
 
249
                else if (mEscParam[0] == 3)
 
250
                    fill_n(mTabStop, 5, 0);
 
251
                break;
 
252
            case 'h':
 
253
                SetMode(true);
 
254
                break;
 
255
            case 'l':
 
256
                SetMode(false);
 
257
                break;
 
258
            case 'm':  // ESC [nm set attribute
 
259
                for (int i = 0; i < num; i++) {
 
260
                    int value = mEscParam[i];
 
261
                    switch (value) {
 
262
                        case 0:
 
263
                            DefaultAttr();
 
264
                            break;
 
265
                        case 1:
 
266
                            mIntensity = 2;
 
267
                            break;
 
268
                        case 2:
 
269
                            mIntensity = 0;
 
270
                            break;
 
271
                        case 4:  // underline
 
272
                            mUnderline = true;
 
273
                            break;
 
274
                        case 5:  // blinking
 
275
                            mBlink = true;
 
276
                            break;
 
277
                        case 7:  // reverse
 
278
                            mReverse = true;
 
279
                            break;
 
280
                        case 8:  // hidden
 
281
                            break;
 
282
                        case 10:
 
283
                            /* ANSI X3.64-1979 (SCO-ish?)
 
284
                             * Select primary font, don't display
 
285
                             * control chars if defined, don't set
 
286
                             * bit 8 on output.
 
287
                             */
 
288
                            mCharSet = PRIMARY;
 
289
                            break;
 
290
                        case 11:
 
291
                            /* ANSI X3.64-1979 (SCO-ish?)
 
292
                             * Select first alternate font, lets
 
293
                             * chars < 32 be displayed as ROM chars.
 
294
                             */
 
295
                            mCharSet = ALT1;
 
296
                            break;
 
297
                        case 12:
 
298
                            /* ANSI X3.64-1979 (SCO-ish?)
 
299
                             * Select second alternate font, toggle
 
300
                             * high bit before displaying as ROM char.
 
301
                             */
 
302
                            mCharSet = ALT2;
 
303
                            break;
 
304
                        case 21:
 
305
                        case 22:
 
306
                            mIntensity = 1;
 
307
                        case 24:
 
308
                            mUnderline = false;
 
309
                            break;
 
310
                        case 25:
 
311
                            mBlink = false;
 
312
                            break;
 
313
                        case 27:
 
314
                            mReverse = false;
 
315
                            break;
 
316
                        case 38:
 
317
                            /* ANSI X3.64-1979 (SCO-ish?)
 
318
                             * Enables underscore, white foreground
 
319
                             * with white underscore (Linux - use
 
320
                             * default foreground).
 
321
                             */
 
322
                            mColor = BuildColor(FgColor(mDefColor),BgColor(mColor));
 
323
                            mUnderline = true;
 
324
                            break;
 
325
                        case 39:
 
326
                            /* ANSI X3.64-1979 (SCO-ish?)
 
327
                             * Disable underline option.
 
328
                             * Reset colour to default? It did this
 
329
                             * before...
 
330
                             */
 
331
                            mColor = BuildColor(FgColor(mDefColor),BgColor(mColor));
 
332
                            mUnderline = false;
 
333
                            break;
 
334
                        case 49:
 
335
                            mColor = BuildColor(FgColor(mColor),BgColor(mDefColor));
 
336
                            break;
 
337
                        default:
 
338
                            //color
 
339
                            if (value >= 30 && value <= 37)
 
340
                                mColor = BuildColor(mColorTable[(value - 30)],
 
341
                                    BgColor(mColor));
 
342
                            else if (value >= 40 && value <= 47)
 
343
                                mColor = BuildColor(FgColor(mColor),
 
344
                                    mColorTable[(value - 40)]);
 
345
                            else {
 
346
                                //what to do?
 
347
                            }
 
348
                            break;
 
349
                    }//switch
 
350
                }//for
 
351
                UpdateAttr();
 
352
                break;
 
353
            case 'n':  // not implemented
 
354
                assert(!"n");
 
355
                break;
 
356
            case 'p':  // Define Key
 
357
                assert(!"Define Key not implemented yet!");
 
358
                break;
 
359
            case 'q':
 
360
                assert(!"esc q");
 
361
                break;
 
362
            case 'r':  // set scrolling range
 
363
                if (!mEscParam[0])
 
364
                    mEscParam[0]++;
 
365
                if (!mEscParam[1])
 
366
                    mEscParam[1] = mConMaxRows;
 
367
                /* Minimum allowed region is 2 lines */
 
368
                if (mEscParam[0] < mEscParam[1] &&
 
369
                    mEscParam[1] <= mConMaxRows) {
 
370
                    mScrollStart = mEscParam[0] - 1;
 
371
                    mScrollEnd = mEscParam[1];
 
372
                    AbsGoto(0, 0);
 
373
                }
 
374
                break;
 
375
            case 's':  // Save Cursor <ESC>[s
 
376
                SaveCursor();
 
377
                break;
 
378
            case 'u':  // Unsave Cursor <ESC>[u
 
379
                UnSaveCursor();
 
380
        } //switch
 
381
    }
 
382
    else if (mEscIntro == ']') {
 
383
        //unfinished
 
384
    }
 
385
    mEscState = NORMAL;
 
386
}
 
387
 
 
388
void Console::ParseEscape(char c) {
 
389
    switch (mEscState) {
 
390
        case ESC:
 
391
            mEscIntro = '\0';          //ESC seen
 
392
            mEscQuestion = false;
 
393
            mpEscParam = mEscParam;
 
394
            for (int i = 0; i < MAX_ESC_PARAMS; i++)
 
395
                mEscParam[i] = 0;
 
396
            switch (c) {
 
397
                case '#':  // DEC obsolete hacks
 
398
                    //anyone want to implement them?
 
399
                    break;
 
400
                case '[':              //control sequence introducer
 
401
                    mEscIntro = c;
 
402
                    mEscState = SQUARE;
 
403
                    break;
 
404
                case ']':
 
405
                    mEscIntro = c;
 
406
                    mEscState = NONSTD;
 
407
                    break;
 
408
                case '%':  // unfinished
 
409
 
 
410
                    break;
 
411
                case '(':              //Char Set G0
 
412
                case ')':              //Char Set G1
 
413
                    //unfinished
 
414
                    //charset change not implemented
 
415
                    break;
 
416
                default:
 
417
                    DoEscape(c);
 
418
            }                          //swicth
 
419
            break;
 
420
        case SQUARE:                   //ESC [ seen
 
421
            if (c == '?')
 
422
                mEscQuestion = true;
 
423
            else if (c >= '0' && c <= '9') {
 
424
                if (mpEscParam < mEscParam + MAX_ESC_PARAMS)
 
425
                    *mpEscParam = *mpEscParam * 10 + (c - '0');
 
426
            }
 
427
            else if (c == ';') {
 
428
                if (++mpEscParam < mEscParam + MAX_ESC_PARAMS)
 
429
                    *mpEscParam = 0;
 
430
            }
 
431
            else {
 
432
                DoEscape(c);
 
433
            }
 
434
            break;
 
435
        case NONSTD:
 
436
            DoEscape(c);
 
437
            break;
 
438
        default:
 
439
            break;
 
440
    }                                  //switch
 
441
}
 
442
 
 
443
//send c to buffer
 
444
void Console::SendChar(char c) {
 
445
    if (mHistMode) {
 
446
        mHistMode = false;
 
447
        //restore saved Buffer
 
448
        memcpy(mpText, mpSavTextBuf, mConMaxCols * mConMaxRows);
 
449
        memcpy(mpAttr, mpSavAttrBuf, mConMaxCols * mConMaxRows);
 
450
        ResetFlagAll();
 
451
        // Redraw(); // why need? called by write
 
452
    }
 
453
 
 
454
    if (mNeedWrap) {
 
455
        Cr();
 
456
        Lf();
 
457
    }
 
458
    assert(mInsertMode == false);
 
459
    if (mCharSet == PRIMARY) {
 
460
        // txtDblCode could be code1, code2, even ASCII
 
461
        // It will be identified in UpdateScreen()
 
462
        if (gpDecoder->IsCode1(c) || gpDecoder->IsCode2(c)) {
 
463
            PutChar(mAttr,txtDblCode | txtPrimary | txtUpdated,c);
 
464
        } else {
 
465
            PutChar(mAttr,txtASCII | txtPrimary | txtUpdated,c);
 
466
        }
 
467
    }
 
468
    else {  // always table line char
 
469
        PutChar(mAttr,txtASCII | txtUpdated,c);
 
470
    }
 
471
 
 
472
    //update cursor
 
473
    if (Col() == mConEndCol)
 
474
        mNeedWrap = mAutoWrap;
 
475
    else
 
476
        Goto(Col() + 1, Row());
 
477
}
 
478
 
 
479
//#include <sys/time.h>
 
480
//#include <sys/types.h>
 
481
//#include <unistd.h> //for debug
 
482
/** Write num chars in pBuf to console */
 
483
void Console::Write(const char *pBuf, int num) {
 
484
    SelClear(); // hide mouse
 
485
    bool isCursorOn = CursorOnOff();
 
486
    // turn off cursor for rapid display
 
487
    if (isCursorOn) CursorHide();
 
488
 
 
489
    char c;
 
490
    for (; num; pBuf++, num--) {
 
491
        c = *pBuf;
 
492
        //debug<<c<<flush;
 
493
        if (mEscState != NORMAL)
 
494
            ParseEscape(c);
 
495
        else if (c < ' ')
 
496
            DoControl(c);
 
497
        else {
 
498
            SendChar(c);
 
499
//for debug
 
500
//            Redraw();
 
501
//            fd_set set;
 
502
//            struct timeval tv;
 
503
//            FD_ZERO(&set);
 
504
//            tv.tv_sec = 0;
 
505
//            tv.tv_usec = 10000; // 0.1 sec
 
506
//            select(FD_SETSIZE, &set, NULL, NULL, &tv);
 
507
        }
 
508
    }
 
509
    Redraw();
 
510
 
 
511
    if (isCursorOn) CursorShow();
 
512
}
 
513
 
 
514
/** do ANSI control function  */
 
515
void Console::DoControl(char c) {
 
516
    switch (c) {
 
517
        case 0:
 
518
            return;
 
519
        case 7:
 
520
            Beep();
 
521
            return;
 
522
        case 8:
 
523
            //backspace
 
524
            if (Col()) {
 
525
                Goto(Col()-1, Row());
 
526
                mNeedWrap = false;
 
527
            }
 
528
            return;
 
529
        case 9:
 
530
            //tab
 
531
            while (Col() < mConEndCol) {
 
532
                Goto(Col() + 1, Row());
 
533
                if (mTabStop[Col() >> 5] & (1 << (Col() & 31)))
 
534
                    break;
 
535
            }
 
536
            return;
 
537
        case 10:                       //'\n'
 
538
        case 11:
 
539
        case 12:
 
540
            Lf();
 
541
            return;
 
542
        case 13:                       //'\r'
 
543
            Cr();
 
544
            return;
 
545
        case 14:
 
546
            //charset = 1;
 
547
            //translate = set_translate(G1_charset,currcons);
 
548
            //disp_ctrl = 1;
 
549
            return;
 
550
        case 15:
 
551
            //charset = 0;
 
552
            //translate = set_translate(G0_charset,currcons);
 
553
            //disp_ctrl = 0;
 
554
            return;
 
555
        case 24://graph arrows
 
556
        case 26:
 
557
        assert(mEscState == NORMAL);
 
558
        break;
 
559
        case 27: //ESC
 
560
            mEscState = ESC;
 
561
            return;
 
562
        case 127:
 
563
            //del(currcons);
 
564
            return;
 
565
        case 128 + 27:
 
566
            mEscState = SQUARE;
 
567
            assert(!"128+27");
 
568
            return;
 
569
        default:
 
570
            break;//assert(!"unknown control char reached!");
 
571
    }//switch
 
572
    //send out unknown control char
 
573
    SendChar(c);
 
574
}
 
575
 
 
576
//Copy lines from r1 to r2
 
577
void Console::CopyLines(int r1, int r2, int count) {
 
578
    assert(r1 >= 0 && r1 < mMaxRows && r2 >= 0 && r2 < mMaxRows);
 
579
    if (count == 0 || r1 == r2)
 
580
        return;
 
581
 
 
582
    int si, di;
 
583
    si = Index(0, r1);
 
584
    di = Index(0, r2);
 
585
    int n;
 
586
    if (r2 + count < mConMaxRows)
 
587
        n = count * mConMaxCols;
 
588
    else
 
589
        n = (mConMaxRows - r2) * mConMaxCols;
 
590
 
 
591
    memmove(&mpText[di], &mpText[si], n);
 
592
    memmove(&mpAttr[di], &mpAttr[si], n);
 
593
    memmove(&mpFlag[di], &mpFlag[si], n);
 
594
    for (int i = 0; i < n; i++)
 
595
        mpFlag[di + i] |= txtUpdated;
 
596
}
 
597
 
 
598
//insert n blank line at cursor
 
599
void Console::InsertLine(int n) {
 
600
    assert(Row() + 1 <= mScrollEnd && Row() >= mScrollStart);
 
601
    if (n < 1)
 
602
        n = 1;
 
603
    if (n > mScrollEnd - Row())
 
604
        n = mScrollEnd - Row();
 
605
 
 
606
    CopyLines(Row(), Row() + n, mScrollEnd - Row() - n);
 
607
    Clear(0, Row(), mConEndCol, Row() + n - 1, mAttr);
 
608
    mNeedWrap = false;
 
609
}
 
610
 
 
611
//delete n lines at cursor
 
612
//append blank lines
 
613
void Console::DeleteLine(int n) {
 
614
    assert(Row() + 1 <= mScrollEnd && Row() >= mScrollStart);
 
615
 
 
616
    if (n < 1)
 
617
        n = 1;
 
618
    if (n > mScrollEnd - Row())
 
619
        n = mScrollEnd - Row();
 
620
 
 
621
    CopyLines(Row() + n, Row(), mScrollEnd - Row() - n);
 
622
    Clear(0, mScrollEnd - n, mConEndCol, mScrollEnd - 1, mAttr);
 
623
    mNeedWrap = false;
 
624
}
 
625
 
 
626
//insert n blank char at current position
 
627
void Console::InsertBlank(int n) {
 
628
    if (n < 1)
 
629
        n = 1;
 
630
    if (Col() + n > mConEndCol)
 
631
        n = mConEndCol - Col();
 
632
 
 
633
    int count = mConEndCol - (Col() - 1) - n;
 
634
    for (int s = mConEndCol - n, d = mConEndCol; count--;)
 
635
        CopyChar(s--, Row(), d--, Row());
 
636
    Clear(Col(), Row(), Col() + n - 1, Row(), mAttr);
 
637
    mNeedWrap = false;
 
638
}
 
639
 
 
640
//delete n chars at current position
 
641
//append blank char at the end of line
 
642
void Console::DeleteChar(int n) {
 
643
    if (n < 1)
 
644
        n = 1;
 
645
    if (Col() + n > mConEndCol)
 
646
        n = mConEndCol - Col();
 
647
 
 
648
    int count = mConEndCol - (Col() - 1) - n;
 
649
    for (int d = Col(), s = d + n; count--;) {
 
650
        assert(s <= mEndCol);
 
651
        CopyChar(s++, Row(), d++, Row());
 
652
    }
 
653
    //append blank
 
654
    Clear(mConEndCol - n + 1, Row(), mConEndCol, Row(), mAttr);
 
655
    mNeedWrap = false;
 
656
}
 
657
 
 
658
//copy a char from (r1,c1) to (r2,c2)
 
659
void Console::CopyChar(int c1, int r1, int c2, int r2) {
 
660
    assert(r1 >= 0 && r1 <= mEndRow && r2 >= 0 && r2 <= mEndRow);
 
661
    int si, di;
 
662
    si = Index(c1, r1);
 
663
    di = Index(c2, r2);
 
664
 
 
665
    mpText[di] = mpText[si];
 
666
    mpAttr[di] = mpAttr[si];
 
667
    mpFlag[di] = mpFlag[si] | txtUpdated;
 
668
}
 
669
 
 
670
//scroll screen up or down one line
 
671
//in view: [mScrollStart,mScrollEnd)
 
672
void Console::ScrollScr(DIR dir) {
 
673
    assert(mScrollEnd > mScrollStart);
 
674
 
 
675
    int count = (mScrollEnd - mScrollStart - 1) * mConMaxCols;
 
676
    int si, di, blank;
 
677
 
 
678
    if (dir == UP) {
 
679
        si = (mScrollStart + 1) * mConMaxCols;
 
680
        di = si - mConMaxCols;
 
681
        blank = mScrollEnd - 1;
 
682
        PushHistoryLine();
 
683
    }
 
684
    else {
 
685
        si = mScrollStart * mConMaxCols;
 
686
        di = si + mConMaxCols;
 
687
        blank = mScrollStart;
 
688
    }
 
689
 
 
690
    memmove(&mpText[di], &mpText[si], count);
 
691
    memmove(&mpAttr[di], &mpAttr[si], count);
 
692
    memmove(&mpFlag[di], &mpFlag[si], count);
 
693
    for (int i = 0; i < count; i++)
 
694
        mpFlag[di + i] |= txtUpdated;
 
695
    Clear(0, blank, mConEndCol, blank, mAttr);
 
696
}
 
697
 
 
698
void Console::DefaultAttr() {
 
699
    mIntensity = 1;
 
700
    mBlink = false;
 
701
    mUnderline = false;
 
702
    mReverse = false;
 
703
    mColor = mDefColor;
 
704
}
 
705
 
 
706
void Console::Reset() {
 
707
    DefaultAttr();
 
708
    UpdateAttr();
 
709
    mTabStop[0] = 0x01010100;
 
710
    mTabStop[1] = mTabStop[2] = mTabStop[3] = mTabStop[4] = 0x01010101;
 
711
    mEscQuestion = false;
 
712
    mNeedWrap = false;
 
713
    mCharSet = PRIMARY;
 
714
    mInsertMode = false;
 
715
    mDecom = false;
 
716
    mAutoWrap = true;
 
717
    mScrollStart = 0;
 
718
    mScrollEnd = mConMaxRows;
 
719
 
 
720
    int size = mConMaxCols * mConMaxRows;
 
721
    memset(mpText, ' ', size);
 
722
    memset(mpAttr, mAttr, size);
 
723
    memset(mpFlag, txtASCII | txtUpdated, size);
 
724
    ConGoto(0, 0);
 
725
}
 
726
 
 
727
void Console::SaveCursor() {
 
728
    mOldCol = Col();
 
729
    mOldRow = Row();
 
730
    mOldColor = mColor;
 
731
    mOldBlink = mBlink;
 
732
    mOldUnderline = mUnderline;
 
733
    mOldIntensity = mIntensity;
 
734
    mOldReverse = mReverse;
 
735
    mOldCharSet = mCharSet;
 
736
}
 
737
 
 
738
void Console::UnSaveCursor() {
 
739
    ConGoto(mOldCol, mOldRow);
 
740
    mColor = mOldColor;
 
741
    mBlink = mOldBlink;
 
742
    mUnderline = mOldUnderline;
 
743
    mBold = mOldBold;
 
744
    mReverse = mOldReverse;
 
745
    mCharSet = mOldCharSet;
 
746
    UpdateAttr();
 
747
    mNeedWrap = false;
 
748
}
 
749
 
 
750
void Console::SetMode(bool f) {
 
751
    if (mEscQuestion)
 
752
    switch (mEscParam[0]) {
 
753
        /* DEC private modes set/reset */
 
754
        case 1:                        /* Cursor keys send ^[Ox/^[[x */
 
755
            assert(!"set_dec_cursor_keys(tty, on_off)");
 
756
            break;
 
757
        case 3:                        /* 80/132 mode switch unimplemented */
 
758
            break;
 
759
        case 4:
 
760
            /* soft scroll/Jump scroll toggle, unimplemented yet */
 
761
            break;
 
762
        case 5:                        /* Inverted screen on/off */
 
763
            //not implemented
 
764
            break;
 
765
        case 6:
 
766
            mDecom = f;
 
767
            AbsGoto(0, 0);
 
768
        case 7:                        /* Autowrap on/off */
 
769
            mAutoWrap = f;
 
770
        case 8:                        /* Autorepeat on/off not implemented yet */
 
771
            break;
 
772
        case 25:                       /* Cursor on/off */
 
773
            //deccm = on_off;
 
774
            if (f)
 
775
                CursorShow();
 
776
            else
 
777
                CursorHide();
 
778
            break;
 
779
    }
 
780
    else
 
781
    switch (mEscParam[0]) {
 
782
        /* ANSI modes set/reset */
 
783
        case 4:                        /* Insert Mode on/off */
 
784
            mInsertMode = f;
 
785
            //decim = f;
 
786
            break;
 
787
        case 20:                       /* Lf, Enter == CrLf/Lf */
 
788
            //          set_lf_mode(tty, on_off);
 
789
            assert(!"Lf, Enter == CrLf/Lf");
 
790
            break;
 
791
    }
 
792
}
 
793
 
 
794
void Console::ConGoto(int c, int r) {
 
795
    int col, row;
 
796
    if (c < 0)
 
797
        col = 0;
 
798
    else if (c > mConEndCol)
 
799
        col = mConEndCol;
 
800
    else
 
801
        col = c;
 
802
 
 
803
    int min_y, max_y;
 
804
 
 
805
    if (mDecom) {
 
806
        min_y = mScrollStart;
 
807
        max_y = mScrollEnd;
 
808
    }
 
809
    else {
 
810
        min_y = 0;
 
811
        max_y = mConMaxRows;
 
812
    }
 
813
    if (r < min_y)
 
814
        row = min_y;
 
815
    else if (r >= max_y)
 
816
        row = max_y - 1;
 
817
    else
 
818
        row = r;
 
819
    Goto(col, row);
 
820
    mNeedWrap = false;
 
821
}
 
822
 
 
823
//for absolute user moves, when decom is set
 
824
void Console::AbsGoto(int c, int r) {
 
825
    ConGoto(c, mDecom ? (mScrollStart + r) : r);
 
826
}
 
827
 
 
828
void Console::Lf() {
 
829
    /* don't scroll if above bottom of scrolling region, or
 
830
     * if below scrolling region
 
831
     */
 
832
    if (Row() + 1 == mScrollEnd)
 
833
        ScrollScr(UP);
 
834
    else if (Row() < mConEndRow)
 
835
        Goto(Col(), Row() + 1);
 
836
    mNeedWrap = false;
 
837
}
 
838
 
 
839
void Console::Cr() {
 
840
    Goto(0, Row());
 
841
    mNeedWrap = false;
 
842
}
 
843
 
 
844
//push top line into history buffers
 
845
void Console::PushHistoryLine() {
 
846
    int s = mConMaxCols;
 
847
    memcpy(mpHistText + mHistCurRow * s, mpText, s);
 
848
    memcpy(mpHistAttr + mHistCurRow * s, mpAttr, s);
 
849
    memcpy(mpHistFlag + mHistCurRow * s, mpFlag, s);
 
850
    mHistCurRow = (mHistCurRow + 1) % HISTORY_LINES;
 
851
}
 
852
 
 
853
//scroll into history buffer and switch to history mode if necessary
 
854
void Console::ScrollDelta(ScrollFlag f) {
 
855
    SelClear();
 
856
    static int sBackOffset = 0;
 
857
    if (!mHistMode) {
 
858
        //history mode will be closed in PutChar()
 
859
        sBackOffset = 0;
 
860
        mHistMode = true;
 
861
        //save screen buffer
 
862
        memcpy(mpSavTextBuf, mpText, mConMaxCols * mConMaxRows);
 
863
        memcpy(mpSavAttrBuf, mpAttr, mConMaxCols * mConMaxRows);
 
864
        memcpy(mpSavFlagBuf, mpFlag, mConMaxCols * mConMaxRows);
 
865
    }
 
866
    switch (f) {
 
867
        case PAGE_UP:
 
868
            sBackOffset += mConMaxRows / 2;
 
869
            break;
 
870
        case PAGE_DOWN:
 
871
            sBackOffset -= mConMaxRows / 2;
 
872
            break;
 
873
        case LINE_UP:
 
874
            sBackOffset++;
 
875
            break;
 
876
        case LINE_DOWN:
 
877
            sBackOffset--;
 
878
            break;
 
879
    }
 
880
    if (sBackOffset >= HISTORY_LINES)
 
881
        sBackOffset = HISTORY_LINES - 1;
 
882
    if (sBackOffset < 0)
 
883
        sBackOffset = 0;
 
884
    ShowHistory(sBackOffset);
 
885
}
 
886
 
 
887
void Console::ShowHistory(int offset) {
 
888
    int row, indexCol, histrow;
 
889
    // draw history row
 
890
    for (row = 0; row < mConMaxRows && offset; row++, offset--) {
 
891
        histrow = mHistCurRow - offset;
 
892
        if (histrow < 0)
 
893
            histrow += HISTORY_LINES;
 
894
 
 
895
        indexCol = Index(0, histrow);
 
896
        //copy one row from history buffer
 
897
        memcpy(mpText + Index(0, row),mpHistText + indexCol,mConMaxCols);
 
898
        memcpy(mpAttr + Index(0, row),mpHistAttr + indexCol,mConMaxCols);
 
899
        memcpy(mpFlag + Index(0, row),mpHistFlag + indexCol,mConMaxCols);
 
900
        ResetFlagRow(mpText + row * mConMaxCols,mpFlag + row * mConMaxCols,mConMaxCols);
 
901
    }
 
902
    //remain rows copied from screen buffer
 
903
    for (int r = 0; row < mConMaxRows; row++, r++) {
 
904
        memcpy(mpText + Index(0, row), mpSavTextBuf + Index(0, r),mConMaxCols);
 
905
        memcpy(mpAttr + Index(0, row), mpSavAttrBuf + Index(0, r),mConMaxCols);
 
906
        memcpy(mpFlag + Index(0, row), mpSavFlagBuf + Index(0, r),mConMaxCols);
 
907
        ResetFlagRow(mpText + row * mConMaxCols,mpFlag + row * mConMaxCols,mConMaxCols);
 
908
//        DrawRow(row, &mpText[indexCol], &mpAttr[indexCol],
 
909
//            &mpFlag[indexCol], true);
 
910
    }
 
911
 
 
912
    // turn off cursor for rapid display
 
913
    bool isCursorOn = CursorOnOff();
 
914
    if (isCursorOn) CursorHide();
 
915
    Redraw();
 
916
    if (isCursorOn) CursorShow();
 
917
}
 
918
 
 
919
//modified from Yu Guanghui's auto-converter(judge.c)
 
920
Encode Console::DetectBufferEncode() {
 
921
    char *phz;
 
922
    int c_gb = 0;
 
923
    int c_big5 = 0;
 
924
 
 
925
    /* first we look up "ļæ½ļæ½"  and "ļæ½ļæ½" ,both gb and big5
 
926
     * in the text.
 
927
     */
 
928
    for (phz = mpText; phz < (mpText + mConMaxRows * mConMaxCols);
 
929
    phz++) {
 
930
        if (*phz & 0x80) {
 
931
            if ((*phz == 0xB5 && *(phz + 1) == 0xC4)
 
932
            || ((*phz == 0xCE) && *(phz + 1) == 0xD2)) {
 
933
                c_gb++;
 
934
                phz++;
 
935
                continue;
 
936
            } else if ((*phz == 0xAA && *(phz + 1) == 0xBA)
 
937
            || ((*phz == 0xA7) && *(phz + 1) == 0xDA)) {
 
938
                c_big5++;
 
939
                phz++;
 
940
                continue;
 
941
            }
 
942
            phz++;
 
943
        }
 
944
    }
 
945
 
 
946
    if (c_gb > c_big5) {
 
947
        return GB2312;
 
948
    }
 
949
    else if (c_gb == c_big5) {
 
950
        //c_gb == 0,c_big5==0
 
951
        /*There is not "ļæ½ļæ½" and "ļæ½ļæ½" in the text
 
952
         *So we test the text with a 400 words table.
 
953
         */
 
954
        //unable to detect so return ascii
 
955
        return ::ASCII;                //j_code3(buff,count);
 
956
    }
 
957
    else {
 
958
        return BIG5;
 
959
    }
 
960
}
 
961
 
 
962
void Console::VtSizeDelta(int ColDelta, int RowDelta) {
 
963
    SelClear();
 
964
    int NewRows, NewEndRow;
 
965
    NewRows = mMaxRows - RowDelta;
 
966
    NewEndRow = NewRows - 1;
 
967
 
 
968
    if (Row() > NewEndRow) {
 
969
        //CopyLines(Row(), NewEndRow, 1);
 
970
        Goto(Col(), NewEndRow);
 
971
    }
 
972
    if (RowDelta > 0) {
 
973
        //debug<<"Clear "<<NewRows<<"-"<<mConEndRow<<endl;
 
974
        Clear(0, NewRows, mConEndCol, mConEndRow, 0);
 
975
    }
 
976
    Redraw();
 
977
 
 
978
    mConMaxRows = NewRows;
 
979
    mConEndRow = NewEndRow;
 
980
    mScrollEnd = mConMaxRows;
 
981
}
 
982
 
 
983
void Console::GetVtSize(int &cols, int &rows) {
 
984
    cols = mConMaxCols;
 
985
    rows = mConMaxRows;
 
986
}
 
987
 
 
988
void Console::UpdateAttr(){
 
989
    mAttr = mColor;
 
990
    if (mUnderline)
 
991
        mAttr = (mAttr & 0xf0) | mUlColor;
 
992
    else if (mIntensity == 0)
 
993
        mAttr = (mAttr & 0xf0) | mHalfColor;
 
994
    if (mReverse)
 
995
        mAttr = ((mAttr) & 0x88) | ((((mAttr) >> 4) | ((mAttr) << 4)) & 0x77);
 
996
    if (mIntensity == 2)
 
997
        mAttr |= 0x08;
 
998
    if (mBlink)
 
999
        mAttr |= 0x80;
 
1000
}
 
1001
 
 
1002
/* use complementary color to show the mouse pointer */
 
1003
void Console::SelPointer(const int offset) {
 
1004
    if (mMouseIdx >= 0 && mMouseIdx < mMaxCols * mMaxRows) {
 
1005
        mpAttr[mMouseIdx] ^= mMouseMask;
 
1006
        mpFlag[mMouseIdx] |= txtUpdated;
 
1007
 
 
1008
        // Redraw();
 
1009
        RedrawChar(mMouseIdx % mMaxCols, mMouseIdx / mMaxCols);
 
1010
    }
 
1011
 
 
1012
    if (offset < 0) {
 
1013
        mMouseIdx = -1;
 
1014
        return;
 
1015
    }
 
1016
 
 
1017
    mMouseIdx = offset;
 
1018
    if (mMouseIdx > mMaxCols * mMaxRows - 1) {
 
1019
        mMouseIdx = mMaxCols * mMaxRows - 1;
 
1020
    }
 
1021
    
 
1022
    mpAttr[mMouseIdx] ^= mMouseMask;
 
1023
    mpFlag[mMouseIdx] |= txtUpdated;
 
1024
 
 
1025
    // Redraw();
 
1026
    RedrawChar(mMouseIdx % mMaxCols, mMouseIdx / mMaxCols);
 
1027
}
 
1028
 
 
1029
/* set reverse video on characters s-e of console with selection. */
 
1030
void Console::SelHighlight(const int begin, const int end) {
 
1031
    int count = end - begin + 1;
 
1032
    char* pAttr = &mpAttr[begin];
 
1033
    char* pFlag = &mpFlag[begin];
 
1034
    
 
1035
    char color;
 
1036
    while (count--) {
 
1037
         color = *pAttr;
 
1038
         //color = ((color) & 0x11) | (((color) & 0xe0) >> 4) | (((color) & 0x0e) << 4);
 
1039
         color = ((color) & 0x88) | (((color) & 0x70) >> 4) | (((color) & 0x07) << 4);
 
1040
         *pAttr = color;
 
1041
         pAttr++;
 
1042
         (*pFlag) |= txtUpdated;
 
1043
         pFlag++;
 
1044
         
 
1045
    }
 
1046
 
 
1047
    // turn off cursor for rapid display
 
1048
    bool isCursorOn = CursorOnOff();
 
1049
    if (isCursorOn) CursorHide();
 
1050
    Redraw();
 
1051
    if (isCursorOn) CursorShow();
 
1052
    /*
 
1053
    int count = end - beign + 2;
 
1054
    unsigned short *p;
 
1055
 
 
1056
    count /= 2;
 
1057
    p = screenpos(currcons, beign, viewed);
 
1058
    u16 *q = p;
 
1059
    int cnt = count;
 
1060
 
 
1061
    if (!can_do_color) {
 
1062
        while (cnt--) *q++ ^= 0x0800;
 
1063
    } else if (hi_font_mask == 0x100) {
 
1064
        while (cnt--) {
 
1065
            u16 a = *q;
 
1066
            a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
 
1067
            *q++ = a;
 
1068
        }
 
1069
    } else {
 
1070
        while (cnt--) {
 
1071
            u16 a = *q;
 
1072
            a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
 
1073
            *q++ = a;
 
1074
        }
 
1075
    }
 
1076
    if (DO_UPDATE)
 
1077
        do_update_region(currcons, (unsigned long) p, count);
 
1078
    */
 
1079
}
 
1080
 
 
1081
/* remove the current selection highlight, if any,
 
1082
   from the console holding the selection. */
 
1083
void Console::SelClear() {
 
1084
    SelPointer(-1); /* hide the pointer */
 
1085
    if (mSelStart != -1) {
 
1086
        SelHighlight(mSelStart, mSelEnd);
 
1087
        mSelStart = -1;
 
1088
    }
 
1089
}
 
1090
 
 
1091
// User settable table: what characters are to be considered alphabetic?
 
1092
// 256 bits
 
1093
__u32 Console::mInWordLut[8] = {
 
1094
  0x00000000, // control chars
 
1095
  0x03FF0000, // digits
 
1096
  0x87FFFFFE, // uppercase and '_'
 
1097
  0x07FFFFFE, // lowercase
 
1098
  0x00000000,
 
1099
  0x00000000,
 
1100
  0xFF7FFFFF, // latin-1 accented letters, not multiplication sign
 
1101
  0xFF7FFFFF  // latin-1 accented letters, not division sign
 
1102
};
 
1103
 
 
1104
int Console::InWord(const unsigned char c) {
 
1105
    return ( mInWordLut[c>>5] >> (c & 0x1F) ) & 1;
 
1106
}
 
1107
 
 
1108
// does screen address p correspond to character at LH/RH edge of screen?
 
1109
int Console::AtColEdge(const int p)
 
1110
{
 
1111
    return (!(p % mMaxCols) || !((p + 1) % mMaxCols));
 
1112
}
 
1113
 
 
1114
// Don't take this from <ctype.h>: 011-015 on the screen aren't spaces
 
1115
#define IS_SPACE(c)  ((c) == ' ')
 
1116
#define IS_ASCII(c)  ((c) & txtASCII)
 
1117
 
 
1118
// based on kernel, linux/drivers/char/selection.c
 
1119
void Console::SelCopy(int c1, int r1, int c2, int r2, int mode) {
 
1120
    int xs, ys, xe, ye, ps, pe;
 
1121
    xs = CorrectCol(c1);
 
1122
    ys = CorrectRow(r1);
 
1123
    xe = CorrectCol(c2);
 
1124
    ye = CorrectRow(r2);
 
1125
    ps = ys * mMaxCols + xs;
 
1126
    pe = ye * mMaxCols + xe;
 
1127
    //debug<<"Mouse " <<xs<<","<<ys<<" "<<xe<<","<<ye<<" "
 
1128
    //    <<ps<<","<<pe<<" "<<endl;
 
1129
 
 
1130
    if (mode == 4) {  // useful for screendump without selection highlights
 
1131
        SelClear();
 
1132
        return;
 
1133
    }
 
1134
 
 
1135
    if (ps > pe)    // make exchange if sel_start > sel_end
 
1136
    {
 
1137
        int tmp = ps;
 
1138
        ps = pe;
 
1139
        pe = tmp;
 
1140
    }
 
1141
 
 
1142
    int new_sel_start, new_sel_end;
 
1143
    bool spc, ascii;
 
1144
    char *bp, *obp;
 
1145
    int i;
 
1146
 
 
1147
    switch (mode)
 
1148
    {
 
1149
        case 0: // character-by-character selection
 
1150
            new_sel_start = ps;
 
1151
            new_sel_end = pe;
 
1152
            break;
 
1153
        case 1: // word-by-word selection
 
1154
            spc = IS_SPACE(mpText[ps]);
 
1155
            ascii = IS_ASCII(mpFlag[ps]);
 
1156
            for (new_sel_start = ps; ; ps--)
 
1157
            {
 
1158
                if (ascii) {
 
1159
                    if (spc && !IS_SPACE(mpText[ps]))
 
1160
                        break;
 
1161
                    if (!spc && !InWord(mpText[ps]))
 
1162
                        break;
 
1163
                } else {
 
1164
                    if (IS_ASCII(mpFlag[ps]))
 
1165
                        break;
 
1166
                }
 
1167
                new_sel_start = ps;
 
1168
                if (!(ps % mMaxCols))
 
1169
                    break;
 
1170
            }
 
1171
            spc = IS_SPACE(mpText[pe]);
 
1172
            ascii = IS_ASCII(mpFlag[pe]);
 
1173
            for (new_sel_end = pe; ; pe++)
 
1174
            {
 
1175
                if (ascii) {
 
1176
                    if (spc && !IS_SPACE(mpText[pe]))
 
1177
                        break;
 
1178
                    if (!spc && !InWord(mpText[pe]))
 
1179
                        break;
 
1180
                } else {
 
1181
                    if (IS_ASCII(mpFlag[pe]))
 
1182
                        break;
 
1183
                }
 
1184
                new_sel_end = pe;
 
1185
                if (!((pe+1) % mMaxCols))
 
1186
                    break;
 
1187
            }
 
1188
            break;
 
1189
        case 2: // line-by-line selection
 
1190
            new_sel_start = ps - ps % mMaxCols;
 
1191
            new_sel_end = pe + mMaxCols - pe % mMaxCols - 1;
 
1192
            break;
 
1193
        case 3:
 
1194
            SelPointer(pe);
 
1195
            return;
 
1196
        default:
 
1197
            return;
 
1198
    }
 
1199
 
 
1200
    // remove the pointer
 
1201
    SelPointer(-1);
 
1202
 
 
1203
    // select to end of line if on trailing space
 
1204
    if (new_sel_end > new_sel_start &&
 
1205
        !AtColEdge(new_sel_end) &&
 
1206
        IS_SPACE(mpText[new_sel_end])) {
 
1207
        for (pe = new_sel_end + 1; ; pe++)
 
1208
            if (!IS_SPACE(mpText[pe]) ||
 
1209
                AtColEdge(pe))
 
1210
                break;
 
1211
        if (IS_SPACE(mpText[pe]))
 
1212
            new_sel_end = pe;
 
1213
    }
 
1214
    if (mSelStart == -1)    // no current selection
 
1215
        SelHighlight(new_sel_start, new_sel_end);
 
1216
    else if (new_sel_start == mSelStart)
 
1217
    {
 
1218
        if (new_sel_end == mSelEnd) // no action required
 
1219
            return;
 
1220
        else if (new_sel_end > mSelEnd) // extend to right
 
1221
            SelHighlight(mSelEnd + 1, new_sel_end);
 
1222
        else                // contract from right
 
1223
            SelHighlight(new_sel_end + 1, mSelEnd);
 
1224
    }
 
1225
    else if (new_sel_end == mSelEnd)
 
1226
    {
 
1227
        if (new_sel_start < mSelStart)  // extend to left
 
1228
            SelHighlight(new_sel_start, mSelStart - 1);
 
1229
        else                // contract from left
 
1230
            SelHighlight(mSelStart, new_sel_start - 1);
 
1231
    }
 
1232
    else    // some other case; start selection from scratch
 
1233
    {
 
1234
        SelClear();
 
1235
        SelHighlight(new_sel_start, new_sel_end);
 
1236
    }
 
1237
    mSelStart = new_sel_start;
 
1238
    mSelEnd = new_sel_end;
 
1239
 
 
1240
    // Allocate a new buffer before freeing the old one ...
 
1241
    bp = new char[mSelEnd-mSelStart+1];
 
1242
    if (!bp) { // selection: kmalloc() failed
 
1243
        SelClear();
 
1244
        return;
 
1245
    }
 
1246
    if (mpSelBuf)
 
1247
        delete[] mpSelBuf;
 
1248
    mpSelBuf = bp;
 
1249
 
 
1250
    obp = bp;
 
1251
    for (i = mSelStart; i <= mSelEnd; i++) {
 
1252
        *bp = mpText[i];
 
1253
        if (!IS_SPACE(*bp++))
 
1254
            obp = bp;
 
1255
        if (! ((i + 1) % mMaxCols)) {
 
1256
            // strip trailing blanks from line and add newline,
 
1257
            //   unless non-space at end of line.
 
1258
            if (obp != bp) {
 
1259
                bp = obp;
 
1260
                *bp++ = '\r';
 
1261
            }
 
1262
            obp = bp;
 
1263
        }
 
1264
    }
 
1265
    mSelBufLen = bp - mpSelBuf;
 
1266
}
 
1267
 
 
1268
void Console::SelPaste(int fd) {
 
1269
    assert(fd >= 0);
 
1270
    int pasted = 0, count;
 
1271
    while (mpSelBuf && (mSelBufLen > pasted)) {
 
1272
        count = mSelBufLen - pasted;
 
1273
        pasted = write(fd, mpSelBuf, count);
 
1274
        pasted += count;
 
1275
    }
 
1276
}
 
1277