~ubuntu-branches/ubuntu/karmic/iterm/karmic

« back to all changes in this revision

Viewing changes to lib/src/screen_row.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Fok
  • Date: 2004-02-27 04:13:16 UTC
  • Revision ID: james.westby@ubuntu.com-20040227041316-q0jn37sia8mt0t9u
Tags: upstream-0.5
ImportĀ upstreamĀ versionĀ 0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This software is subject to the terms of the Common Public License
 
2
   You must accept the terms of this license to use this software.
 
3
 
 
4
   Copyright (C) 2002, International Business Machines Corporation
 
5
   and others.  All Rights Reserved.
 
6
 
 
7
   Further information about Common Public License Version 0.5 is obtained
 
8
   from url http://oss.software.ibm.com/developer/opensource/license-cpl.html */
 
9
 
 
10
#include "../config.h"
 
11
#include "screen_row.h"
 
12
#include <string.h>
 
13
#include <stdlib.h>
 
14
#include <stdio.h>
 
15
 
 
16
Char Blank = {" ",1,1,1};
 
17
enum {
 
18
    SPECIAL_GRAPHICS = '0',
 
19
    UK = 'A',
 
20
    ASCII = 'B'
 
21
};
 
22
 
 
23
#define ON_ERROR(row, func) \
 
24
if(row->buffer.value_max < row->buffer.value_length) \
 
25
  fprintf(stderr,"%s: value_max %d, value_length %d\n", \
 
26
          func, row->buffer.value_max ,row->buffer.value_length); \
 
27
 
 
28
#define IS_SAME_INDEX(row,col1,col2) (row->buffer.cell_to_char[(col1)] == row->buffer.cell_to_char[(col2)])
 
29
#define GET_INDEX(row,col) ((col < row->num_columns && row->buffer.cell_to_char[(col)] >= 0) ? row->buffer.cell_to_char[(col)] : row->buffer.value_length)
 
30
#define SET_INDEX(row,col,val) (row->buffer.cell_to_char[(col)] = (val))
 
31
#define CLEAR_CELL(row,col) (row->buffer.cell_to_char[(col)] = -1)
 
32
#define EXPAND_BUFFER(row,size,msg) \
 
33
do { \
 
34
    int columns_needs; \
 
35
    int last_col=1; \
 
36
    while(last_col < row->num_columns && Row_is_char_drawn(row,last_col)) \
 
37
          last_col++; \
 
38
    columns_needs = row->num_columns - last_col;\
 
39
    if(columns_needs < (size)) \
 
40
        columns_needs = (size); \
 
41
    row->buffer.value = realloc(row->buffer.value, \
 
42
                                 row->buffer.value_max+columns_needs); \
 
43
    row->buffer.value_max += columns_needs; \
 
44
} while(0)
 
45
 
 
46
#define COPY_TO(row,index,mbchar) \
 
47
do { \
 
48
 memcpy(row->buffer.value+index, Char_get_string(mbchar), Char_get_length(mbchar)); \
 
49
} while(0)
 
50
 
 
51
#define CellAttr_init(attr, bold, blink, inverse, underline, foreground, background, charset) \
 
52
do {\
 
53
  memset(attr,0,sizeof(CellAttributes)); \
 
54
  if(bold) (attr)[ATTRIBUTES]|=BOLD; \
 
55
  if(blink) (attr)[ATTRIBUTES]|=BLINK; \
 
56
  if(inverse)(attr)[ATTRIBUTES]|=INVERSE; \
 
57
  if(underline)(attr)[ATTRIBUTES]|=UNDERLINE; \
 
58
  (attr)[COLOR]|=foreground; \
 
59
  (attr)[COLOR]|=(background<<4); \
 
60
  (attr)[CHARSET]|=charset; \
 
61
} while(0)
 
62
 
 
63
static void simple_clear_cells(Row *row, int start, int end)
 
64
{
 
65
  int i;
 
66
#ifdef DEBUG
 
67
  if(start < 0 || row->num_columns < start ||
 
68
     end < 0 || row->num_columns < end ||
 
69
     end < start)
 
70
  {
 
71
    fprintf(stderr,
 
72
            "simple clear cells, row->num_columns = %d start = %d end = %d\n",
 
73
            row->num_columns,start,end);
 
74
    return;
 
75
  }
 
76
  
 
77
#endif
 
78
  for(i=start;i<end;i++)
 
79
  {
 
80
    CLEAR_CELL(row,i);
 
81
  }
 
82
  Row_set_updated(row,start,end);
 
83
}
 
84
 
 
85
static void RowBuffer_shrink(Row *row, int size)
 
86
{
 
87
  if(Row_is_char_drawn(row,size-1))
 
88
  {
 
89
        /* edge character is double width */
 
90
    if(IS_SAME_INDEX(row,size-1,size))
 
91
    {
 
92
          /* delete edge char */
 
93
      row->buffer.value_length = GET_INDEX(row,(size-1));
 
94
      CLEAR_CELL(row,(size-1));
 
95
    }
 
96
    else if(Row_is_char_drawn(row,size))
 
97
    {
 
98
      row->buffer.value_length = GET_INDEX(row,size);
 
99
    }
 
100
  }
 
101
 
 
102
  row->buffer.value_max = size < row->buffer.value_length ? row->buffer.value_length : size;
 
103
  row->buffer.value = (char *)realloc(row->buffer.value,
 
104
                                      row->buffer.value_max);
 
105
#ifdef DEBUG  
 
106
  if(row->num_columns < row->buffer.value_max ||
 
107
     row->num_columns < row->buffer.value_length ||
 
108
     row->buffer.value_max < row->buffer.value_length)
 
109
      fprintf(stderr,"row->num_columns %d, row->buffer.value_max %d\n",
 
110
              row->num_columns, row->buffer.value_max);
 
111
#endif  
 
112
}
 
113
 
 
114
static void shift_buffer(Row *row, int dest, int src, int length)
 
115
{
 
116
  if( row->buffer.value_max < dest + length )
 
117
  {
 
118
    EXPAND_BUFFER(row,(dest+length-row->buffer.value_max),"shift_buffer");
 
119
  }
 
120
  memmove(row->buffer.value + dest, row->buffer.value + src, length);
 
121
#ifdef DEBUG  
 
122
  if(row->buffer.value_max < row->buffer.value_length) 
 
123
      fprintf(stderr,"shift_buffer: row->num_columns %d, row->buffer.value_max %d\n",
 
124
              row->num_columns, row->buffer.value_max);
 
125
#endif  
 
126
}
 
127
 
 
128
static void shift_index(Row *row, int start, int index_diff)
 
129
{
 
130
  int index = start;
 
131
  while(index < row->num_columns && Row_is_char_drawn(row,index))
 
132
  {
 
133
        /* row->buffer.cell_to_char[index] += index_diff; */
 
134
    SET_INDEX(row,index,(GET_INDEX(row,index)+index_diff));
 
135
    index++;
 
136
  }
 
137
}
 
138
 
 
139
static void shift_cells(Row *row, int start , int value)
 
140
{
 
141
  int length = row->num_columns - start;
 
142
  if(value > 0)
 
143
  {
 
144
    length -= value;
 
145
  }
 
146
  memmove(row->buffer.cell_to_char + start + value,
 
147
          row->buffer.cell_to_char + start,
 
148
          length*sizeof(int));
 
149
  memmove(row->buffer.attrs + start + value,
 
150
          row->buffer.attrs + start,
 
151
          length*sizeof(CellAttributes));
 
152
  Row_set_updated(row,start,row->num_columns);
 
153
  if(value < 0)
 
154
  {
 
155
    simple_clear_cells(row,row->num_columns+value,row->num_columns);
 
156
  }
 
157
}
 
158
 
 
159
 
 
160
static void RowBuffer_add_char(Row *row, int col, Char *mbchar)
 
161
{
 
162
  int index;
 
163
  int w;
 
164
  index = GET_INDEX(row,col);
 
165
 
 
166
  if(row->buffer.value_max < index + Char_get_length(mbchar))
 
167
  {
 
168
    EXPAND_BUFFER(row,
 
169
                  (index + Char_get_length(mbchar) - row->buffer.value_max),
 
170
                  "RowBuffer_add_char()");
 
171
  }
 
172
  for(w=0;w<Char_get_width(mbchar);w++) 
 
173
  {
 
174
        /* do this row->buffer.cell_to_char[col+w] = index; */
 
175
    SET_INDEX(row,(col+w),index);
 
176
  }
 
177
      /* terminate column */
 
178
  if(col+w < row->num_columns)
 
179
      CLEAR_CELL(row,col+w);
 
180
  COPY_TO(row,index,mbchar);
 
181
  row->buffer.value_length = index + Char_get_length(mbchar);
 
182
  Row_set_updated(row,col,col+Char_get_width(mbchar));
 
183
#ifdef DEBUG  
 
184
  if(row->buffer.value_max < row->buffer.value_length)
 
185
      fprintf(stderr,"add_char, row->num_columns %d, row->buffer.value_max %d\n",
 
186
              row->num_columns, row->buffer.value_max);
 
187
#endif  
 
188
}
 
189
 
 
190
static int get_end_index(Row *row, int col, int col_width)
 
191
{
 
192
  if(row->num_columns < col + col_width ||
 
193
     (!Row_is_char_drawn(row,(col+col_width))) )
 
194
      return row->buffer.value_length;
 
195
  return GET_INDEX(row,col+col_width);
 
196
}
 
197
 
 
198
static int has_next_char(Row *row, int col, int width)
 
199
{
 
200
  if(col == row->num_columns - width) /* col is right edge of row */
 
201
      return 0;
 
202
  if(!Row_is_char_drawn(row,col+1)) /* col+1 has no char */
 
203
      return 0;
 
204
  if(width == 1)
 
205
  {
 
206
    if(IS_SAME_INDEX(row,col,col+1))
 
207
        return has_next_char(row,col+1,width);
 
208
    else
 
209
        return 1;
 
210
  }
 
211
      
 
212
  return has_next_char(row,col+1,width-1); /* col+width is multicolumn,
 
213
                                              so check next */
 
214
}
 
215
 
 
216
static void RowBuffer_replace_char(Row *row, int col, Char *mbchar)
 
217
{
 
218
  int start_index = GET_INDEX(row,col);
 
219
  int ex_end_index = get_end_index(row,col,Char_get_width(mbchar));
 
220
  int bytes_length =  ex_end_index - start_index;
 
221
  int w;
 
222
 
 
223
  if(bytes_length ==  Char_get_length(mbchar))
 
224
      COPY_TO(row, start_index, mbchar);
 
225
  else
 
226
  {
 
227
    int diff = Char_get_length(mbchar) - bytes_length;
 
228
    shift_buffer(row,start_index + Char_get_length(mbchar), ex_end_index,
 
229
                 row->buffer.value_length - ex_end_index);
 
230
    shift_index(row,col+Char_get_width(mbchar),diff);
 
231
    COPY_TO(row, start_index, mbchar);
 
232
    row->buffer.value_length += diff;
 
233
  }
 
234
 
 
235
  for(w=1;w<Char_get_width(mbchar);w++)
 
236
  {
 
237
        /* do this row->buffer.cell_to_char[col+w] = start_index; */
 
238
    SET_INDEX(row,(col+w),start_index);
 
239
  }
 
240
  Row_set_updated(row,col,col+Char_get_length(mbchar));
 
241
#ifdef DBUG  
 
242
  if(row->buffer.value_max < row->buffer.value_length)
 
243
  {
 
244
    fprintf(stderr,
 
245
            "replace_char after : col %d, num_columns %d, value_length %d, value_max %d\n",
 
246
            col, row->num_columns, row->buffer.value_length,
 
247
            row->buffer.value_max);
 
248
    fprintf(stderr,
 
249
            "replace_char after: bytes_length %d, mbchar->length %d ex_end_index %d\n",
 
250
            bytes_length, Char_get_length(mbchar), ex_end_index);
 
251
  }
 
252
#endif  
 
253
}
 
254
 
 
255
static void RowBuffer_simple_replace_space(Row *row, int col)
 
256
{
 
257
  row->buffer.value[GET_INDEX(row,col)] = ' ';
 
258
  row->buffer.attrs[col][0] = row->buffer.attrs[col][1] = row->buffer.attrs[col][3] = 0;
 
259
  row->buffer.attrs[col][2] = ASCII; /* ASCII */
 
260
  Row_set_updated(row,col,(col+1));
 
261
}
 
262
 
 
263
Row *Row_new(int col)
 
264
{
 
265
  Row *row = NULL;
 
266
  row = (Row *)malloc(sizeof(Row));
 
267
  if(row == NULL)
 
268
  {
 
269
    perror("Row_new(1)");
 
270
    return NULL;
 
271
  }
 
272
  row->buffer.cell_to_char = NULL;
 
273
  row->buffer.value = NULL;
 
274
  row->buffer.attrs = NULL;
 
275
 
 
276
  row->buffer.cell_to_char = (int *)calloc(col,sizeof(int));
 
277
  if(row->buffer.cell_to_char == NULL)
 
278
  {
 
279
    perror("Row_new(2)");
 
280
    goto FAIL;
 
281
  }
 
282
 
 
283
  row->buffer.value = (char *)calloc(col,sizeof(char));
 
284
  if(row->buffer.value == NULL)
 
285
  {
 
286
    perror("Row_new(3)");
 
287
    goto FAIL;
 
288
  }
 
289
  
 
290
  row->buffer.attrs = (CellAttributes *)calloc(col,sizeof(CellAttributes));
 
291
  if(row->buffer.attrs == NULL)
 
292
  {
 
293
    perror("Row_new(4)");
 
294
    goto FAIL;
 
295
  }
 
296
 
 
297
  row->buffer.value_max = col;
 
298
  row->num_columns = col;
 
299
  Row_clear(row);
 
300
  Row_clear_updated(row);
 
301
  return row;
 
302
  FAIL:
 
303
  if(row)
 
304
  {
 
305
    if(row->buffer.cell_to_char)
 
306
        free(row->buffer.cell_to_char);
 
307
    if(row->buffer.value)
 
308
        free(row->buffer.value);
 
309
    if(row->buffer.attrs)
 
310
        free(row->buffer.attrs);
 
311
    free(row);
 
312
  }
 
313
  return NULL;
 
314
}
 
315
 
 
316
void Row_destroy(Row *row)
 
317
{
 
318
  if(row)
 
319
  {
 
320
    if(row->buffer.cell_to_char)
 
321
        free(row->buffer.cell_to_char);
 
322
    if(row->buffer.value)
 
323
        free(row->buffer.value);
 
324
    if(row->buffer.attrs)
 
325
        free(row->buffer.attrs);
 
326
    free(row);
 
327
  }
 
328
}
 
329
 
 
330
int Row_is_multicolumn_start(Row *row, int col)
 
331
{
 
332
#ifdef DEBUG
 
333
  if(row->num_columns <= col || col < 0)
 
334
  {
 
335
    fprintf(stderr,
 
336
            "Row_is_multicolumn_start, row->num_cols = %d, col = %d\n",
 
337
            row->num_columns,col);
 
338
    return -1;
 
339
  }
 
340
#endif
 
341
  if(col == 0 || row->num_columns < col)
 
342
      return 1;
 
343
 
 
344
  if(Row_is_char_drawn(row,col) &&
 
345
     !(IS_SAME_INDEX(row,col-1,col)) )
 
346
  {
 
347
    return 1;
 
348
  }
 
349
  return 0;
 
350
}
 
351
 
 
352
int Row_find_multicolum_char_start_column(Row *row, int col)
 
353
{
 
354
  int c = col;
 
355
#ifdef DEBUG
 
356
  if(row->num_columns <= col || col < 0)
 
357
  {
 
358
    fprintf(stderr,
 
359
            "Row_find_multicolumn_char_start_column, row->num_cols = %d, col = %d\n",
 
360
            row->num_columns,col);
 
361
    return -1;
 
362
  }
 
363
#endif
 
364
  if(row->num_columns < col)
 
365
      return -1;
 
366
  while(0 < c)
 
367
  {
 
368
    if(Row_is_multicolumn_start(row,c))
 
369
        return c;
 
370
      c--;
 
371
  }
 
372
  return c;
 
373
}
 
374
 
 
375
int Row_get_cell_width(Row *row,int col)
 
376
{
 
377
  int w=1;
 
378
#ifdef DEBUG
 
379
  if(row->num_columns <= col || col < 0)
 
380
  {
 
381
    fprintf(stderr,
 
382
            "Row_get_cell_width, row->num_cols = %d, col = %d\n",
 
383
            row->num_columns,col);
 
384
    return -1;
 
385
  }
 
386
#endif
 
387
  if(row->num_columns <= col)
 
388
      return -1;
 
389
  if(col == row->num_columns - 1)
 
390
      return 1;
 
391
  if(IS_SAME_INDEX(row,col,col+1))
 
392
      w += Row_get_cell_width(row,col+1);
 
393
  return w;
 
394
}
 
395
 
 
396
 
 
397
int Row_add_char(Row *row, int col, Char *mbchar, int bold, int blink,
 
398
                 int inverse, int underline, int foreground, int background,
 
399
                 char charset)
 
400
{
 
401
  int w;
 
402
 
 
403
  if(col < 0 || /* invalid */
 
404
     row->num_columns <= col || /* invalid */
 
405
     row->num_columns < col + Char_get_width(mbchar)) /* no colunm space left */
 
406
  {
 
407
#ifdef DEBUG
 
408
    fprintf(stderr,
 
409
            "Row_add_char: row->num_cols %d, col %d, mbchar->width %d\n",
 
410
            row->num_columns, col, Char_get_width(mbchar));
 
411
    
 
412
#endif
 
413
    return 1;
 
414
  }
 
415
 
 
416
  if(IS_COMBINED(mbchar))
 
417
  {
 
418
    int c=col-1;
 
419
    while(0<=c)
 
420
    {
 
421
      if(Row_is_char_drawn(row,c) &&
 
422
         Row_is_multicolumn_start(row,c))
 
423
      {
 
424
            /* found proper cell */
 
425
        int last_index = get_end_index(row,c,Row_get_cell_width(row,c));
 
426
        shift_buffer(row, last_index + Char_get_length(mbchar), last_index,
 
427
                     row->buffer.value_length - last_index);
 
428
        COPY_TO(row, last_index, mbchar);
 
429
        row->buffer.value_length += Char_get_length(mbchar);
 
430
        row->buffer.attrs[c][NUM_COMBINED]++;
 
431
        return 0;
 
432
      }
 
433
      c--;
 
434
    }
 
435
        /* failed to find proper cell to add combined char */
 
436
    return 1;
 
437
  }
 
438
  
 
439
  for(w=0;w<Char_get_width(mbchar);w++)
 
440
  {
 
441
    CellAttr_init(row->buffer.attrs[col+w],bold,blink,inverse,underline,
 
442
                  foreground,background,charset);
 
443
  }
 
444
 
 
445
  if(Row_is_char_drawn(row,col))
 
446
  {
 
447
        /* take care of character over the 2nd column
 
448
         of multibyte character */
 
449
    if(!Row_is_multicolumn_start(row,col))
 
450
    {
 
451
          /* This only cares double column character.
 
452
             Do I need to care more than 2 ? */
 
453
      RowBuffer_simple_replace_space(row, col-1);
 
454
          /* do this row->buffer.cell_to_char[col] += 1; */
 
455
      SET_INDEX(row,col,(GET_INDEX(row,col)+1));
 
456
    }
 
457
 
 
458
        /* take care of multi column character over the
 
459
           only the first column of multi column character  */
 
460
    if(Char_get_width(mbchar) > 1 && Row_get_cell_width(row,col+1) > 1)
 
461
    {
 
462
      SET_INDEX(row,(col+1),
 
463
                (get_end_index(row,col+Char_get_width(mbchar),1) - 1));
 
464
      RowBuffer_simple_replace_space(row, col+Char_get_width(mbchar));
 
465
      Row_set_updated(row,col,col+Char_get_width(mbchar)+1);
 
466
    }
 
467
    
 
468
    if(has_next_char(row,col,Char_get_width(mbchar)))
 
469
    {
 
470
      if(Char_get_width(mbchar) == 1 &&
 
471
         Row_get_cell_width(row,col) != Char_get_width(mbchar))
 
472
      {
 
473
/* do this, row->buffer.cell_to_char[col+1] = get_end_index(row,col+1,1)-1 */
 
474
        SET_INDEX(row,(col+1),(get_end_index(row,col+1,1) - 1));
 
475
        RowBuffer_simple_replace_space(row, col+1);
 
476
      }
 
477
      RowBuffer_replace_char(row,col,mbchar);
 
478
    }
 
479
    else
 
480
    {
 
481
      RowBuffer_add_char(row,col,mbchar);
 
482
    }
 
483
  }
 
484
  else
 
485
  {
 
486
    if(0 <= col-1 && !(Row_is_char_drawn(row,col-1)))
 
487
    {
 
488
      Row_add_char(row,col-1,&Blank,0,0,0,0,0,0,ASCII);
 
489
    }
 
490
    RowBuffer_add_char(row,col,mbchar);
 
491
  }
 
492
#ifdef DEBUG  
 
493
  if(row->buffer.value_max < row->buffer.value_length)
 
494
      fprintf(stderr,
 
495
              "Row_add_char: col %d, num_columns %d, value_length %d, value_max %d\n",
 
496
              col, row->num_columns, row->buffer.value_length,
 
497
              row->buffer.value_max);
 
498
#endif
 
499
  return 0;
 
500
}
 
501
 
 
502
void Row_resize(Row *row, int size)
 
503
{
 
504
  if(row && row->num_columns != size)
 
505
  {
 
506
    int old = row->num_columns;
 
507
    if(size < old)
 
508
    {
 
509
      RowBuffer_shrink(row,size);
 
510
    }
 
511
    row->buffer.attrs = (CellAttributes *)realloc(row->buffer.attrs,
 
512
                                                  size*sizeof(CellAttributes));
 
513
    row->buffer.cell_to_char = (int *)realloc(row->buffer.cell_to_char,
 
514
                                              size*sizeof(int));
 
515
    row->num_columns = size;
 
516
    if(old < row->num_columns)
 
517
    {
 
518
      simple_clear_cells(row,old,row->num_columns);
 
519
    }
 
520
  }
 
521
#ifdef DEBUG
 
522
  ON_ERROR(row,"Row_resize");
 
523
#endif
 
524
}
 
525
 
 
526
int Row_clear_cells(Row *row, int start_col, int end_col)
 
527
{
 
528
  int i,j;
 
529
  int ecol = -1;
 
530
  int scol = -1;
 
531
#ifdef DEBUG
 
532
  if(row->num_columns < start_col || start_col < 0 ||
 
533
     row->num_columns < end_col || end_col < 0 ||
 
534
     end_col < start_col)
 
535
      fprintf(stderr,
 
536
              "Row_clear_cells: row->num_cols = %d, start_col = %d end_col = %d\n",
 
537
              row->num_columns,start_col,end_col);
 
538
#endif
 
539
  if( end_col < start_col)
 
540
      return 1;
 
541
  scol = 0 < start_col ? start_col : 0;
 
542
  ecol = end_col < row->num_columns ? end_col : row->num_columns ;
 
543
 
 
544
  if(!Row_is_char_drawn(row,scol))
 
545
      return 0; /* do not need to clear */
 
546
 
 
547
  scol = Row_find_multicolum_char_start_column(row,scol);
 
548
 
 
549
  if(ecol < row->num_columns &&
 
550
     Row_is_char_drawn(row,ecol) &&
 
551
     !Row_is_multicolumn_start(row,ecol))
 
552
  {
 
553
    ecol = Row_find_multicolum_char_start_column(row,ecol);
 
554
    ecol += Row_get_cell_width(row,ecol);
 
555
  }
 
556
  
 
557
  if(row->num_columns <= ecol || !Row_is_char_drawn(row,ecol))
 
558
  { /*  we have no string on the right.  just clear cells */
 
559
    row->buffer.value_length = GET_INDEX(row,scol);
 
560
    simple_clear_cells(row,scol,ecol);
 
561
  }
 
562
  else
 
563
  { /* we have string on the right.  This case, insert SPACES */
 
564
    int old_length = old_length = GET_INDEX(row,ecol) - GET_INDEX(row,scol);
 
565
    int new_length = ecol - scol; /* white space consumes just one byte */
 
566
 
 
567
    shift_buffer(row,
 
568
                 GET_INDEX(row,scol) + new_length,
 
569
                 GET_INDEX(row,ecol),
 
570
                 row->buffer.value_length - GET_INDEX(row,ecol));
 
571
    for(i=scol,j=0;i<ecol;i++,j++)
 
572
    {
 
573
          /* do this, row->buffer.cell_to_char[i] = GET_INDEX(row,scol) + j; */
 
574
      SET_INDEX(row,i,(GET_INDEX(row,scol) + j));
 
575
      RowBuffer_simple_replace_space(row,i);
 
576
    }
 
577
    row->buffer.value_length += (new_length - old_length);
 
578
  }
 
579
  Row_set_wrapped(row,NOT_WRAPPED);
 
580
#ifdef DEBUG
 
581
  ON_ERROR(row,"Row_clear_cells");
 
582
#endif
 
583
  return 0;
 
584
}
 
585
 
 
586
int Row_clear(Row *row)
 
587
{
 
588
  Row_set_wrapped(row,NOT_WRAPPED);
 
589
  simple_clear_cells(row,0,row->num_columns);
 
590
  row->buffer.value_length = 0;
 
591
#ifdef DEBUG
 
592
  ON_ERROR(row,"Row_clear");
 
593
#endif
 
594
  return 0;
 
595
}
 
596
 
 
597
void Row_set_selection(Row *row ,int scol, int ecol, int selected)
 
598
{
 
599
  int c;
 
600
#ifdef DEBUG
 
601
  if(row->num_columns < scol || scol < 0 ||
 
602
     row->num_columns < ecol || ecol < 0 ||
 
603
     ecol < scol)
 
604
      fprintf(stderr,
 
605
              "Row_set_selection, row->num_cols = %d, scol = %d ecol = %d\n",
 
606
              row->num_columns,scol,ecol);
 
607
#endif
 
608
  if(selected)
 
609
  {
 
610
    for(c=scol;c<ecol;c++)
 
611
    {
 
612
      row->buffer.attrs[c][ATTRIBUTES] |= SELECTED;
 
613
    }
 
614
  }
 
615
  else
 
616
  {
 
617
    for(c=scol;c<ecol;c++)
 
618
    {
 
619
      row->buffer.attrs[c][ATTRIBUTES] &= (~SELECTED);
 
620
    }
 
621
  }
 
622
  Row_set_updated(row,scol,ecol);
 
623
#ifdef DEBUG
 
624
  ON_ERROR(row,"Row_set_selection");
 
625
#endif
 
626
}
 
627
 
 
628
int Row_compose_bytes(Row *row, int col_start, int col_end,
 
629
                      char *str, int str_len,
 
630
                      int *total_len, int *total_width, int pad)
 
631
{
 
632
  int scol;
 
633
  int ecol;
 
634
  int buf_end;
 
635
  int buf_start;
 
636
  *total_len = 0;
 
637
#ifdef DEBUG
 
638
  if(row->num_columns < col_start || col_start < 0 ||
 
639
     col_end < 0 || col_end < col_start)
 
640
  {
 
641
    fprintf(stderr,
 
642
            "Row_compose_bytes, row->num_cols = %d, col_start = %d col_end = %d\n",
 
643
            row->num_columns,col_start,col_end);
 
644
  }
 
645
#endif
 
646
 
 
647
  if(row->buffer.value_length <= 0)
 
648
  {
 
649
    if(pad)
 
650
    {
 
651
      int i;
 
652
      int min = str_len < row->num_columns ? str_len : row->num_columns;
 
653
      for(i=0;i<min;i++)
 
654
      {
 
655
        memcpy(str+i," ",1);
 
656
      }
 
657
      *total_len = min;
 
658
      *total_width = min;
 
659
    }
 
660
    else
 
661
    {
 
662
      *total_len = 0;
 
663
      *total_width = 0;
 
664
    }
 
665
    return 0;
 
666
  }
 
667
  if(col_end <= col_start)
 
668
      return 1;
 
669
  
 
670
  if(col_start < 0)
 
671
      col_start = 0;
 
672
  if(col_end > row->num_columns)
 
673
      col_end = row->num_columns;
 
674
  
 
675
  scol = col_start;
 
676
  ecol = col_end;
 
677
  
 
678
  while(scol < row->num_columns && !Row_is_multicolumn_start(row,scol))
 
679
      scol++;
 
680
  while(scol < ecol && !Row_is_char_drawn(row,ecol-1))
 
681
      ecol--;
 
682
 
 
683
  buf_start = GET_INDEX(row,scol);
 
684
  buf_end = GET_INDEX(row,ecol);
 
685
  *total_len = buf_end - buf_start;
 
686
 
 
687
  if(str_len < *total_len)
 
688
      *total_len = str_len;
 
689
  memcpy(str, (row->buffer.value + buf_start) ,*total_len);
 
690
 
 
691
  *total_width = ecol - scol;
 
692
  if(pad && *total_width < (col_end - col_start))
 
693
  {
 
694
    int num_spaces = row->num_columns - *total_width;
 
695
    int num_left = (str_len >  *total_len) ? (str_len - *total_len) : 0;
 
696
    int min = num_spaces < num_left ? num_spaces : num_left;
 
697
    int c;
 
698
 
 
699
    for(c=0;c<min;c++)
 
700
    {
 
701
      memcpy(str + *total_len + c, " ", 1);
 
702
    }
 
703
    *total_width += min;
 
704
    *total_len += min;
 
705
  }
 
706
#ifdef DEBUG
 
707
  ON_ERROR(row,"Row_compose_bytes");
 
708
#endif
 
709
  return 0;
 
710
}
 
711
 
 
712
static void simple_delete_right(Row *row, int col_start)
 
713
{
 
714
  col_start = Row_find_multicolum_char_start_column(row,col_start);
 
715
  row->buffer.value_length = GET_INDEX(row,col_start);
 
716
  simple_clear_cells(row,col_start,row->num_columns);
 
717
  Row_set_updated(row,col_start,row->num_columns);
 
718
}
 
719
 
 
720
int Row_insert_cells(Row *row, int col_start, int num_spaces)
 
721
{
 
722
  int i;
 
723
  int src_index = GET_INDEX(row,col_start);
 
724
  int length = GET_INDEX(row,row->num_columns - num_spaces) - GET_INDEX(row,col_start);
 
725
 
 
726
  if( (col_start < 0) ||
 
727
      (row->num_columns-1 <= col_start) ||
 
728
      (!Row_is_char_drawn(row,col_start)) )
 
729
  {
 
730
#ifdef DEBUG
 
731
    fprintf(stderr,"Row_insert_cells: invalid colmun: %d\n", col_start);
 
732
#endif    
 
733
    return 0;
 
734
  }
 
735
 
 
736
      /* inserting cells till right side */
 
737
  if( row->num_columns <= col_start + num_spaces )
 
738
  {
 
739
    row->buffer.value_length = GET_INDEX(row,col_start);
 
740
    simple_delete_right(row,col_start);
 
741
    return 0;
 
742
  }
 
743
  
 
744
  if(Row_get_cell_width(row,row->num_columns-num_spaces-1 ) > 1)
 
745
  {
 
746
        /* double column on the edge should be removed */
 
747
    row->buffer.value_length = GET_INDEX(row,row->num_columns-num_spaces-1);
 
748
    CLEAR_CELL(row,row->num_columns-num_spaces-1);
 
749
  }
 
750
 
 
751
  if(!Row_is_multicolumn_start(row,col_start))
 
752
  {
 
753
    if(Row_is_char_drawn(row,col_start+1))
 
754
    { 
 
755
      RowBuffer_simple_replace_space(row, col_start-1);
 
756
          /* do this, row->buffer.cell_to_char[col_start] += 1; */
 
757
      SET_INDEX(row,col_start,(GET_INDEX(row,col_start)+1));
 
758
      Row_add_char(row,col_start,&Blank,0,0,0,0,0,0,ASCII);
 
759
    }
 
760
    else
 
761
    {
 
762
      Row_clear_cells(row,col_start-1,col_start+1);
 
763
      return 0;
 
764
    }
 
765
  }
 
766
 
 
767
      /* Now we have to insert SPACES */
 
768
  if(Row_is_char_drawn(row,row->num_columns-1-num_spaces))
 
769
      row->buffer.value_length = GET_INDEX(row,row->num_columns-num_spaces);
 
770
  row->buffer.value_length += num_spaces;
 
771
  
 
772
  shift_cells(row,col_start, num_spaces);
 
773
  shift_index(row, (col_start + num_spaces), num_spaces);
 
774
  shift_buffer(row,src_index+num_spaces, src_index, length);
 
775
 
 
776
  i=col_start;
 
777
  RowBuffer_simple_replace_space(row, i);
 
778
  for(i++;i<col_start+num_spaces;i++)
 
779
  {
 
780
        /* do this, row->buffer.cell_to_char[i] = GET_INDEX(row,(i-1))+1; */
 
781
    SET_INDEX(row,i,(GET_INDEX(row,(i-1))+1));
 
782
    RowBuffer_simple_replace_space(row, i);
 
783
  }
 
784
#ifdef DEBUG  
 
785
  if(row->buffer.value_max < row->buffer.value_length)
 
786
  {
 
787
    fprintf(stderr,"Row_insert_cells after : num_columns %d, value_max = %d, value_length %d\n", row->num_columns, row->buffer.value_max, row->buffer.value_length);
 
788
  }
 
789
#endif  
 
790
  return 0;
 
791
}
 
792
 
 
793
/* col_start must be coordinated pointing at the fisrt column of
 
794
   multi column character */
 
795
static void simple_delete_cells(Row *row, int col_start, int num)
 
796
{
 
797
  int dest_index;
 
798
  int src_index;
 
799
  int diff;
 
800
 
 
801
  dest_index = GET_INDEX(row,col_start);
 
802
  src_index = GET_INDEX(row,col_start+num);
 
803
  diff = src_index - dest_index;
 
804
  
 
805
  shift_cells(row,col_start+num,-num);
 
806
  shift_buffer(row,dest_index,src_index,row->buffer.value_max-src_index);
 
807
  shift_index(row,col_start,-diff);
 
808
  row->buffer.value_length -= diff;
 
809
  Row_set_updated(row,col_start,row->num_columns);
 
810
}
 
811
 
 
812
int Row_delete_cells(Row *row, int col_start, int num)
 
813
{
 
814
 
 
815
      /* invalid case, do nothing */
 
816
  if(col_start < 0 || row->num_columns -1 <= col_start || num < 0)
 
817
  {
 
818
#ifdef DEBUG
 
819
    if(row->num_columns <= col_start || col_start < 0 || num < 0)
 
820
    {
 
821
      fprintf(stderr,
 
822
              "Row_delete_cells, row->num_cols = %d, col_start = %d\n",
 
823
              row->num_columns,col_start);
 
824
    }
 
825
#endif
 
826
    return 1;
 
827
  }
 
828
 
 
829
      /* No need to delete characters */
 
830
  if(!Row_is_char_drawn(row,col_start))
 
831
      return 0;
 
832
 
 
833
      /* delete right side, we don't need to shift right side string */
 
834
  if( (row->num_columns <= col_start + num) ||
 
835
      !Row_is_char_drawn(row,col_start+num) )
 
836
  {
 
837
    simple_delete_right(row,col_start);
 
838
    return 0;
 
839
  }
 
840
      /* if we will try to delete only fisrt(or some) column(s)
 
841
         of multicolumn char */
 
842
  else if(!Row_is_multicolumn_start(row,col_start+num))
 
843
  {
 
844
    int end_col = Row_find_multicolum_char_start_column(row,col_start+num);
 
845
        /* if the char has another char on right */
 
846
    if(has_next_char(row,end_col,
 
847
                     end_col + Row_get_cell_width(row, end_col)))
 
848
    {
 
849
/* do this,
 
850
   row->buffer.cell_to_char[col_start+num]=GET_INDEX(row,col_start+num+1)-1 */
 
851
      SET_INDEX(row,(col_start+num),(GET_INDEX(row,col_start+num+1)-1));
 
852
      RowBuffer_simple_replace_space(row, col_start+num);
 
853
    }
 
854
    else /* if that multi column char is the last char */
 
855
    {
 
856
      simple_delete_right(row,col_start);
 
857
      return 0;
 
858
    }
 
859
  }
 
860
      /* Now we have to delete and shift right side of string */
 
861
 
 
862
      /* if col_start is not first column of multicolumn char
 
863
         replace left side columns as spaces 
 
864
       */
 
865
  if(!Row_is_multicolumn_start(row,col_start))
 
866
  {
 
867
        /* only handle double width char */
 
868
/* do this,
 
869
   row->buffer.cell_to_char[col_start] = GET_INDEX(row,col_start-1) + 1; */
 
870
    SET_INDEX(row,col_start,(GET_INDEX(row,col_start-1) + 1));
 
871
    RowBuffer_simple_replace_space(row, col_start-1);
 
872
  }
 
873
  simple_delete_cells(row,col_start,num);
 
874
  
 
875
#ifdef DEBUG
 
876
  ON_ERROR(row,"Row_delete_cells");
 
877
#endif
 
878
  return 0;
 
879
}
 
880
 
 
881
int Row_copy(Row *src, Row *dest)
 
882
{
 
883
  int num_col = src->num_columns < dest->num_columns ? src->num_columns : dest->num_columns;
 
884
  int last_index = GET_INDEX(src,num_col);
 
885
 
 
886
  if(dest->buffer.value_max < last_index)
 
887
  {
 
888
    dest->buffer.value = realloc(dest->buffer.value,last_index);
 
889
    dest->buffer.value_max = last_index;
 
890
  }
 
891
 
 
892
  memcpy(dest->buffer.value,src->buffer.value,last_index);
 
893
  dest->buffer.value_length = last_index;
 
894
 
 
895
  memcpy(dest->buffer.cell_to_char,
 
896
         src->buffer.cell_to_char,
 
897
         num_col*sizeof(int));
 
898
  memcpy(dest->buffer.attrs,
 
899
         src->buffer.attrs,
 
900
         num_col*sizeof(CellAttributes));
 
901
  if(num_col < dest->num_columns)
 
902
  {
 
903
    simple_clear_cells(dest,num_col,dest->num_columns);
 
904
  }
 
905
#ifdef DEBUG
 
906
  ON_ERROR(src,"Row_copy(src)");
 
907
  ON_ERROR(dest,"Row_copy(dest)");
 
908
#endif
 
909
  return 0;
 
910
}
 
911
 
 
912
void Row_set_char_drawn(Row *row, int col,int value)
 
913
{
 
914
#ifdef DEBUG
 
915
  if(row->num_columns <= col || col < 0)
 
916
      fprintf(stderr,
 
917
              "Row_set_char_drawn, row->num_cols = %d, col = %d\n",
 
918
              row->num_columns,col);
 
919
#endif
 
920
  if(!value && Row_is_char_drawn(row,col))
 
921
  {
 
922
    if(has_next_char(row,col,Row_get_cell_width(row,col)))
 
923
    {
 
924
      int end_index = GET_INDEX(row,col+Row_get_cell_width(row,col));
 
925
      int start_index = GET_INDEX(row,col);
 
926
 
 
927
      if(end_index > start_index+1)
 
928
      {
 
929
        int diff = end_index - start_index - 1;
 
930
        shift_buffer(row,end_index,start_index+1,row->num_columns-end_index);
 
931
        shift_index(row,start_index+1,diff);
 
932
        
 
933
      }
 
934
      RowBuffer_simple_replace_space(row,col);
 
935
    }
 
936
    else
 
937
    {
 
938
      CLEAR_CELL(row,col);
 
939
    }
 
940
  }
 
941
#ifdef DEBUG
 
942
  ON_ERROR(row,"Row_set_char_drawn");
 
943
#endif
 
944
}