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

Annotation of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.108 - (hide annotations)
Thu Oct 9 12:20:31 2025 UTC (5 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.107: +266 -3 lines
Content type: text/x-csrc
Add move cursor feature to get_data()

1 sysadm 1.1 /***************************************************************************
2 sysadm 1.21 screen.c - description
3     -------------------
4 sysadm 1.36 Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
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 sysadm 1.36 * the Free Software Foundation; either version 3 of the License, or *
13 sysadm 1.1 * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17 sysadm 1.9 #include "bbs.h"
18 sysadm 1.6 #include "common.h"
19 sysadm 1.89 #include "editor.h"
20 sysadm 1.54 #include "file_loader.h"
21 sysadm 1.102 #include "io.h"
22     #include "log.h"
23 sysadm 1.101 #include "login.h"
24 sysadm 1.102 #include "screen.h"
25     #include "str_process.h"
26     #include <ctype.h>
27     #include <errno.h>
28 sysadm 1.52 #include <fcntl.h>
29 sysadm 1.98 #include <string.h>
30 sysadm 1.102 #include <stdlib.h>
31 sysadm 1.41 #include <unistd.h>
32 sysadm 1.102 #include <sys/param.h>
33 sysadm 1.6 #include <sys/stat.h>
34 sysadm 1.55 #include <sys/shm.h>
35 sysadm 1.102 #include <sys/types.h>
36 sysadm 1.1
37 sysadm 1.21 #define ACTIVE_BOARD_HEIGHT 8
38 sysadm 1.9
39 sysadm 1.105 #define STR_TOP_LEFT_MAX_LEN 80
40     #define STR_TOP_MIDDLE_MAX_LEN 40
41     #define STR_TOP_RIGHT_MAX_LEN 40
42 sysadm 1.70
43 sysadm 1.107 static const char *get_time_str(char *s, size_t len)
44     {
45     static const char *weekday[] = {
46     "天", "一", "二", "三", "四", "五", "六"};
47     time_t curtime;
48     struct tm local_tm;
49    
50     time(&curtime);
51     localtime_r(&curtime, &local_tm);
52     size_t j = strftime(s, len, "%b %d %H:%M 星期", &local_tm);
53    
54     if (j == 0 || j + strlen(weekday[local_tm.tm_wday]) + 1 > len)
55     {
56     return NULL;
57     }
58    
59     strncat(s, weekday[local_tm.tm_wday], len - 1 - j);
60    
61     return s;
62     }
63    
64 sysadm 1.21 void moveto(int row, int col)
65 sysadm 1.1 {
66 sysadm 1.21 if (row >= 0)
67     {
68     prints("\033[%d;%dH", row, col);
69     }
70     else
71     {
72     prints("\r");
73     }
74 sysadm 1.1 }
75    
76 sysadm 1.21 void clrtoeol()
77 sysadm 1.1 {
78 sysadm 1.63 prints(CTRL_SEQ_CLR_LINE);
79 sysadm 1.2 }
80    
81 sysadm 1.21 void clrline(int line_begin, int line_end)
82 sysadm 1.5 {
83 sysadm 1.21 int i;
84 sysadm 1.6
85 sysadm 1.21 for (i = line_begin; i <= line_end; i++)
86     {
87     moveto(i, 0);
88 sysadm 1.63 prints(CTRL_SEQ_CLR_LINE);
89 sysadm 1.21 }
90 sysadm 1.5 }
91    
92 sysadm 1.21 void clrtobot(int line_begin)
93 sysadm 1.16 {
94 sysadm 1.21 moveto(line_begin, 0);
95 sysadm 1.25 prints("\033[J");
96     moveto(line_begin, 0);
97 sysadm 1.16 }
98    
99 sysadm 1.21 void clearscr()
100 sysadm 1.2 {
101 sysadm 1.23 prints("\033[2J");
102 sysadm 1.21 moveto(0, 0);
103 sysadm 1.6 }
104    
105 sysadm 1.21 int press_any_key()
106 sysadm 1.6 {
107 sysadm 1.53 moveto(SCREEN_ROWS, 0);
108 sysadm 1.21 clrtoeol();
109 sysadm 1.6
110 sysadm 1.104 prints(" \033[1;33m按任意键继续...\033[0;37m");
111 sysadm 1.21 iflush();
112 sysadm 1.6
113 sysadm 1.41 return igetch_t(MIN(MAX_DELAY_TIME, 60));
114 sysadm 1.1 }
115    
116 sysadm 1.21 void set_input_echo(int echo)
117 sysadm 1.7 {
118 sysadm 1.21 if (echo)
119     {
120     outc('\x83'); // ASCII code 131
121     iflush();
122     }
123     else
124     {
125     // outc ('\x85'); // ASCII code 133
126     prints("\xff\xfb\x01\xff\xfb\x03");
127     iflush();
128 sysadm 1.26 igetch(0);
129 sysadm 1.47 igetch_reset();
130 sysadm 1.21 }
131 sysadm 1.7 }
132    
133 sysadm 1.104 static int _str_input(char *buffer, int buf_size, int max_display_len, int echo_mode)
134 sysadm 1.1 {
135 sysadm 1.104 int ch;
136 sysadm 1.38 int offset = 0;
137 sysadm 1.104 int eol;
138     int display_len;
139     char input_str[4];
140     int str_len = 0;
141     char c;
142 sysadm 1.1
143 sysadm 1.38 buffer[buf_size - 1] = '\0';
144 sysadm 1.104 offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
145 sysadm 1.21
146 sysadm 1.47 igetch_reset();
147    
148 sysadm 1.48 while (!SYS_server_exit)
149 sysadm 1.1 {
150 sysadm 1.104 ch = igetch_t(MIN(MAX_DELAY_TIME, 60));
151 sysadm 1.48
152 sysadm 1.104 if (ch == CR)
153 sysadm 1.22 {
154 sysadm 1.47 igetch_reset();
155 sysadm 1.21 break;
156 sysadm 1.22 }
157 sysadm 1.104 else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
158 sysadm 1.41 {
159     return -1;
160     }
161 sysadm 1.104 else if (ch == LF || ch == '\0')
162 sysadm 1.22 {
163 sysadm 1.21 continue;
164 sysadm 1.22 }
165 sysadm 1.104 else if (ch == BACKSPACE)
166 sysadm 1.21 {
167     if (offset > 0)
168     {
169 sysadm 1.31 offset--;
170 sysadm 1.104 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
171 sysadm 1.31 {
172 sysadm 1.104 while (offset > 0 && (buffer[offset] & 0b11000000) != 0b11000000)
173 sysadm 1.31 {
174 sysadm 1.104 offset--;
175 sysadm 1.31 }
176 sysadm 1.104 display_len--;
177     prints("\033[D \033[D");
178 sysadm 1.31 }
179     buffer[offset] = '\0';
180 sysadm 1.104 display_len--;
181 sysadm 1.31 prints("\033[D \033[D");
182 sysadm 1.21 iflush();
183     }
184     continue;
185     }
186 sysadm 1.104 else if (ch > 255 || iscntrl(ch))
187 sysadm 1.21 {
188     continue;
189     }
190 sysadm 1.104 else if ((ch & 0xff80) == 0x80) // head of multi-byte character
191 sysadm 1.21 {
192 sysadm 1.104 str_len = 0;
193     c = (char)(ch & 0b11110000);
194     while (c & 0b10000000)
195     {
196     input_str[str_len] = (char)(ch - 256);
197     str_len++;
198     c = (c & 0b01111111) << 1;
199    
200     if ((c & 0b10000000) == 0) // Input completed
201     {
202     break;
203     }
204    
205     // Expect additional bytes of input
206     ch = igetch(100); // 0.1 second
207     if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
208     {
209 sysadm 1.106 #ifdef _DEBUG
210 sysadm 1.104 log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
211 sysadm 1.106 #endif
212 sysadm 1.104 str_len = 0;
213     break;
214     }
215     }
216    
217     if (str_len == 0) // Incomplete input
218     {
219     continue;
220     }
221    
222     if (offset + str_len > buf_size - 1 || display_len + 2 > max_display_len) // No enough space for Chinese character
223 sysadm 1.31 {
224     outc('\a');
225     iflush();
226     continue;
227     }
228 sysadm 1.104
229     memcpy(buffer + offset, input_str, (size_t)str_len);
230     offset += str_len;
231     buffer[offset] = '\0';
232     display_len += 2;
233    
234     switch (echo_mode)
235     {
236     case DOECHO:
237     prints(input_str);
238     break;
239     case NOECHO:
240     prints("**");
241     break;
242     }
243 sysadm 1.21 }
244 sysadm 1.104 else if (ch >= 32 && ch < 127) // Printable character
245 sysadm 1.21 {
246 sysadm 1.104 if (offset + 1 > buf_size - 1 || display_len + 1 > max_display_len)
247     {
248     outc('\a');
249     iflush();
250     continue;
251     }
252 sysadm 1.43
253 sysadm 1.104 buffer[offset++] = (char)ch;
254     buffer[offset] = '\0';
255     display_len++;
256 sysadm 1.43
257 sysadm 1.104 switch (echo_mode)
258     {
259     case DOECHO:
260     outc((char)ch);
261     break;
262     case NOECHO:
263     outc('*');
264     break;
265     }
266 sysadm 1.21 }
267 sysadm 1.104 else // Invalid character
268 sysadm 1.21 {
269 sysadm 1.104 continue;
270 sysadm 1.21 }
271 sysadm 1.104
272     iflush();
273 sysadm 1.6 }
274 sysadm 1.1
275 sysadm 1.21 return offset;
276 sysadm 1.1 }
277    
278 sysadm 1.38 int str_input(char *buffer, int buf_size, int echo_mode)
279 sysadm 1.18 {
280 sysadm 1.32 int len;
281    
282     buffer[0] = '\0';
283 sysadm 1.21
284 sysadm 1.104 len = _str_input(buffer, buf_size, buf_size, echo_mode);
285 sysadm 1.21
286 sysadm 1.32 prints("\r\n");
287     iflush();
288 sysadm 1.21
289 sysadm 1.32 return len;
290 sysadm 1.18 };
291    
292 sysadm 1.108 int get_data(int row, int col, char *prompt, char *buffer, int buf_size, int max_display_len)
293 sysadm 1.15 {
294 sysadm 1.108 int len = 0;
295     int col_cur = 0;
296     int ch;
297     int offset = 0;
298     int eol;
299     int display_len;
300     char input_str[4];
301     int str_len = 0;
302     char c;
303    
304     buffer[buf_size - 1] = '\0';
305     offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
306     buffer[offset] = '\0';
307     len = offset;
308     col_cur = col + str_length(prompt, 1) + display_len;
309 sysadm 1.15
310 sysadm 1.21 moveto(row, col);
311 sysadm 1.80 prints("%s", prompt);
312     prints("%s", buffer);
313 sysadm 1.108 prints("%*s", max_display_len - display_len, "");
314     moveto(row, col_cur);
315 sysadm 1.21 iflush();
316 sysadm 1.15
317 sysadm 1.108 igetch_reset();
318    
319     while (!SYS_server_exit)
320     {
321     ch = igetch_t(MIN(MAX_DELAY_TIME, 60));
322    
323     if (ch == CR)
324     {
325     igetch_reset();
326     break;
327     }
328     else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
329     {
330     return -1;
331     }
332     else if (ch == LF || ch == '\0')
333     {
334     continue;
335     }
336     else if (ch == BACKSPACE)
337     {
338     if (offset > 0)
339     {
340     str_len = 1;
341     offset--;
342     if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
343     {
344     while (offset > 0 && (buffer[offset] & 0b11000000) != 0b11000000)
345     {
346     str_len++;
347     offset--;
348     }
349     display_len--;
350     col_cur--;
351     }
352    
353     memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
354     len -= str_len;
355     buffer[len] = '\0';
356     display_len--;
357     col_cur--;
358    
359     moveto(row, col_cur);
360     prints("%s", buffer + offset);
361     prints("%*s", max_display_len - display_len, "");
362     moveto(row, col_cur);
363     iflush();
364     }
365     continue;
366     }
367     else if (ch == KEY_DEL)
368     {
369     if (offset < len)
370     {
371     if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
372     {
373     str_len = 0;
374     c = (char)(buffer[offset] & 0b11110000);
375     while (c & 0b10000000)
376     {
377     str_len++;
378     c = (c & 0b01111111) << 1;
379     }
380     display_len--;
381     }
382     else
383     {
384     str_len = 1;
385     }
386    
387     memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
388     len -= str_len;
389     buffer[len] = '\0';
390     display_len--;
391    
392     moveto(row, col_cur);
393     prints("%s", buffer + offset);
394     prints("%*s", max_display_len - display_len, "");
395     moveto(row, col_cur);
396     iflush();
397     }
398     continue;
399     }
400     else if (ch == KEY_LEFT)
401     {
402     if (offset > 0)
403     {
404     str_len = 1;
405     offset--;
406     if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
407     {
408     while (offset > 0 && (buffer[offset] & 0b11000000) != 0b11000000)
409     {
410     str_len++;
411     offset--;
412     }
413     col_cur--;
414     }
415     col_cur--;
416    
417     moveto(row, col_cur);
418     iflush();
419     }
420     continue;
421     }
422     else if (ch == KEY_RIGHT)
423     {
424     if (offset < len)
425     {
426     str_len = 0;
427     if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
428     {
429     c = (char)(buffer[offset] & 0b11110000);
430     while (c & 0b10000000)
431     {
432     str_len++;
433     c = (c & 0b01111111) << 1;
434     }
435     col_cur++;
436     }
437     else
438     {
439     str_len = 1;
440     }
441    
442     col_cur++;
443     offset += str_len;
444    
445     moveto(row, col_cur);
446     iflush();
447     }
448     continue;
449     }
450     else if (ch == KEY_HOME || ch == KEY_UP)
451     {
452     if (offset > 0)
453     {
454     offset = 0;
455     col_cur = col + str_length(prompt, 1);
456    
457     moveto(row, col_cur);
458     iflush();
459     }
460     continue;
461     }
462     else if (ch == KEY_END || ch == KEY_DOWN)
463     {
464     if (offset < len)
465     {
466     offset = len;
467     col_cur = col + str_length(prompt, 1) + display_len;
468    
469     moveto(row, col_cur);
470     iflush();
471     }
472     continue;
473     }
474     else if (ch > 255 || iscntrl(ch))
475     {
476     continue;
477     }
478     else if ((ch & 0xff80) == 0x80) // head of multi-byte character
479     {
480     str_len = 0;
481     c = (char)(ch & 0b11110000);
482     while (c & 0b10000000)
483     {
484     input_str[str_len] = (char)(ch - 256);
485     str_len++;
486     c = (c & 0b01111111) << 1;
487    
488     if ((c & 0b10000000) == 0) // Input completed
489     {
490     break;
491     }
492    
493     // Expect additional bytes of input
494     ch = igetch(100); // 0.1 second
495     if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
496     {
497     #ifdef _DEBUG
498     log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
499     #endif
500     str_len = 0;
501     break;
502     }
503     }
504    
505     if (str_len == 0) // Incomplete input
506     {
507     continue;
508     }
509    
510     if (len + str_len > buf_size - 1 || display_len + 2 > max_display_len) // No enough space for Chinese character
511     {
512     outc('\a');
513     iflush();
514     continue;
515     }
516    
517     memmove(buffer + offset + str_len, buffer + offset, (size_t)(len - offset));
518     memcpy(buffer + offset, input_str, (size_t)str_len);
519     len += str_len;
520     buffer[len] = '\0';
521     display_len += 2;
522    
523     moveto(row, col_cur);
524     prints("%s", buffer + offset);
525     prints("%*s", max_display_len - display_len, "");
526    
527     col_cur += 2;
528    
529     moveto(row, col_cur);
530     iflush();
531    
532     offset += str_len;
533     }
534     else if (ch >= 32 && ch < 127) // Printable character
535     {
536     if (len + 1 > buf_size - 1 || display_len + 1 > max_display_len)
537     {
538     outc('\a');
539     iflush();
540     continue;
541     }
542    
543     memmove(buffer + offset + 1, buffer + offset, (size_t)(len - offset));
544     buffer[offset] = (char)ch;
545     len++;
546     buffer[len] = '\0';
547     display_len++;
548    
549     moveto(row, col_cur);
550     prints("%s", buffer + offset);
551     prints("%*s", max_display_len - display_len, "");
552    
553     col_cur++;
554    
555     moveto(row, col_cur);
556     iflush();
557    
558     offset++;
559     }
560     else // Invalid character
561     {
562     continue;
563     }
564     }
565 sysadm 1.21
566     return len;
567 sysadm 1.15 }
568    
569 sysadm 1.89 int display_data(const void *p_data, long display_line_total, const long *p_line_offsets, int eof_exit,
570 sysadm 1.81 display_data_key_handler key_handler, const char *help_filename)
571 sysadm 1.1 {
572 sysadm 1.37 static int show_help = 1;
573 sysadm 1.26 char buffer[LINE_BUFFER_LEN];
574 sysadm 1.85 DISPLAY_CTX ctx;
575 sysadm 1.81 int ch = 0;
576 sysadm 1.91 int input_ok;
577     const int screen_begin_row = 1;
578 sysadm 1.95 const int screen_row_total = SCREEN_ROWS - screen_begin_row;
579     int output_current_row = screen_begin_row;
580     int output_end_row = SCREEN_ROWS - 1;
581 sysadm 1.54 long int line_current = 0;
582 sysadm 1.34 long int len;
583     long int percentile;
584 sysadm 1.54 int loop;
585 sysadm 1.78 int eol, display_len;
586 sysadm 1.52
587 sysadm 1.95 clrline(output_current_row, SCREEN_ROWS);
588 sysadm 1.6
589 sysadm 1.81 // update msg_ext with extended key handler
590 sysadm 1.85 if (key_handler(&ch, &ctx) != 0)
591 sysadm 1.81 {
592     return ch;
593     }
594    
595 sysadm 1.54 loop = 1;
596 sysadm 1.44 while (!SYS_server_exit && loop)
597 sysadm 1.6 {
598 sysadm 1.91 if (eof_exit > 0 && line_current >= display_line_total && display_line_total <= screen_row_total)
599 sysadm 1.27 {
600 sysadm 1.82 if (eof_exit == 1)
601 sysadm 1.27 {
602     ch = press_any_key();
603     }
604 sysadm 1.82 else // if (eof_exit == 2)
605 sysadm 1.27 {
606     iflush();
607     }
608    
609     loop = 0;
610     break;
611     }
612    
613 sysadm 1.95 if (line_current >= display_line_total || output_current_row > output_end_row)
614 sysadm 1.21 {
615 sysadm 1.95 ctx.reach_begin = (line_current < output_current_row ? 1 : 0);
616 sysadm 1.85
617 sysadm 1.95 if (line_current - (output_current_row - screen_begin_row) + screen_row_total < display_line_total)
618 sysadm 1.27 {
619 sysadm 1.95 percentile = (line_current - (output_current_row - screen_begin_row) + screen_row_total) * 100 / display_line_total;
620 sysadm 1.85 ctx.reach_end = 0;
621 sysadm 1.27 }
622     else
623     {
624     percentile = 100;
625 sysadm 1.85 ctx.reach_end = 1;
626 sysadm 1.27 }
627 sysadm 1.6
628 sysadm 1.95 ctx.line_top = line_current - (output_current_row - screen_begin_row) + 1;
629     ctx.line_bottom = MIN(line_current - (output_current_row - screen_begin_row) + screen_row_total, display_line_total);
630 sysadm 1.85
631 sysadm 1.78 snprintf(buffer, sizeof(buffer),
632 sysadm 1.104 "\033[1;44;33m第\033[32m%ld\033[33m-\033[32m%ld\033[33m行 (\033[32m%ld%%\033[33m) %s",
633 sysadm 1.85 ctx.line_top,
634     ctx.line_bottom,
635     percentile,
636     ctx.msg);
637 sysadm 1.78
638 sysadm 1.97 len = split_line(buffer, SCREEN_COLS, &eol, &display_len, 1);
639 sysadm 1.81 for (; display_len < SCREEN_COLS; display_len++)
640 sysadm 1.78 {
641     buffer[len++] = ' ';
642     }
643     buffer[len] = '\0';
644     strncat(buffer, "\033[m", sizeof(buffer) - 1 - strnlen(buffer, sizeof(buffer)));
645    
646 sysadm 1.53 moveto(SCREEN_ROWS, 0);
647 sysadm 1.80 prints("%s", buffer);
648 sysadm 1.26 iflush();
649 sysadm 1.6
650 sysadm 1.26 input_ok = 0;
651 sysadm 1.44 while (!SYS_server_exit && !input_ok)
652 sysadm 1.21 {
653 sysadm 1.94 ch = igetch_t(MAX_DELAY_TIME);
654     input_ok = 1;
655    
656 sysadm 1.81 // extended key handler
657 sysadm 1.85 if (key_handler(&ch, &ctx) != 0)
658 sysadm 1.81 {
659     goto cleanup;
660     }
661    
662 sysadm 1.26 switch (ch)
663 sysadm 1.21 {
664 sysadm 1.67 case KEY_NULL:
665 sysadm 1.41 case KEY_TIMEOUT:
666     goto cleanup;
667 sysadm 1.50 case KEY_HOME:
668 sysadm 1.95 if (line_current - output_current_row < 0) // Reach begin
669 sysadm 1.84 {
670     break;
671     }
672 sysadm 1.54 line_current = 0;
673 sysadm 1.95 output_current_row = screen_begin_row;
674     output_end_row = SCREEN_ROWS - 1;
675     clrline(output_current_row, SCREEN_ROWS);
676 sysadm 1.50 break;
677     case KEY_END:
678 sysadm 1.91 if (display_line_total < screen_row_total)
679 sysadm 1.83 {
680 sysadm 1.84 break;
681 sysadm 1.83 }
682 sysadm 1.91 line_current = display_line_total - screen_row_total;
683 sysadm 1.95 output_current_row = screen_begin_row;
684     output_end_row = SCREEN_ROWS - 1;
685     clrline(output_current_row, SCREEN_ROWS);
686 sysadm 1.50 break;
687 sysadm 1.26 case KEY_UP:
688 sysadm 1.95 if (line_current - output_current_row < 0) // Reach begin
689 sysadm 1.21 {
690     break;
691 sysadm 1.26 }
692 sysadm 1.95 line_current -= output_current_row;
693     output_current_row = screen_begin_row;
694 sysadm 1.89 // screen_end_line = screen_begin_line;
695 sysadm 1.39 // prints("\033[T"); // Scroll down 1 line
696 sysadm 1.95 output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line
697 sysadm 1.26 break;
698 sysadm 1.49 case CR:
699     igetch_reset();
700 sysadm 1.78 case KEY_SPACE:
701 sysadm 1.26 case KEY_DOWN:
702 sysadm 1.95 if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= display_line_total) // Reach end
703 sysadm 1.26 {
704 sysadm 1.21 break;
705 sysadm 1.26 }
706 sysadm 1.95 line_current += (screen_row_total - (output_current_row - screen_begin_row));
707     output_current_row = screen_row_total;
708     output_end_row = SCREEN_ROWS - 1;
709 sysadm 1.53 moveto(SCREEN_ROWS, 0);
710 sysadm 1.26 clrtoeol();
711 sysadm 1.104 // prints("\033[S"); // Scroll up 1 line
712 sysadm 1.103 prints("\n"); // Legacy Cterm only works with this line
713 sysadm 1.26 break;
714     case KEY_PGUP:
715 sysadm 1.95 if (line_current - output_current_row < 0) // Reach begin
716 sysadm 1.26 {
717 sysadm 1.21 break;
718 sysadm 1.26 }
719 sysadm 1.95 line_current -= ((screen_row_total - 1) + (output_current_row - screen_begin_row));
720 sysadm 1.54 if (line_current < 0)
721 sysadm 1.26 {
722 sysadm 1.54 line_current = 0;
723 sysadm 1.26 }
724 sysadm 1.95 output_current_row = screen_begin_row;
725     output_end_row = SCREEN_ROWS - 1;
726     clrline(output_current_row, SCREEN_ROWS);
727 sysadm 1.26 break;
728     case KEY_PGDN:
729 sysadm 1.95 if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= display_line_total) // Reach end
730 sysadm 1.26 {
731 sysadm 1.21 break;
732     }
733 sysadm 1.95 line_current += (screen_row_total - 1) - (output_current_row - screen_begin_row);
734 sysadm 1.91 if (line_current + screen_row_total > display_line_total) // No enough lines to display
735 sysadm 1.26 {
736 sysadm 1.91 line_current = display_line_total - screen_row_total;
737 sysadm 1.26 }
738 sysadm 1.95 output_current_row = screen_begin_row;
739     output_end_row = SCREEN_ROWS - 1;
740     clrline(output_current_row, SCREEN_ROWS);
741 sysadm 1.26 break;
742 sysadm 1.74 case KEY_ESC:
743 sysadm 1.26 case KEY_LEFT:
744 sysadm 1.27 loop = 0;
745 sysadm 1.26 break;
746     case 'h':
747 sysadm 1.81 if (!show_help) // Not reentrant
748 sysadm 1.37 {
749     break;
750     }
751 sysadm 1.26 // Display help information
752 sysadm 1.37 show_help = 0;
753 sysadm 1.89 display_file(help_filename, 1);
754 sysadm 1.37 show_help = 1;
755 sysadm 1.81 case KEY_F5:
756 sysadm 1.26 // Refresh after display help information
757 sysadm 1.95 line_current -= (output_current_row - screen_begin_row);
758     output_current_row = screen_begin_row;
759     output_end_row = SCREEN_ROWS - 1;
760     clrline(output_current_row, SCREEN_ROWS);
761 sysadm 1.89 break;
762 sysadm 1.81 case 0: // Refresh bottom line
763     break;
764 sysadm 1.26 default:
765     input_ok = 0;
766     break;
767 sysadm 1.21 }
768 sysadm 1.41
769 sysadm 1.99 BBS_last_access_tm = time(NULL);
770 sysadm 1.6 }
771 sysadm 1.21
772 sysadm 1.26 continue;
773     }
774 sysadm 1.21
775 sysadm 1.55 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
776 sysadm 1.89 if (len >= sizeof(buffer))
777 sysadm 1.26 {
778 sysadm 1.87 log_error("Buffer overflow: len=%ld(%ld - %ld) line=%ld \n",
779 sysadm 1.62 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
780 sysadm 1.89 len = sizeof(buffer) - 1;
781 sysadm 1.26 }
782 sysadm 1.87 else if (len < 0)
783     {
784     log_error("Incorrect line offsets: len=%ld(%ld - %ld) line=%ld \n",
785     len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
786     len = 0;
787     }
788 sysadm 1.52
789 sysadm 1.55 memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
790 sysadm 1.52 buffer[len] = '\0';
791    
792 sysadm 1.95 moveto(output_current_row, 0);
793 sysadm 1.26 clrtoeol();
794     prints("%s", buffer);
795 sysadm 1.54 line_current++;
796 sysadm 1.95 output_current_row++;
797 sysadm 1.26 }
798 sysadm 1.6
799 sysadm 1.41 cleanup:
800 sysadm 1.78 return ch;
801     }
802    
803 sysadm 1.85 static int display_file_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
804 sysadm 1.81 {
805 sysadm 1.85 switch (*p_key)
806 sysadm 1.81 {
807     case 0: // Set msg
808 sysadm 1.85 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
809 sysadm 1.104 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] | "
810     "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] | "
811     "帮助[\033[32mh\033[33m] |");
812 sysadm 1.81 break;
813     }
814    
815     return 0;
816     }
817    
818 sysadm 1.89 int display_file(const char *filename, int eof_exit)
819 sysadm 1.78 {
820 sysadm 1.81 int ret;
821 sysadm 1.78 const void *p_shm;
822     size_t data_len;
823     long line_total;
824     const void *p_data;
825     const long *p_line_offsets;
826    
827     if ((p_shm = get_file_shm_readonly(filename, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
828     {
829     log_error("get_file_shm(%s) error\n", filename);
830     return KEY_NULL;
831     }
832    
833 sysadm 1.101 if (user_online_update("VIEW_FILE") < 0)
834     {
835     log_error("user_online_update(VIEW_FILE) error\n");
836     }
837    
838 sysadm 1.89 ret = display_data(p_data, line_total, p_line_offsets, eof_exit, display_file_key_handler, DATA_READ_HELP);
839 sysadm 1.78
840 sysadm 1.69 if (detach_file_shm(p_shm) < 0)
841     {
842     log_error("detach_file_shm(%s) error\n", filename);
843     }
844    
845 sysadm 1.81 return ret;
846 sysadm 1.1 }
847 sysadm 1.9
848 sysadm 1.73 int show_top(const char *str_left, const char *str_middle, const char *str_right)
849 sysadm 1.9 {
850 sysadm 1.71 char str_left_f[STR_TOP_LEFT_MAX_LEN + 1];
851     char str_middle_f[STR_TOP_MIDDLE_MAX_LEN + 1];
852     char str_right_f[STR_TOP_RIGHT_MAX_LEN + 1];
853 sysadm 1.70 int str_left_len;
854 sysadm 1.71 int str_middle_len;
855 sysadm 1.70 int str_right_len;
856 sysadm 1.71 int eol;
857 sysadm 1.51 int len;
858 sysadm 1.40
859 sysadm 1.71 strncpy(str_left_f, str_left, sizeof(str_left_f) - 1);
860     str_left_f[sizeof(str_left_f) - 1] = '\0';
861 sysadm 1.105 len = split_line(str_left_f, STR_TOP_LEFT_MAX_LEN / 2, &eol, &str_left_len, 1);
862 sysadm 1.71 str_left_f[len] = '\0';
863    
864     strncpy(str_middle_f, str_middle, sizeof(str_middle_f) - 1);
865     str_middle_f[sizeof(str_middle_f) - 1] = '\0';
866 sysadm 1.105 len = split_line(str_middle, STR_TOP_MIDDLE_MAX_LEN / 2, &eol, &str_middle_len, 1);
867 sysadm 1.71 str_middle_f[len] = '\0';
868    
869 sysadm 1.73 strncpy(str_right_f, str_right, sizeof(str_right_f) - 1);
870 sysadm 1.71 str_right_f[sizeof(str_right_f) - 1] = '\0';
871 sysadm 1.105 len = split_line(str_right, STR_TOP_RIGHT_MAX_LEN / 2, &eol, &str_right_len, 1);
872 sysadm 1.71 str_right_f[len] = '\0';
873 sysadm 1.9
874 sysadm 1.21 moveto(1, 0);
875 sysadm 1.26 clrtoeol();
876 sysadm 1.105 prints("\033[1;44;33m%s\033[37m%*s%s\033[33m%*s%s\033[m",
877     str_left_f, 44 - str_left_len - str_middle_len, "",
878     str_middle_f, 36 - str_right_len, "", str_right_f);
879 sysadm 1.9
880 sysadm 1.21 return 0;
881 sysadm 1.9 }
882    
883 sysadm 1.57 int show_bottom(const char *msg)
884 sysadm 1.9 {
885 sysadm 1.26 char str_time[LINE_BUFFER_LEN];
886 sysadm 1.21 time_t time_online;
887     struct tm *tm_online;
888 sysadm 1.77 char msg_f[LINE_BUFFER_LEN];
889 sysadm 1.72 int eol;
890 sysadm 1.58 int msg_len;
891     int len;
892     int len_username;
893 sysadm 1.88 char str_tm_online[LINE_BUFFER_LEN];
894 sysadm 1.9
895 sysadm 1.26 get_time_str(str_time, sizeof(str_time));
896 sysadm 1.9
897 sysadm 1.76 msg_f[0] = '\0';
898     msg_len = 0;
899 sysadm 1.77 if (msg != NULL)
900 sysadm 1.76 {
901 sysadm 1.77 strncpy(msg_f, msg, sizeof(msg_f) - 1);
902 sysadm 1.76 msg_f[sizeof(msg_f) - 1] = '\0';
903 sysadm 1.97 len = split_line(msg_f, 23, &eol, &msg_len, 1);
904 sysadm 1.77 msg_f[len] = '\0';
905 sysadm 1.76 }
906 sysadm 1.58
907     len_username = (int)strnlen(BBS_username, sizeof(BBS_username));
908    
909 sysadm 1.99 time_online = time(NULL) - BBS_login_tm;
910 sysadm 1.21 tm_online = gmtime(&time_online);
911 sysadm 1.88 if (tm_online->tm_mday > 1)
912     {
913     snprintf(str_tm_online, sizeof(str_tm_online),
914 sysadm 1.104 "\033[36m%2d\033[33m天\033[36m%2d\033[33m时",
915 sysadm 1.89 tm_online->tm_mday - 1, tm_online->tm_hour);
916 sysadm 1.88 }
917     else
918     {
919     snprintf(str_tm_online, sizeof(str_tm_online),
920 sysadm 1.104 "\033[36m%2d\033[33m时\033[36m%2d\033[33m分",
921 sysadm 1.89 tm_online->tm_hour, tm_online->tm_min);
922 sysadm 1.88 }
923 sysadm 1.9
924 sysadm 1.53 moveto(SCREEN_ROWS, 0);
925 sysadm 1.26 clrtoeol();
926 sysadm 1.104 prints("\033[1;44;33m时间[\033[36m%s\033[33m]%s%*s \033[33m帐号[\033[36m%s\033[33m][%s\033[33m]\033[m",
927 sysadm 1.88 str_time, msg_f, 38 - msg_len - len_username, "", BBS_username, str_tm_online);
928 sysadm 1.9
929 sysadm 1.21 return 0;
930 sysadm 1.9 }
931    
932 sysadm 1.21 int show_active_board()
933 sysadm 1.9 {
934 sysadm 1.59 static int line_current = 0;
935 sysadm 1.61 static const void *p_shm = NULL;
936 sysadm 1.59 static size_t data_len;
937     static long line_total;
938 sysadm 1.61 static const void *p_data;
939 sysadm 1.59 static const long *p_line_offsets;
940    
941 sysadm 1.65 static time_t t_last_show = 0;
942     static int line_last = 0;
943    
944 sysadm 1.26 char buffer[LINE_BUFFER_LEN];
945 sysadm 1.59 long int len;
946 sysadm 1.9
947 sysadm 1.61 if (p_shm == NULL)
948 sysadm 1.26 {
949 sysadm 1.69 if ((p_shm = get_file_shm_readonly(DATA_ACTIVE_BOARD, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
950 sysadm 1.9 {
951 sysadm 1.59 log_error("get_file_shm(%s) error\n", DATA_ACTIVE_BOARD);
952     return KEY_NULL;
953 sysadm 1.9 }
954 sysadm 1.26 }
955 sysadm 1.21
956 sysadm 1.99 if (time(NULL) - t_last_show >= 10)
957 sysadm 1.65 {
958     line_last = line_current;
959 sysadm 1.99 t_last_show = time(NULL);
960 sysadm 1.65 }
961     else
962     {
963     line_current = line_last;
964     }
965    
966 sysadm 1.64 clrline(2, 2 + ACTIVE_BOARD_HEIGHT);
967 sysadm 1.59
968 sysadm 1.26 for (int i = 0; i < ACTIVE_BOARD_HEIGHT; i++)
969     {
970 sysadm 1.59 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
971     if (len >= LINE_BUFFER_LEN)
972 sysadm 1.9 {
973 sysadm 1.62 log_error("buffer overflow: len=%ld(%ld - %ld) line=%ld \n",
974     len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
975 sysadm 1.59 len = LINE_BUFFER_LEN - 1;
976 sysadm 1.9 }
977 sysadm 1.59
978     memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
979     buffer[len] = '\0';
980    
981 sysadm 1.26 moveto(3 + i, 0);
982     prints("%s", buffer);
983 sysadm 1.59
984     line_current++;
985 sysadm 1.60 if (line_current >= line_total)
986 sysadm 1.59 {
987     line_current = 0;
988     break;
989     }
990 sysadm 1.9 }
991 sysadm 1.26
992 sysadm 1.21 return 0;
993 sysadm 1.9 }

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