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

Annotation of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.110 - (hide annotations)
Thu Oct 16 11:26:16 2025 UTC (5 months ago) by sysadm
Branch: MAIN
Changes since 1.109: +8 -2 lines
Content type: text/x-csrc
Refine logging of KEY_NULL and KEY_TIMEOUT

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 sysadm 1.109 #define STR_TOP_RIGHT_MAX_LEN 80
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.110 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
657     {
658     BBS_last_access_tm = time(NULL);
659     }
660    
661 sysadm 1.81 // extended key handler
662 sysadm 1.85 if (key_handler(&ch, &ctx) != 0)
663 sysadm 1.81 {
664     goto cleanup;
665     }
666    
667 sysadm 1.26 switch (ch)
668 sysadm 1.21 {
669 sysadm 1.67 case KEY_NULL:
670 sysadm 1.110 log_error("KEY_NULL\n");
671     goto cleanup;
672 sysadm 1.41 case KEY_TIMEOUT:
673 sysadm 1.110 log_error("User input timeout\n");
674 sysadm 1.41 goto cleanup;
675 sysadm 1.50 case KEY_HOME:
676 sysadm 1.95 if (line_current - output_current_row < 0) // Reach begin
677 sysadm 1.84 {
678     break;
679     }
680 sysadm 1.54 line_current = 0;
681 sysadm 1.95 output_current_row = screen_begin_row;
682     output_end_row = SCREEN_ROWS - 1;
683     clrline(output_current_row, SCREEN_ROWS);
684 sysadm 1.50 break;
685     case KEY_END:
686 sysadm 1.91 if (display_line_total < screen_row_total)
687 sysadm 1.83 {
688 sysadm 1.84 break;
689 sysadm 1.83 }
690 sysadm 1.91 line_current = display_line_total - screen_row_total;
691 sysadm 1.95 output_current_row = screen_begin_row;
692     output_end_row = SCREEN_ROWS - 1;
693     clrline(output_current_row, SCREEN_ROWS);
694 sysadm 1.50 break;
695 sysadm 1.26 case KEY_UP:
696 sysadm 1.95 if (line_current - output_current_row < 0) // Reach begin
697 sysadm 1.21 {
698     break;
699 sysadm 1.26 }
700 sysadm 1.95 line_current -= output_current_row;
701     output_current_row = screen_begin_row;
702 sysadm 1.89 // screen_end_line = screen_begin_line;
703 sysadm 1.39 // prints("\033[T"); // Scroll down 1 line
704 sysadm 1.95 output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line
705 sysadm 1.26 break;
706 sysadm 1.49 case CR:
707     igetch_reset();
708 sysadm 1.78 case KEY_SPACE:
709 sysadm 1.26 case KEY_DOWN:
710 sysadm 1.95 if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= display_line_total) // Reach end
711 sysadm 1.26 {
712 sysadm 1.21 break;
713 sysadm 1.26 }
714 sysadm 1.95 line_current += (screen_row_total - (output_current_row - screen_begin_row));
715     output_current_row = screen_row_total;
716     output_end_row = SCREEN_ROWS - 1;
717 sysadm 1.53 moveto(SCREEN_ROWS, 0);
718 sysadm 1.26 clrtoeol();
719 sysadm 1.104 // prints("\033[S"); // Scroll up 1 line
720 sysadm 1.103 prints("\n"); // Legacy Cterm only works with this line
721 sysadm 1.26 break;
722     case KEY_PGUP:
723 sysadm 1.95 if (line_current - output_current_row < 0) // Reach begin
724 sysadm 1.26 {
725 sysadm 1.21 break;
726 sysadm 1.26 }
727 sysadm 1.95 line_current -= ((screen_row_total - 1) + (output_current_row - screen_begin_row));
728 sysadm 1.54 if (line_current < 0)
729 sysadm 1.26 {
730 sysadm 1.54 line_current = 0;
731 sysadm 1.26 }
732 sysadm 1.95 output_current_row = screen_begin_row;
733     output_end_row = SCREEN_ROWS - 1;
734     clrline(output_current_row, SCREEN_ROWS);
735 sysadm 1.26 break;
736     case KEY_PGDN:
737 sysadm 1.95 if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= display_line_total) // Reach end
738 sysadm 1.26 {
739 sysadm 1.21 break;
740     }
741 sysadm 1.95 line_current += (screen_row_total - 1) - (output_current_row - screen_begin_row);
742 sysadm 1.91 if (line_current + screen_row_total > display_line_total) // No enough lines to display
743 sysadm 1.26 {
744 sysadm 1.91 line_current = display_line_total - screen_row_total;
745 sysadm 1.26 }
746 sysadm 1.95 output_current_row = screen_begin_row;
747     output_end_row = SCREEN_ROWS - 1;
748     clrline(output_current_row, SCREEN_ROWS);
749 sysadm 1.26 break;
750 sysadm 1.74 case KEY_ESC:
751 sysadm 1.26 case KEY_LEFT:
752 sysadm 1.27 loop = 0;
753 sysadm 1.26 break;
754     case 'h':
755 sysadm 1.81 if (!show_help) // Not reentrant
756 sysadm 1.37 {
757     break;
758     }
759 sysadm 1.26 // Display help information
760 sysadm 1.37 show_help = 0;
761 sysadm 1.89 display_file(help_filename, 1);
762 sysadm 1.37 show_help = 1;
763 sysadm 1.81 case KEY_F5:
764 sysadm 1.26 // Refresh after display help information
765 sysadm 1.95 line_current -= (output_current_row - screen_begin_row);
766     output_current_row = screen_begin_row;
767     output_end_row = SCREEN_ROWS - 1;
768     clrline(output_current_row, SCREEN_ROWS);
769 sysadm 1.89 break;
770 sysadm 1.81 case 0: // Refresh bottom line
771     break;
772 sysadm 1.26 default:
773     input_ok = 0;
774     break;
775 sysadm 1.21 }
776 sysadm 1.6 }
777 sysadm 1.21
778 sysadm 1.26 continue;
779     }
780 sysadm 1.21
781 sysadm 1.55 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
782 sysadm 1.89 if (len >= sizeof(buffer))
783 sysadm 1.26 {
784 sysadm 1.87 log_error("Buffer overflow: len=%ld(%ld - %ld) line=%ld \n",
785 sysadm 1.62 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
786 sysadm 1.89 len = sizeof(buffer) - 1;
787 sysadm 1.26 }
788 sysadm 1.87 else if (len < 0)
789     {
790     log_error("Incorrect line offsets: len=%ld(%ld - %ld) line=%ld \n",
791     len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
792     len = 0;
793     }
794 sysadm 1.52
795 sysadm 1.55 memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
796 sysadm 1.52 buffer[len] = '\0';
797    
798 sysadm 1.95 moveto(output_current_row, 0);
799 sysadm 1.26 clrtoeol();
800     prints("%s", buffer);
801 sysadm 1.54 line_current++;
802 sysadm 1.95 output_current_row++;
803 sysadm 1.26 }
804 sysadm 1.6
805 sysadm 1.41 cleanup:
806 sysadm 1.78 return ch;
807     }
808    
809 sysadm 1.85 static int display_file_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
810 sysadm 1.81 {
811 sysadm 1.85 switch (*p_key)
812 sysadm 1.81 {
813     case 0: // Set msg
814 sysadm 1.85 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
815 sysadm 1.104 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] | "
816     "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] | "
817     "帮助[\033[32mh\033[33m] |");
818 sysadm 1.81 break;
819     }
820    
821     return 0;
822     }
823    
824 sysadm 1.89 int display_file(const char *filename, int eof_exit)
825 sysadm 1.78 {
826 sysadm 1.81 int ret;
827 sysadm 1.78 const void *p_shm;
828     size_t data_len;
829     long line_total;
830     const void *p_data;
831     const long *p_line_offsets;
832    
833     if ((p_shm = get_file_shm_readonly(filename, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
834     {
835     log_error("get_file_shm(%s) error\n", filename);
836     return KEY_NULL;
837     }
838    
839 sysadm 1.101 if (user_online_update("VIEW_FILE") < 0)
840     {
841     log_error("user_online_update(VIEW_FILE) error\n");
842     }
843    
844 sysadm 1.89 ret = display_data(p_data, line_total, p_line_offsets, eof_exit, display_file_key_handler, DATA_READ_HELP);
845 sysadm 1.78
846 sysadm 1.69 if (detach_file_shm(p_shm) < 0)
847     {
848     log_error("detach_file_shm(%s) error\n", filename);
849     }
850    
851 sysadm 1.81 return ret;
852 sysadm 1.1 }
853 sysadm 1.9
854 sysadm 1.73 int show_top(const char *str_left, const char *str_middle, const char *str_right)
855 sysadm 1.9 {
856 sysadm 1.71 char str_left_f[STR_TOP_LEFT_MAX_LEN + 1];
857     char str_middle_f[STR_TOP_MIDDLE_MAX_LEN + 1];
858     char str_right_f[STR_TOP_RIGHT_MAX_LEN + 1];
859 sysadm 1.70 int str_left_len;
860 sysadm 1.71 int str_middle_len;
861 sysadm 1.70 int str_right_len;
862 sysadm 1.71 int eol;
863 sysadm 1.51 int len;
864 sysadm 1.40
865 sysadm 1.71 strncpy(str_left_f, str_left, sizeof(str_left_f) - 1);
866     str_left_f[sizeof(str_left_f) - 1] = '\0';
867 sysadm 1.105 len = split_line(str_left_f, STR_TOP_LEFT_MAX_LEN / 2, &eol, &str_left_len, 1);
868 sysadm 1.71 str_left_f[len] = '\0';
869    
870     strncpy(str_middle_f, str_middle, sizeof(str_middle_f) - 1);
871     str_middle_f[sizeof(str_middle_f) - 1] = '\0';
872 sysadm 1.105 len = split_line(str_middle, STR_TOP_MIDDLE_MAX_LEN / 2, &eol, &str_middle_len, 1);
873 sysadm 1.71 str_middle_f[len] = '\0';
874    
875 sysadm 1.73 strncpy(str_right_f, str_right, sizeof(str_right_f) - 1);
876 sysadm 1.71 str_right_f[sizeof(str_right_f) - 1] = '\0';
877 sysadm 1.105 len = split_line(str_right, STR_TOP_RIGHT_MAX_LEN / 2, &eol, &str_right_len, 1);
878 sysadm 1.71 str_right_f[len] = '\0';
879 sysadm 1.9
880 sysadm 1.21 moveto(1, 0);
881 sysadm 1.26 clrtoeol();
882 sysadm 1.105 prints("\033[1;44;33m%s\033[37m%*s%s\033[33m%*s%s\033[m",
883     str_left_f, 44 - str_left_len - str_middle_len, "",
884     str_middle_f, 36 - str_right_len, "", str_right_f);
885 sysadm 1.9
886 sysadm 1.21 return 0;
887 sysadm 1.9 }
888    
889 sysadm 1.57 int show_bottom(const char *msg)
890 sysadm 1.9 {
891 sysadm 1.26 char str_time[LINE_BUFFER_LEN];
892 sysadm 1.21 time_t time_online;
893     struct tm *tm_online;
894 sysadm 1.77 char msg_f[LINE_BUFFER_LEN];
895 sysadm 1.72 int eol;
896 sysadm 1.58 int msg_len;
897     int len;
898     int len_username;
899 sysadm 1.88 char str_tm_online[LINE_BUFFER_LEN];
900 sysadm 1.9
901 sysadm 1.26 get_time_str(str_time, sizeof(str_time));
902 sysadm 1.9
903 sysadm 1.76 msg_f[0] = '\0';
904     msg_len = 0;
905 sysadm 1.77 if (msg != NULL)
906 sysadm 1.76 {
907 sysadm 1.77 strncpy(msg_f, msg, sizeof(msg_f) - 1);
908 sysadm 1.76 msg_f[sizeof(msg_f) - 1] = '\0';
909 sysadm 1.97 len = split_line(msg_f, 23, &eol, &msg_len, 1);
910 sysadm 1.77 msg_f[len] = '\0';
911 sysadm 1.76 }
912 sysadm 1.58
913     len_username = (int)strnlen(BBS_username, sizeof(BBS_username));
914    
915 sysadm 1.99 time_online = time(NULL) - BBS_login_tm;
916 sysadm 1.21 tm_online = gmtime(&time_online);
917 sysadm 1.88 if (tm_online->tm_mday > 1)
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_mday - 1, tm_online->tm_hour);
922 sysadm 1.88 }
923     else
924     {
925     snprintf(str_tm_online, sizeof(str_tm_online),
926 sysadm 1.104 "\033[36m%2d\033[33m时\033[36m%2d\033[33m分",
927 sysadm 1.89 tm_online->tm_hour, tm_online->tm_min);
928 sysadm 1.88 }
929 sysadm 1.9
930 sysadm 1.53 moveto(SCREEN_ROWS, 0);
931 sysadm 1.26 clrtoeol();
932 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",
933 sysadm 1.88 str_time, msg_f, 38 - msg_len - len_username, "", BBS_username, str_tm_online);
934 sysadm 1.9
935 sysadm 1.21 return 0;
936 sysadm 1.9 }
937    
938 sysadm 1.21 int show_active_board()
939 sysadm 1.9 {
940 sysadm 1.59 static int line_current = 0;
941 sysadm 1.61 static const void *p_shm = NULL;
942 sysadm 1.59 static size_t data_len;
943     static long line_total;
944 sysadm 1.61 static const void *p_data;
945 sysadm 1.59 static const long *p_line_offsets;
946    
947 sysadm 1.65 static time_t t_last_show = 0;
948     static int line_last = 0;
949    
950 sysadm 1.26 char buffer[LINE_BUFFER_LEN];
951 sysadm 1.59 long int len;
952 sysadm 1.9
953 sysadm 1.61 if (p_shm == NULL)
954 sysadm 1.26 {
955 sysadm 1.69 if ((p_shm = get_file_shm_readonly(DATA_ACTIVE_BOARD, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
956 sysadm 1.9 {
957 sysadm 1.59 log_error("get_file_shm(%s) error\n", DATA_ACTIVE_BOARD);
958     return KEY_NULL;
959 sysadm 1.9 }
960 sysadm 1.26 }
961 sysadm 1.21
962 sysadm 1.99 if (time(NULL) - t_last_show >= 10)
963 sysadm 1.65 {
964     line_last = line_current;
965 sysadm 1.99 t_last_show = time(NULL);
966 sysadm 1.65 }
967     else
968     {
969     line_current = line_last;
970     }
971    
972 sysadm 1.64 clrline(2, 2 + ACTIVE_BOARD_HEIGHT);
973 sysadm 1.59
974 sysadm 1.26 for (int i = 0; i < ACTIVE_BOARD_HEIGHT; i++)
975     {
976 sysadm 1.59 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
977     if (len >= LINE_BUFFER_LEN)
978 sysadm 1.9 {
979 sysadm 1.62 log_error("buffer overflow: len=%ld(%ld - %ld) line=%ld \n",
980     len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
981 sysadm 1.59 len = LINE_BUFFER_LEN - 1;
982 sysadm 1.9 }
983 sysadm 1.59
984     memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
985     buffer[len] = '\0';
986    
987 sysadm 1.26 moveto(3 + i, 0);
988     prints("%s", buffer);
989 sysadm 1.59
990     line_current++;
991 sysadm 1.60 if (line_current >= line_total)
992 sysadm 1.59 {
993     line_current = 0;
994     break;
995     }
996 sysadm 1.9 }
997 sysadm 1.26
998 sysadm 1.21 return 0;
999 sysadm 1.9 }

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