/[LeafOK_CVS]/lbbs/src/editor.c
ViewVC logotype

Annotation of /lbbs/src/editor.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.40 - (hide annotations)
Sun Jul 20 02:04:21 2025 UTC (7 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.39: +2 -0 lines
Content type: text/x-csrc
Logging incorrent UTF8 input only when _DEBUG is defined

1 sysadm 1.1 /***************************************************************************
2     editor.h - description
3     -------------------
4     copyright : (C) 2004-2025 by Leaflet
5     email : leaflet@leafok.com
6     ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 3 of the License, or *
13     * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17 sysadm 1.31 #include "bbs.h"
18     #include "common.h"
19 sysadm 1.1 #include "editor.h"
20     #include "io.h"
21     #include "log.h"
22 sysadm 1.31 #include "memory_pool.h"
23 sysadm 1.1 #include "str_process.h"
24     #include <stdlib.h>
25 sysadm 1.30 #include <string.h>
26 sysadm 1.1 #include <sys/param.h>
27    
28 sysadm 1.12 #define EDITOR_ESC_DISPLAY_STR "\033[32m*\033[m"
29 sysadm 1.16 #define EDITOR_MEM_POOL_LINE_PER_CHUNK 1000
30     #define EDITOR_MEM_POOL_CHUNK_LIMIT (MAX_EDITOR_DATA_LINES / EDITOR_MEM_POOL_LINE_PER_CHUNK + 1)
31    
32     static MEMORY_POOL *p_mp_data_line;
33     static MEMORY_POOL *p_mp_editor_data;
34    
35     int editor_memory_pool_init(void)
36     {
37     if (p_mp_data_line != NULL || p_mp_editor_data != NULL)
38     {
39     log_error("Editor mem pool already initialized\n");
40     return -1;
41     }
42    
43     p_mp_data_line = memory_pool_init(MAX_EDITOR_DATA_LINE_LENGTH, EDITOR_MEM_POOL_LINE_PER_CHUNK, EDITOR_MEM_POOL_CHUNK_LIMIT);
44     if (p_mp_data_line == NULL)
45     {
46     log_error("Memory pool init error\n");
47     return -2;
48     }
49    
50     p_mp_editor_data = memory_pool_init(sizeof(EDITOR_DATA), 1, 1);
51     if (p_mp_data_line == NULL)
52     {
53     log_error("Memory pool init error\n");
54     return -3;
55     }
56    
57     return 0;
58     }
59    
60     void editor_memory_pool_cleanup(void)
61     {
62     if (p_mp_data_line != NULL)
63     {
64     memory_pool_cleanup(p_mp_data_line);
65     p_mp_data_line = NULL;
66     }
67    
68     if (p_mp_editor_data != NULL)
69     {
70     memory_pool_cleanup(p_mp_editor_data);
71     p_mp_editor_data = NULL;
72     }
73     }
74 sysadm 1.12
75 sysadm 1.1 EDITOR_DATA *editor_data_load(const char *p_data)
76     {
77     EDITOR_DATA *p_editor_data;
78 sysadm 1.4 char *p_data_line = NULL;
79 sysadm 1.22 long line_offsets[MAX_EDITOR_DATA_LINES + 1];
80 sysadm 1.1 long current_data_line_length = 0;
81 sysadm 1.14 long i;
82 sysadm 1.1
83     if (p_data == NULL)
84     {
85     log_error("editor_data_load() error: NULL pointer\n");
86     return NULL;
87     }
88    
89 sysadm 1.16 p_editor_data = memory_pool_alloc(p_mp_editor_data);
90 sysadm 1.1 if (p_editor_data == NULL)
91     {
92 sysadm 1.16 log_error("memory_pool_alloc() error\n");
93 sysadm 1.1 return NULL;
94     }
95    
96 sysadm 1.39 p_editor_data->display_line_total = split_data_lines(p_data, SCREEN_COLS, line_offsets, MAX_EDITOR_DATA_LINES + 1,
97     0, p_editor_data->display_line_widths);
98 sysadm 1.1
99     for (i = 0; i < p_editor_data->display_line_total; i++)
100     {
101     p_editor_data->display_line_lengths[i] = line_offsets[i + 1] - line_offsets[i];
102    
103     if (i == 0 ||
104 sysadm 1.2 current_data_line_length + p_editor_data->display_line_lengths[i] + 1 > MAX_EDITOR_DATA_LINE_LENGTH ||
105 sysadm 1.1 (p_editor_data->display_line_lengths[i - 1] > 0 && p_data[line_offsets[i - 1] + p_editor_data->display_line_lengths[i - 1] - 1] == '\n'))
106     {
107     // Allocate new data line
108 sysadm 1.16 p_data_line = memory_pool_alloc(p_mp_data_line);
109 sysadm 1.4 if (p_data_line == NULL)
110 sysadm 1.1 {
111 sysadm 1.16 log_error("memory_pool_alloc() error: i = %d\n", i);
112 sysadm 1.1 // Cleanup
113 sysadm 1.14 editor_data_cleanup(p_editor_data);
114 sysadm 1.1 return NULL;
115     }
116    
117 sysadm 1.4 p_editor_data->p_display_lines[i] = p_data_line;
118 sysadm 1.2 current_data_line_length = 0;
119 sysadm 1.1 }
120     else
121     {
122     p_editor_data->p_display_lines[i] = p_editor_data->p_display_lines[i - 1] + p_editor_data->display_line_lengths[i - 1];
123     }
124    
125     memcpy(p_editor_data->p_display_lines[i], p_data + line_offsets[i], (size_t)p_editor_data->display_line_lengths[i]);
126     current_data_line_length += p_editor_data->display_line_lengths[i];
127 sysadm 1.19
128     // Trim \n from last line
129 sysadm 1.20 if (i + 1 == p_editor_data->display_line_total &&
130     p_editor_data->display_line_lengths[i] > 0 &&
131 sysadm 1.19 p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n')
132     {
133     p_editor_data->display_line_lengths[i]--;
134 sysadm 1.39 p_editor_data->display_line_widths[i]--;
135 sysadm 1.19 current_data_line_length--;
136     }
137 sysadm 1.4 p_data_line[current_data_line_length] = '\0';
138 sysadm 1.1 }
139    
140 sysadm 1.26 memset(p_editor_data->p_display_lines + p_editor_data->display_line_total, 0, MAX_EDITOR_DATA_LINES - (size_t)p_editor_data->display_line_total);
141 sysadm 1.4
142 sysadm 1.1 return p_editor_data;
143     }
144    
145     long editor_data_save(const EDITOR_DATA *p_editor_data, char *p_data, size_t buf_len)
146     {
147     long current_pos = 0;
148     long i;
149    
150     if (p_editor_data == NULL || p_data == NULL)
151     {
152     log_error("editor_data_save() error: NULL pointer\n");
153     return -1;
154     }
155    
156     for (i = 0; i < p_editor_data->display_line_total; i++)
157     {
158     if (current_pos + p_editor_data->display_line_lengths[i] + 1 > buf_len)
159     {
160     log_error("Data buffer not longer enough %d > %d\n", current_pos + p_editor_data->display_line_lengths[i] + 1, buf_len);
161     p_data[current_pos] = '\0';
162     return -2;
163     }
164    
165     memcpy(p_data + current_pos, p_editor_data->p_display_lines[i], (size_t)p_editor_data->display_line_lengths[i]);
166     current_pos += p_editor_data->display_line_lengths[i];
167     }
168    
169     p_data[current_pos] = '\0';
170    
171     return current_pos;
172     }
173    
174     void editor_data_cleanup(EDITOR_DATA *p_editor_data)
175     {
176 sysadm 1.14 char *p_data_line = NULL;
177 sysadm 1.1 long i;
178    
179     if (p_editor_data == NULL)
180     {
181     return;
182     }
183    
184 sysadm 1.14 for (i = 0; i < p_editor_data->display_line_total; i++)
185     {
186     if (p_data_line == NULL)
187     {
188     p_data_line = p_editor_data->p_display_lines[i];
189     }
190    
191     if (p_editor_data->display_line_lengths[i] > 0 &&
192     p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n')
193     {
194 sysadm 1.16 memory_pool_free(p_mp_data_line, p_data_line);
195 sysadm 1.14 p_data_line = NULL;
196     }
197     }
198    
199     if (p_data_line != NULL)
200 sysadm 1.1 {
201 sysadm 1.16 memory_pool_free(p_mp_data_line, p_data_line);
202 sysadm 1.1 }
203    
204 sysadm 1.16 memory_pool_free(p_mp_editor_data, p_editor_data);
205 sysadm 1.1 }
206    
207 sysadm 1.3 int editor_data_insert(EDITOR_DATA *p_editor_data, long *p_display_line, long *p_offset,
208 sysadm 1.2 const char *str, int str_len, long *p_last_updated_line)
209     {
210 sysadm 1.3 long display_line = *p_display_line;
211     long offset = *p_offset;
212 sysadm 1.4 char *p_data_line = NULL;
213 sysadm 1.2 long len_data_line;
214     long offset_data_line;
215     long last_display_line; // of data line
216 sysadm 1.4 long line_offsets[MAX_EDITOR_DATA_LINE_LENGTH + 1];
217 sysadm 1.39 int line_widths[MAX_EDITOR_DATA_LINE_LENGTH + 1];
218 sysadm 1.4 long split_line_total;
219 sysadm 1.32 long i;
220 sysadm 1.15 int len;
221     int eol;
222     int display_len;
223 sysadm 1.2
224     if (p_editor_data == NULL || p_last_updated_line == NULL)
225     {
226     log_error("editor_data_op() error: NULL pointer\n");
227     return -1;
228     }
229    
230     // Get length of current data line
231     len_data_line = 0;
232     p_data_line = p_editor_data->p_display_lines[display_line];
233     for (i = display_line - 1; i >= 0; i--)
234     {
235     if (p_editor_data->display_line_lengths[i] > 0 &&
236     p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n') // reach end of prior data line
237     {
238     break;
239     }
240    
241     len_data_line += p_editor_data->display_line_lengths[i];
242     p_data_line = p_editor_data->p_display_lines[i];
243     }
244     offset_data_line = len_data_line + offset;
245     last_display_line = p_editor_data->display_line_total - 1;
246     for (i = display_line; i < p_editor_data->display_line_total; i++)
247     {
248     len_data_line += p_editor_data->display_line_lengths[i];
249    
250     if (p_editor_data->display_line_lengths[i] > 0 &&
251     p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n') // reach end of current data line
252     {
253     last_display_line = i;
254     break;
255     }
256     }
257    
258     // Split current data line if over-length
259 sysadm 1.37 if (len_data_line + str_len + 2 > MAX_EDITOR_DATA_LINE_LENGTH || str[0] == CR)
260 sysadm 1.2 {
261 sysadm 1.14 if (p_editor_data->display_line_total >= MAX_EDITOR_DATA_LINES)
262 sysadm 1.2 {
263 sysadm 1.29 #ifdef _DEBUG
264     log_error("Split line error, display_line_total(%ld) reach limit(%d)\n",
265     p_editor_data->display_line_total, MAX_EDITOR_DATA_LINES);
266     #endif
267    
268 sysadm 1.2 return -2;
269     }
270    
271     // Allocate new data line
272 sysadm 1.16 p_data_line = memory_pool_alloc(p_mp_data_line);
273 sysadm 1.4 if (p_data_line == NULL)
274 sysadm 1.2 {
275 sysadm 1.16 log_error("memory_pool_alloc() error\n");
276 sysadm 1.2 return -2;
277     }
278 sysadm 1.3
279 sysadm 1.37 if (offset_data_line + str_len + 2 >= MAX_EDITOR_DATA_LINE_LENGTH || str[0] == CR)
280 sysadm 1.2 {
281 sysadm 1.6 if (str[0] == CR)
282     {
283     str_len = 0;
284     }
285 sysadm 1.3
286 sysadm 1.4 // Copy str to new data line
287     memcpy(p_data_line, str, (size_t)str_len);
288    
289     // Copy rest part of current data line to new data line
290     memcpy(p_data_line + str_len,
291 sysadm 1.2 p_editor_data->p_display_lines[display_line] + offset,
292 sysadm 1.4 (size_t)(len_data_line - offset_data_line));
293    
294     p_data_line[str_len + len_data_line - offset_data_line] = '\0';
295 sysadm 1.2
296     // Add line ending to current display line (data line)
297     p_editor_data->p_display_lines[display_line][offset] = '\n';
298     p_editor_data->p_display_lines[display_line][offset + 1] = '\0';
299     p_editor_data->display_line_lengths[display_line] = offset + 1;
300 sysadm 1.4
301     *p_display_line = display_line + 1;
302     *p_offset = str_len;
303 sysadm 1.2 }
304 sysadm 1.6 else
305     {
306     // Copy rest part of current data line to new data line
307     memcpy(p_data_line,
308     p_editor_data->p_display_lines[display_line] + offset,
309     (size_t)(len_data_line - offset_data_line));
310    
311     p_data_line[len_data_line - offset_data_line] = '\0';
312    
313     // Append str to current display line
314     memcpy(p_editor_data->p_display_lines[display_line] + offset, str, (size_t)str_len);
315    
316     // Add line ending to current display line (data line)
317     p_editor_data->p_display_lines[display_line][offset + str_len] = '\n';
318     p_editor_data->p_display_lines[display_line][offset + str_len + 1] = '\0';
319     p_editor_data->display_line_lengths[display_line] = offset + str_len + 1;
320    
321     *p_display_line = display_line;
322     *p_offset = offset + str_len;
323     }
324 sysadm 1.2
325 sysadm 1.39 // Update display width of current display line
326     len = split_line(p_editor_data->p_display_lines[display_line], SCREEN_COLS, &eol, &display_len, 0);
327     p_editor_data->display_line_widths[display_line] = display_len;
328    
329 sysadm 1.4 split_line_total = last_display_line - display_line + 3;
330    
331     // Set start display_line for spliting new data line
332 sysadm 1.2 display_line++;
333 sysadm 1.4
334     *p_last_updated_line = p_editor_data->display_line_total;
335 sysadm 1.2 }
336 sysadm 1.4 else // insert str into current data line at offset_data_line
337 sysadm 1.2 {
338 sysadm 1.4 memmove(p_data_line + offset_data_line + str_len, p_data_line + offset_data_line, (size_t)(len_data_line - offset_data_line));
339     memcpy(p_data_line + offset_data_line, str, (size_t)str_len);
340     p_data_line[len_data_line + str_len] = '\0';
341 sysadm 1.3
342 sysadm 1.4 // Set p_data_line to head of current display line
343     p_data_line = p_editor_data->p_display_lines[display_line];
344     split_line_total = last_display_line - display_line + 3;
345 sysadm 1.3
346 sysadm 1.4 *p_display_line = display_line;
347     *p_offset = offset + str_len;
348 sysadm 1.2 }
349    
350 sysadm 1.4 // Split current data line since beginning of current display line
351 sysadm 1.39 split_line_total = split_data_lines(p_data_line, SCREEN_COLS, line_offsets, split_line_total, 0, line_widths);
352 sysadm 1.2
353 sysadm 1.4 for (i = 0; i < split_line_total; i++)
354 sysadm 1.2 {
355 sysadm 1.4 if (display_line + i > last_display_line)
356 sysadm 1.2 {
357 sysadm 1.4 // Insert blank display line after last_display_line
358     if (p_editor_data->display_line_total >= MAX_EDITOR_DATA_LINES)
359     {
360 sysadm 1.29 #ifdef _DEBUG
361     log_error("display_line_total over limit %d >= %d\n", p_editor_data->display_line_total, MAX_EDITOR_DATA_LINES);
362     #endif
363    
364 sysadm 1.15 // Terminate prior display line with \n, to avoid error on cleanup
365     if (display_line + i - 1 >= 0 && p_editor_data->display_line_lengths[display_line + i - 1] > 0)
366     {
367 sysadm 1.24 len = split_line(p_editor_data->p_display_lines[display_line + i - 1], SCREEN_COLS - 1, &eol, &display_len, 0);
368 sysadm 1.15 p_editor_data->p_display_lines[display_line + i - 1][len] = '\n';
369     p_editor_data->p_display_lines[display_line + i - 1][len + 1] = '\0';
370     p_editor_data->display_line_lengths[display_line + i - 1] = len + 1;
371 sysadm 1.39 p_editor_data->display_line_widths[display_line + i - 1] = display_len;
372 sysadm 1.15 }
373     if (*p_offset >= p_editor_data->display_line_lengths[*p_display_line])
374     {
375     *p_offset = p_editor_data->display_line_lengths[*p_display_line] - 1;
376     }
377     break;
378 sysadm 1.4 }
379 sysadm 1.32
380     // for (j = p_editor_data->display_line_total; j > last_display_line + 1; j--)
381     // {
382     // p_editor_data->p_display_lines[j] = p_editor_data->p_display_lines[j - 1];
383     // p_editor_data->display_line_lengths[j] = p_editor_data->display_line_lengths[j - 1];
384 sysadm 1.39 // p_editor_data->display_line_widths[j] = p_editor_data->display_line_widths[j - 1];
385 sysadm 1.32 // }
386     memmove(p_editor_data->p_display_lines + last_display_line + 2,
387     p_editor_data->p_display_lines + last_display_line + 1,
388     (size_t)(p_editor_data->display_line_total - last_display_line - 1) *
389     sizeof(p_editor_data->p_display_lines[last_display_line + 1]));
390     memmove(p_editor_data->display_line_lengths + last_display_line + 2,
391     p_editor_data->display_line_lengths + last_display_line + 1,
392     (size_t)(p_editor_data->display_line_total - last_display_line - 1) *
393     sizeof(p_editor_data->display_line_lengths[last_display_line + 1]));
394 sysadm 1.39 memmove(p_editor_data->display_line_widths + last_display_line + 2,
395     p_editor_data->display_line_widths + last_display_line + 1,
396     (size_t)(p_editor_data->display_line_total - last_display_line - 1) *
397     sizeof(p_editor_data->display_line_widths[last_display_line + 1]));
398 sysadm 1.32
399 sysadm 1.4 last_display_line++;
400 sysadm 1.32 *p_last_updated_line = p_editor_data->display_line_total;
401 sysadm 1.4 (p_editor_data->display_line_total)++;
402 sysadm 1.2 }
403    
404 sysadm 1.4 p_editor_data->display_line_lengths[display_line + i] = line_offsets[i + 1] - line_offsets[i];
405 sysadm 1.39 p_editor_data->display_line_widths[display_line + i] = line_widths[i];
406 sysadm 1.4 p_editor_data->p_display_lines[display_line + i] =
407     (i == 0
408     ? p_data_line
409     : (p_editor_data->p_display_lines[display_line + i - 1] + p_editor_data->display_line_lengths[display_line + i - 1]));
410 sysadm 1.2
411 sysadm 1.4 if (p_editor_data->display_line_lengths[display_line + i] > 0 &&
412     p_editor_data->p_display_lines[display_line + i][p_editor_data->display_line_lengths[display_line + i] - 1] == '\n')
413 sysadm 1.3 {
414 sysadm 1.4 break;
415 sysadm 1.3 }
416 sysadm 1.4 }
417 sysadm 1.3
418 sysadm 1.7 *p_last_updated_line = MAX(display_line + MIN(i, split_line_total - 1), *p_last_updated_line);
419 sysadm 1.2
420 sysadm 1.14 if (*p_offset >= p_editor_data->display_line_lengths[*p_display_line])
421 sysadm 1.3 {
422 sysadm 1.18 if (*p_display_line + 1 < p_editor_data->display_line_total)
423 sysadm 1.15 {
424 sysadm 1.18 *p_offset -= p_editor_data->display_line_lengths[*p_display_line];
425 sysadm 1.15 (*p_display_line)++;
426     }
427 sysadm 1.22 }
428    
429     // Prevent the last display line from being over-length
430     if (p_editor_data->display_line_total == MAX_EDITOR_DATA_LINES)
431     {
432 sysadm 1.24 len = split_line(p_editor_data->p_display_lines[p_editor_data->display_line_total - 1], SCREEN_COLS - 1, &eol, &display_len, 0);
433 sysadm 1.22 p_editor_data->p_display_lines[p_editor_data->display_line_total - 1][len] = '\0';
434     p_editor_data->display_line_lengths[p_editor_data->display_line_total - 1] = len;
435 sysadm 1.39 p_editor_data->display_line_widths[p_editor_data->display_line_total - 1] = display_len;
436 sysadm 1.22 if (*p_display_line + 1 >= p_editor_data->display_line_total)
437 sysadm 1.20 {
438 sysadm 1.22 *p_offset = MIN(*p_offset, len);
439     *p_display_line = p_editor_data->display_line_total - 1;
440 sysadm 1.20 }
441 sysadm 1.3 }
442    
443 sysadm 1.4 return 0;
444 sysadm 1.2 }
445    
446 sysadm 1.23 int editor_data_delete(EDITOR_DATA *p_editor_data, long *p_display_line, long *p_offset,
447 sysadm 1.2 long *p_last_updated_line)
448     {
449 sysadm 1.23 long display_line = *p_display_line;
450     long offset = *p_offset;
451 sysadm 1.7 char *p_data_line = NULL;
452     long len_data_line;
453     long offset_data_line;
454     long last_display_line; // of data line
455     long line_offsets[MAX_EDITOR_DATA_LINE_LENGTH + 1];
456 sysadm 1.39 int line_widths[MAX_EDITOR_DATA_LINE_LENGTH + 1];
457 sysadm 1.7 long split_line_total;
458     long i, j;
459     int str_len = 0;
460 sysadm 1.39 char c;
461 sysadm 1.7
462     if (p_editor_data == NULL || p_last_updated_line == NULL)
463     {
464     log_error("editor_data_op() error: NULL pointer\n");
465     return -1;
466     }
467    
468     // Get length of current data line
469     len_data_line = 0;
470     p_data_line = p_editor_data->p_display_lines[display_line];
471     for (i = display_line - 1; i >= 0; i--)
472     {
473     if (p_editor_data->display_line_lengths[i] > 0 &&
474     p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n') // reach end of prior data line
475     {
476     break;
477     }
478    
479     len_data_line += p_editor_data->display_line_lengths[i];
480     p_data_line = p_editor_data->p_display_lines[i];
481     }
482     offset_data_line = len_data_line + offset;
483     last_display_line = p_editor_data->display_line_total - 1;
484     for (i = display_line; i < p_editor_data->display_line_total; i++)
485     {
486     len_data_line += p_editor_data->display_line_lengths[i];
487    
488     if (p_editor_data->display_line_lengths[i] > 0 &&
489     p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n') // reach end of current data line
490     {
491     last_display_line = i;
492     break;
493     }
494     }
495    
496 sysadm 1.18 if (offset_data_line >= len_data_line) // end-of-line
497     {
498     return 0;
499     }
500    
501 sysadm 1.7 // Check str to be deleted
502     if (p_data_line[offset_data_line] > 0 && p_data_line[offset_data_line] < 127)
503     {
504     str_len = 1;
505     }
506 sysadm 1.39 else if (p_data_line[offset_data_line] & 0b10000000) // head of multi-byte character
507 sysadm 1.7 {
508 sysadm 1.39 str_len = 1;
509     c = (p_data_line[offset_data_line] & 0b01110000) << 1;
510     while (c & 0b10000000)
511     {
512     str_len++;
513     c = (c & 0b01111111) << 1;
514     }
515 sysadm 1.7 }
516     else
517     {
518 sysadm 1.18 log_error("Some strange character at display_line %ld, offset %ld: %d %d\n",
519     display_line, offset, p_data_line[offset_data_line], p_data_line[offset_data_line + 1]);
520 sysadm 1.10 str_len = 1;
521 sysadm 1.7 }
522    
523     // Current display line is (almost) empty
524     if (offset_data_line + str_len > len_data_line ||
525     (offset_data_line + str_len == len_data_line && p_data_line[offset_data_line] == '\n'))
526     {
527 sysadm 1.9 if (display_line + 1 >= p_editor_data->display_line_total) // No additional display line (data line)
528     {
529     return 0;
530     }
531    
532     len_data_line = 0; // Next data line
533     last_display_line = p_editor_data->display_line_total - 1;
534     for (i = display_line + 1; i < p_editor_data->display_line_total; i++)
535     {
536     len_data_line += p_editor_data->display_line_lengths[i];
537    
538     if (p_editor_data->display_line_lengths[i] > 0 &&
539     p_editor_data->p_display_lines[i][p_editor_data->display_line_lengths[i] - 1] == '\n') // reach end of current data line
540     {
541     last_display_line = i;
542     break;
543     }
544     }
545    
546     if (offset_data_line + len_data_line + 1 > MAX_EDITOR_DATA_LINE_LENGTH) // No enough buffer to merge current data line with next data line
547     {
548     return 0;
549     }
550    
551     // Append next data line to current one
552     memcpy(p_data_line + offset_data_line, p_editor_data->p_display_lines[display_line + 1], (size_t)len_data_line);
553     p_data_line[offset_data_line + len_data_line] = '\0';
554    
555     // Recycle next data line
556 sysadm 1.16 memory_pool_free(p_mp_data_line, p_editor_data->p_display_lines[display_line + 1]);
557 sysadm 1.9 }
558     else
559     {
560     memmove(p_data_line + offset_data_line, p_data_line + offset_data_line + str_len, (size_t)(len_data_line - offset_data_line - str_len));
561     p_data_line[len_data_line - str_len] = '\0';
562     len_data_line -= str_len;
563 sysadm 1.7 }
564    
565     // Set p_data_line to head of current display line
566     p_data_line = p_editor_data->p_display_lines[display_line];
567     split_line_total = last_display_line - display_line + 2;
568    
569     // Split current data line since beginning of current display line
570 sysadm 1.39 split_line_total = split_data_lines(p_data_line, SCREEN_COLS, line_offsets, split_line_total, 0, line_widths);
571 sysadm 1.7
572     for (i = 0; i < split_line_total; i++)
573     {
574     p_editor_data->display_line_lengths[display_line + i] = line_offsets[i + 1] - line_offsets[i];
575 sysadm 1.39 p_editor_data->display_line_widths[display_line + i] = line_widths[i];
576 sysadm 1.7 p_editor_data->p_display_lines[display_line + i] =
577     (i == 0
578     ? p_data_line
579     : (p_editor_data->p_display_lines[display_line + i - 1] + p_editor_data->display_line_lengths[display_line + i - 1]));
580    
581     if (p_editor_data->display_line_lengths[display_line + i] > 0 &&
582     p_editor_data->p_display_lines[display_line + i][p_editor_data->display_line_lengths[display_line + i] - 1] == '\n')
583     {
584     break;
585     }
586     }
587    
588     *p_last_updated_line = display_line + MIN(i, split_line_total - 1);
589    
590 sysadm 1.18 if (*p_last_updated_line < last_display_line)
591 sysadm 1.7 {
592     // Remove redundant display line after last_display_line
593 sysadm 1.32 // for (j = last_display_line + 1; j < p_editor_data->display_line_total; j++)
594     // {
595     // p_editor_data->p_display_lines[j - (last_display_line - *p_last_updated_line)] = p_editor_data->p_display_lines[j];
596     // p_editor_data->display_line_lengths[j - (last_display_line - *p_last_updated_line)] = p_editor_data->display_line_lengths[j];
597 sysadm 1.39 // p_editor_data->display_line_widths[j - (last_display_line - *p_last_updated_line)] = p_editor_data->display_line_widths[j];
598 sysadm 1.32 // }
599     memmove(p_editor_data->p_display_lines + *p_last_updated_line + 1,
600     p_editor_data->p_display_lines + last_display_line + 1,
601     (size_t)(p_editor_data->display_line_total - last_display_line - 1) *
602     sizeof(p_editor_data->p_display_lines[last_display_line + 1]));
603     memmove(p_editor_data->display_line_lengths + *p_last_updated_line + 1,
604     p_editor_data->display_line_lengths + last_display_line + 1,
605     (size_t)(p_editor_data->display_line_total - last_display_line - 1) *
606     sizeof(p_editor_data->display_line_lengths[last_display_line + 1]));
607 sysadm 1.39 memmove(p_editor_data->display_line_widths + *p_last_updated_line + 1,
608     p_editor_data->display_line_widths + last_display_line + 1,
609     (size_t)(p_editor_data->display_line_total - last_display_line - 1) *
610     sizeof(p_editor_data->display_line_widths[last_display_line + 1]));
611 sysadm 1.7
612 sysadm 1.18 j = p_editor_data->display_line_total;
613     (p_editor_data->display_line_total) -= (last_display_line - *p_last_updated_line);
614     *p_last_updated_line = MAX(j - 1, *p_last_updated_line);
615 sysadm 1.7 }
616    
617 sysadm 1.23 // Return real offset
618     *p_offset = offset;
619    
620 sysadm 1.9 return str_len;
621 sysadm 1.2 }
622    
623     static int editor_display_key_handler(int *p_key, EDITOR_CTX *p_ctx)
624 sysadm 1.1 {
625     switch (*p_key)
626     {
627     case 0: // Set msg
628     snprintf(p_ctx->msg, sizeof(p_ctx->msg),
629 sysadm 1.39 "| 退出[\033[32mCtrl-W\033[33m] |");
630 sysadm 1.1 break;
631 sysadm 1.24 case KEY_CSI:
632     *p_key = KEY_ESC;
633     break;
634 sysadm 1.1 }
635    
636     return 0;
637     }
638    
639     int editor_display(EDITOR_DATA *p_editor_data)
640     {
641     static int show_help = 1;
642     char buffer[MAX_EDITOR_DATA_LINE_LENGTH];
643 sysadm 1.2 EDITOR_CTX ctx;
644 sysadm 1.1 int ch = 0;
645 sysadm 1.4 char input_str[4];
646 sysadm 1.39 char c;
647 sysadm 1.3 int str_len = 0;
648     int input_ok;
649     const int screen_begin_row = 1;
650 sysadm 1.14 const int screen_row_total = SCREEN_ROWS - screen_begin_row;
651     int output_current_row = screen_begin_row;
652     int output_end_row = SCREEN_ROWS - 1;
653 sysadm 1.1 long int line_current = 0;
654     long int len;
655     int loop;
656     int eol, display_len;
657     long row_pos = 1, col_pos = 1;
658 sysadm 1.3 long display_line_in, offset_in;
659     long display_line_out, offset_out;
660     int scroll_rows;
661 sysadm 1.2 long last_updated_line = 0;
662 sysadm 1.8 int key_insert = 1;
663 sysadm 1.12 int i, j;
664     char *p_str;
665 sysadm 1.1
666 sysadm 1.14 clrline(output_current_row, SCREEN_ROWS);
667 sysadm 1.1
668     // update msg_ext with extended key handler
669     if (editor_display_key_handler(&ch, &ctx) != 0)
670     {
671     return ch;
672     }
673    
674 sysadm 1.35 for (loop = 1; !SYS_server_exit && loop;)
675 sysadm 1.1 {
676 sysadm 1.14 if (line_current >= p_editor_data->display_line_total || output_current_row > output_end_row)
677 sysadm 1.1 {
678 sysadm 1.14 ctx.line_cursor = line_current - output_current_row + row_pos + 1;
679 sysadm 1.1
680     snprintf(buffer, sizeof(buffer),
681 sysadm 1.2 "\033[1;44;33m[\033[32m%ld\033[33m;\033[32m%ld\033[33m] "
682 sysadm 1.39 "第\033[32m%ld\033[33m/\033[32m%ld\033[33m行 [\033[32m%s\033[33m] "
683 sysadm 1.2 "%s",
684     row_pos, col_pos,
685     ctx.line_cursor, p_editor_data->display_line_total,
686 sysadm 1.39 key_insert ? "插入" : "替换",
687 sysadm 1.1 ctx.msg);
688    
689 sysadm 1.24 len = split_line(buffer, SCREEN_COLS, &eol, &display_len, 1);
690 sysadm 1.1 for (; display_len < SCREEN_COLS; display_len++)
691     {
692     buffer[len++] = ' ';
693     }
694     buffer[len] = '\0';
695     strncat(buffer, "\033[m", sizeof(buffer) - 1 - strnlen(buffer, sizeof(buffer)));
696    
697     moveto(SCREEN_ROWS, 0);
698     prints("%s", buffer);
699    
700     moveto((int)row_pos, (int)col_pos);
701     iflush();
702    
703 sysadm 1.25 str_len = 0;
704     ch = igetch_t(MAX_DELAY_TIME);
705 sysadm 1.33 while (!SYS_server_exit)
706 sysadm 1.1 {
707     // extended key handler
708     if (editor_display_key_handler(&ch, &ctx) != 0)
709     {
710     goto cleanup;
711     }
712    
713 sysadm 1.39 if (ch < 256 && (ch & 0b10000000)) // head of multi-byte character
714 sysadm 1.3 {
715     str_len = 0;
716 sysadm 1.39 c = (char)(ch & 0b11110000);
717     while (c & 0b10000000)
718     {
719     input_str[str_len] = (char)(ch - 256);
720     str_len++;
721     c = (c & 0b01111111) << 1;
722    
723     if ((c & 0b10000000) == 0) // Input completed
724     {
725     break;
726     }
727    
728     // Expect additional bytes of input
729     ch = igetch(100); // 0.1 second
730     if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
731     {
732 sysadm 1.40 #ifdef _DEBUG
733 sysadm 1.39 log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
734 sysadm 1.40 #endif
735 sysadm 1.39 str_len = 0;
736     break;
737     }
738     }
739 sysadm 1.3 }
740    
741 sysadm 1.39 if ((ch >= 32 && ch < 127) || str_len >= 2 || // Printable character or multi-byte character
742     ch == CR || ch == KEY_ESC) // Special character
743 sysadm 1.2 {
744 sysadm 1.27 BBS_last_access_tm = time(NULL);
745 sysadm 1.25
746 sysadm 1.21 if (str_len == 0) // ch >= 32 && ch < 127
747 sysadm 1.3 {
748 sysadm 1.4 input_str[0] = (char)ch;
749 sysadm 1.3 str_len = 1;
750     }
751    
752 sysadm 1.14 display_line_in = line_current - output_current_row + row_pos;
753 sysadm 1.39 offset_in = split_line(p_editor_data->p_display_lines[display_line_in], (int)col_pos - 1, &eol, &display_len, 0);
754 sysadm 1.3 display_line_out = display_line_in;
755     offset_out = offset_in;
756 sysadm 1.2
757 sysadm 1.32 last_updated_line = display_line_in;
758    
759 sysadm 1.8 if (!key_insert) // overwrite
760     {
761 sysadm 1.23 if (editor_data_delete(p_editor_data, &display_line_out, &offset_out,
762 sysadm 1.8 &last_updated_line) < 0)
763     {
764     log_error("editor_data_delete() error\n");
765     }
766     }
767    
768 sysadm 1.3 if (editor_data_insert(p_editor_data, &display_line_out, &offset_out,
769 sysadm 1.4 input_str, str_len, &last_updated_line) < 0)
770 sysadm 1.2 {
771 sysadm 1.14 log_error("editor_data_insert(str_len=%d) error\n", str_len);
772 sysadm 1.2 }
773     else
774     {
775 sysadm 1.14 output_end_row = MIN(SCREEN_ROWS - 1, output_current_row + (int)(last_updated_line - line_current));
776     line_current -= (output_current_row - row_pos);
777     output_current_row = (int)row_pos;
778 sysadm 1.2
779 sysadm 1.14 scroll_rows = MAX(0, (int)(display_line_out - display_line_in) - (output_end_row - output_current_row));
780 sysadm 1.2
781 sysadm 1.3 if (scroll_rows > 0)
782 sysadm 1.2 {
783 sysadm 1.3 moveto(SCREEN_ROWS, 0);
784     clrtoeol();
785     for (i = 0; i < scroll_rows; i++)
786     {
787 sysadm 1.36 // prints("\033[S"); // Scroll up 1 line
788     prints("\n"); // Legacy Cterm only works with this line
789 sysadm 1.3 }
790 sysadm 1.2
791 sysadm 1.14 output_current_row -= scroll_rows;
792     if (output_current_row < screen_begin_row)
793 sysadm 1.2 {
794 sysadm 1.14 line_current += (screen_begin_row - output_current_row);
795     output_current_row = screen_begin_row;
796 sysadm 1.2 }
797 sysadm 1.14 row_pos = output_end_row;
798 sysadm 1.3 }
799     else // if (scroll_lines == 0)
800     {
801     row_pos += (display_line_out - display_line_in);
802 sysadm 1.2 }
803 sysadm 1.39
804     if (offset_out != offset_in)
805     {
806     if (display_line_out != display_line_in)
807     {
808     col_pos = 1;
809     }
810     if (ch != CR)
811     {
812     col_pos += (str_len == 1 ? 1 : 2);
813     }
814     }
815 sysadm 1.11 }
816 sysadm 1.3
817 sysadm 1.25 if (display_line_out != display_line_in) // Output on line change
818     {
819     break;
820     }
821    
822     ch = igetch(0);
823     if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Output if no futher input
824     {
825     break;
826     }
827    
828 sysadm 1.21 str_len = 0;
829 sysadm 1.11 continue;
830 sysadm 1.2 }
831 sysadm 1.9 else if (ch == KEY_DEL || ch == BACKSPACE) // Del
832 sysadm 1.2 {
833 sysadm 1.27 BBS_last_access_tm = time(NULL);
834 sysadm 1.25
835 sysadm 1.9 if (ch == BACKSPACE)
836     {
837 sysadm 1.18 if (line_current - output_current_row + row_pos <= 0 && col_pos <= 1) // Forbidden
838     {
839 sysadm 1.34 break; // force output prior operation result if any
840 sysadm 1.18 }
841    
842 sysadm 1.39 offset_in = split_line(p_editor_data->p_display_lines[line_current - output_current_row + row_pos],
843     (int)col_pos - 1, &eol, &display_len, 0);
844     if (offset_in >= 1 && p_editor_data->p_display_lines[line_current - output_current_row + row_pos][offset_in - 1] < 0) // UTF8
845     {
846     col_pos = display_len - 1;
847     }
848     else
849 sysadm 1.23 {
850 sysadm 1.39 col_pos = display_len;
851 sysadm 1.23 }
852    
853 sysadm 1.14 if (col_pos < 1 && line_current - output_current_row + row_pos >= 0)
854 sysadm 1.9 {
855     row_pos--;
856 sysadm 1.39 col_pos = MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]);
857 sysadm 1.9 }
858     }
859 sysadm 1.2
860 sysadm 1.23 display_line_in = line_current - output_current_row + row_pos;
861 sysadm 1.39 offset_in = split_line(p_editor_data->p_display_lines[display_line_in], (int)col_pos - 1, &eol, &display_len, 0);
862 sysadm 1.23 display_line_out = display_line_in;
863     offset_out = offset_in;
864    
865     if ((str_len = editor_data_delete(p_editor_data, &display_line_out, &offset_out,
866 sysadm 1.9 &last_updated_line)) < 0)
867 sysadm 1.2 {
868 sysadm 1.3 log_error("editor_data_delete() error\n");
869 sysadm 1.2 }
870     else
871     {
872 sysadm 1.39 col_pos = display_len + 1; // Set col_pos to accurate pos
873 sysadm 1.9
874 sysadm 1.14 output_end_row = MIN(SCREEN_ROWS - 1, output_current_row + (int)(last_updated_line - line_current));
875     line_current -= (output_current_row - row_pos);
876     output_current_row = (int)row_pos;
877 sysadm 1.9
878 sysadm 1.14 if (output_current_row < screen_begin_row) // row_pos <= 0
879 sysadm 1.9 {
880 sysadm 1.14 output_current_row = screen_begin_row;
881 sysadm 1.9 row_pos = screen_begin_row;
882 sysadm 1.14 output_end_row = SCREEN_ROWS - 1;
883     }
884    
885     // Exceed end
886     if (line_current + (screen_row_total - output_current_row) >= p_editor_data->display_line_total &&
887     p_editor_data->display_line_total > screen_row_total)
888     {
889     scroll_rows = (int)((line_current - (output_current_row - screen_begin_row)) -
890     (p_editor_data->display_line_total - screen_row_total));
891    
892     line_current = p_editor_data->display_line_total - screen_row_total;
893     row_pos += scroll_rows;
894     output_current_row = screen_begin_row;
895     output_end_row = SCREEN_ROWS - 1;
896 sysadm 1.9 }
897 sysadm 1.18
898     clrline(output_current_row, output_end_row);
899 sysadm 1.2 }
900    
901 sysadm 1.25 if (display_line_out != display_line_in) // Output on line change
902     {
903     break;
904     }
905    
906     ch = igetch(0);
907     if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Output if no futher input
908     {
909     break;
910     }
911    
912 sysadm 1.21 str_len = 0;
913 sysadm 1.2 continue;
914     }
915    
916 sysadm 1.25 input_ok = 1;
917 sysadm 1.1 switch (ch)
918     {
919     case KEY_NULL:
920     case KEY_TIMEOUT:
921     goto cleanup;
922 sysadm 1.17 case Ctrl('W'):
923 sysadm 1.1 loop = 0;
924     break;
925 sysadm 1.13 case Ctrl('S'): // Start of line
926 sysadm 1.2 case KEY_CTRL_LEFT:
927 sysadm 1.1 col_pos = 1;
928     break;
929 sysadm 1.13 case Ctrl('E'): // End of line
930 sysadm 1.2 case KEY_CTRL_RIGHT:
931 sysadm 1.23 if (line_current - output_current_row + row_pos == p_editor_data->display_line_total - 1) // row_pos at end line
932 sysadm 1.22 {
933     // last display line does NOT have \n in the end
934 sysadm 1.39 col_pos = p_editor_data->display_line_widths[line_current - output_current_row + row_pos] + 1;
935 sysadm 1.22 break;
936     }
937 sysadm 1.39 col_pos = MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]);
938 sysadm 1.1 break;
939 sysadm 1.13 case Ctrl('T'): // Top of screen
940 sysadm 1.2 case KEY_CTRL_UP:
941 sysadm 1.3 row_pos = screen_begin_row;
942 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
943 sysadm 1.2 break;
944 sysadm 1.13 case Ctrl('B'): // Bottom of screen
945 sysadm 1.2 case KEY_CTRL_DOWN:
946 sysadm 1.18 if (p_editor_data->display_line_total < screen_row_total)
947     {
948     row_pos = p_editor_data->display_line_total;
949     }
950     else
951     {
952     row_pos = SCREEN_ROWS - 1;
953     }
954     if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= p_editor_data->display_line_total) // Reach end
955     {
956     // last display line does NOT have \n in the end
957 sysadm 1.39 col_pos = MIN(col_pos, p_editor_data->display_line_widths[line_current - output_current_row + row_pos] + 1);
958 sysadm 1.18 }
959     else
960     {
961 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
962 sysadm 1.18 }
963 sysadm 1.2 break;
964     case KEY_INS:
965 sysadm 1.8 key_insert = !key_insert;
966 sysadm 1.2 break;
967 sysadm 1.1 case KEY_HOME:
968     row_pos = 1;
969     col_pos = 1;
970 sysadm 1.14 if (line_current - output_current_row < 0) // Reach begin
971 sysadm 1.1 {
972     break;
973     }
974     line_current = 0;
975 sysadm 1.14 output_current_row = screen_begin_row;
976     output_end_row = SCREEN_ROWS - 1;
977     clrline(output_current_row, SCREEN_ROWS);
978 sysadm 1.1 break;
979     case KEY_END:
980 sysadm 1.3 if (p_editor_data->display_line_total < screen_row_total)
981 sysadm 1.1 {
982     row_pos = p_editor_data->display_line_total;
983 sysadm 1.39 col_pos = p_editor_data->display_line_widths[line_current - output_current_row + row_pos] + 1;
984 sysadm 1.1 break;
985     }
986 sysadm 1.3 line_current = p_editor_data->display_line_total - screen_row_total;
987 sysadm 1.14 output_current_row = screen_begin_row;
988     output_end_row = SCREEN_ROWS - 1;
989     row_pos = SCREEN_ROWS - 1;
990 sysadm 1.39 col_pos = p_editor_data->display_line_widths[line_current - output_current_row + row_pos] + 1;
991 sysadm 1.14 clrline(output_current_row, SCREEN_ROWS);
992 sysadm 1.1 break;
993     case KEY_LEFT:
994 sysadm 1.39 offset_in = split_line(p_editor_data->p_display_lines[line_current - output_current_row + row_pos],
995     (int)col_pos - 1, &eol, &display_len, 0);
996     if (offset_in >= 1 && p_editor_data->p_display_lines[line_current - output_current_row + row_pos][offset_in - 1] < 0) // UTF8
997     {
998     col_pos = display_len - 1;
999     }
1000     else
1001     {
1002     col_pos = display_len;
1003     }
1004     if (col_pos >= 1)
1005 sysadm 1.1 {
1006     break;
1007     }
1008     col_pos = SCREEN_COLS; // continue to KEY_UP
1009     case KEY_UP:
1010 sysadm 1.3 if (row_pos > screen_begin_row)
1011 sysadm 1.1 {
1012     row_pos--;
1013 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
1014 sysadm 1.1 break;
1015     }
1016 sysadm 1.14 if (line_current - output_current_row < 0) // Reach begin
1017 sysadm 1.1 {
1018 sysadm 1.2 col_pos = 1;
1019 sysadm 1.1 break;
1020     }
1021 sysadm 1.14 line_current -= output_current_row;
1022     output_current_row = screen_begin_row;
1023 sysadm 1.1 // screen_end_line = begin_line;
1024     // prints("\033[T"); // Scroll down 1 line
1025 sysadm 1.14 output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line
1026 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
1027 sysadm 1.1 break;
1028     case KEY_SPACE:
1029     break;
1030     case KEY_RIGHT:
1031 sysadm 1.39 offset_in = split_line(p_editor_data->p_display_lines[line_current - output_current_row + row_pos],
1032     (int)col_pos - 1, &eol, &display_len, 0);
1033     if (offset_in < p_editor_data->display_line_lengths[line_current - output_current_row + row_pos] &&
1034     p_editor_data->p_display_lines[line_current - output_current_row + row_pos][offset_in] < 0) // UTF8
1035     {
1036     col_pos = display_len + 3;
1037     }
1038     else
1039     {
1040     col_pos = display_len + 2;
1041     }
1042     if (col_pos <= p_editor_data->display_line_widths[line_current - output_current_row + row_pos])
1043 sysadm 1.1 {
1044     break;
1045     }
1046     col_pos = 1; // continue to KEY_DOWN
1047     case KEY_DOWN:
1048 sysadm 1.3 if (row_pos < MIN(screen_row_total, p_editor_data->display_line_total))
1049 sysadm 1.1 {
1050     row_pos++;
1051 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
1052 sysadm 1.1 break;
1053     }
1054 sysadm 1.23 if (line_current - output_current_row + row_pos == p_editor_data->display_line_total - 1) // row_pos at end line
1055 sysadm 1.1 {
1056 sysadm 1.18 // last display line does NOT have \n in the end
1057 sysadm 1.39 col_pos = p_editor_data->display_line_widths[line_current - output_current_row + row_pos] + 1;
1058 sysadm 1.1 break;
1059     }
1060 sysadm 1.14 line_current += (screen_row_total - (output_current_row - screen_begin_row));
1061     output_current_row = screen_row_total;
1062     output_end_row = SCREEN_ROWS - 1;
1063 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
1064 sysadm 1.1 moveto(SCREEN_ROWS, 0);
1065     clrtoeol();
1066 sysadm 1.36 // prints("\033[S"); // Scroll up 1 line
1067     prints("\n"); // Legacy Cterm only works with this line
1068 sysadm 1.1 break;
1069     case KEY_PGUP:
1070 sysadm 1.14 if (line_current - output_current_row < 0) // Reach begin
1071 sysadm 1.1 {
1072     break;
1073     }
1074 sysadm 1.14 line_current -= ((screen_row_total - 1) + (output_current_row - screen_begin_row));
1075 sysadm 1.1 if (line_current < 0)
1076     {
1077     line_current = 0;
1078     }
1079 sysadm 1.14 output_current_row = screen_begin_row;
1080     output_end_row = SCREEN_ROWS - 1;
1081 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
1082 sysadm 1.14 clrline(output_current_row, SCREEN_ROWS);
1083 sysadm 1.1 break;
1084     case KEY_PGDN:
1085 sysadm 1.14 if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= p_editor_data->display_line_total) // Reach end
1086 sysadm 1.1 {
1087     break;
1088     }
1089 sysadm 1.14 line_current += (screen_row_total - 1) - (output_current_row - screen_begin_row);
1090 sysadm 1.3 if (line_current + screen_row_total > p_editor_data->display_line_total) // No enough lines to display
1091 sysadm 1.1 {
1092 sysadm 1.3 line_current = p_editor_data->display_line_total - screen_row_total;
1093 sysadm 1.1 }
1094 sysadm 1.14 output_current_row = screen_begin_row;
1095     output_end_row = SCREEN_ROWS - 1;
1096 sysadm 1.39 col_pos = MIN(col_pos, MAX(1, p_editor_data->display_line_widths[line_current - output_current_row + row_pos]));
1097 sysadm 1.14 clrline(output_current_row, SCREEN_ROWS);
1098 sysadm 1.1 break;
1099     case KEY_F1:
1100     if (!show_help) // Not reentrant
1101     {
1102     break;
1103     }
1104     // Display help information
1105     show_help = 0;
1106     display_file(DATA_READ_HELP, 1);
1107     show_help = 1;
1108     case KEY_F5:
1109     // Refresh after display help information
1110 sysadm 1.14 line_current -= (output_current_row - screen_begin_row);
1111     output_current_row = screen_begin_row;
1112     output_end_row = SCREEN_ROWS - 1;
1113     clrline(output_current_row, SCREEN_ROWS);
1114 sysadm 1.1 break;
1115     case 0: // Refresh bottom line
1116     break;
1117     default:
1118     input_ok = 0;
1119     break;
1120     }
1121    
1122 sysadm 1.27 BBS_last_access_tm = time(NULL);
1123 sysadm 1.14
1124     if (input_ok)
1125 sysadm 1.11 {
1126 sysadm 1.14 break;
1127 sysadm 1.11 }
1128 sysadm 1.25
1129     ch = igetch_t(MAX_DELAY_TIME);
1130 sysadm 1.1 }
1131    
1132     continue;
1133     }
1134    
1135     len = p_editor_data->display_line_lengths[line_current];
1136     if (len >= sizeof(buffer))
1137     {
1138     log_error("Buffer overflow: len=%ld line=%ld \n", len, line_current);
1139     len = sizeof(buffer) - 1;
1140     }
1141     else if (len < 0)
1142     {
1143     log_error("Incorrect line offsets: len=%ld line=%ld \n", len, line_current);
1144     len = 0;
1145     }
1146    
1147 sysadm 1.12 // memcpy(buffer, p_editor_data->p_display_lines[line_current], (size_t)len);
1148     // Replace '\033' with '*'
1149     p_str = p_editor_data->p_display_lines[line_current];
1150     for (i = 0, j = 0; i < len; i++)
1151     {
1152     if (p_str[i] == '\033')
1153     {
1154     memcpy(buffer + j, EDITOR_ESC_DISPLAY_STR, sizeof(EDITOR_ESC_DISPLAY_STR) - 1);
1155     j += (int)(sizeof(EDITOR_ESC_DISPLAY_STR) - 1);
1156     }
1157     else
1158     {
1159     buffer[j] = p_str[i];
1160     j++;
1161     }
1162     }
1163     buffer[j] = '\0';
1164 sysadm 1.1
1165 sysadm 1.14 moveto(output_current_row, 0);
1166 sysadm 1.1 clrtoeol();
1167     prints("%s", buffer);
1168     line_current++;
1169 sysadm 1.14 output_current_row++;
1170 sysadm 1.1 }
1171    
1172     cleanup:
1173     return ch;
1174     }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1