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

Contents of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.115 - (show annotations)
Sat Oct 18 12:06:10 2025 UTC (4 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.114: +18 -18 lines
Content type: text/x-csrc
Refine code to keep compatible with gcc -Wpedantic option

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

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