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

Diff of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.105 by sysadm, Wed Jul 2 06:25:02 2025 UTC Revision 1.122 by sysadm, Tue Nov 4 14:58:56 2025 UTC
# Line 1  Line 1 
1  /***************************************************************************  /* SPDX-License-Identifier: GPL-3.0-or-later */
2                                                    screen.c  -  description  /*
3                                                           -------------------   * screen
4          Copyright            : (C) 2004-2025 by Leaflet   *   - advanced telnet-based user interactive input / output features
5          Email                : leaflet@leafok.com   *
6   ***************************************************************************/   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>
7     */
 /***************************************************************************  
  *                                                                         *  
  *   This program is free software; you can redistribute it and/or modify  *  
  *   it under the terms of the GNU General Public License as published by  *  
  *   the Free Software Foundation; either version 3 of the License, or     *  
  *   (at your option) any later version.                                   *  
  *                                                                         *  
  ***************************************************************************/  
8    
9  #include "bbs.h"  #include "bbs.h"
10  #include "common.h"  #include "common.h"
# Line 38  Line 30 
30    
31  #define STR_TOP_LEFT_MAX_LEN 80  #define STR_TOP_LEFT_MAX_LEN 80
32  #define STR_TOP_MIDDLE_MAX_LEN 40  #define STR_TOP_MIDDLE_MAX_LEN 40
33  #define STR_TOP_RIGHT_MAX_LEN 40  #define STR_TOP_RIGHT_MAX_LEN 80
34    
35    static size_t get_time_str(char *s, size_t len)
36    {
37            time_t curtime;
38            struct tm local_tm;
39    
40            time(&curtime);
41            localtime_r(&curtime, &local_tm);
42            size_t j = strftime(s, len, "%m/%d %H:%M %Z", &local_tm);
43    
44            return j;
45    }
46    
47  void moveto(int row, int col)  void moveto(int row, int col)
48  {  {
# Line 81  void clearscr() Line 85  void clearscr()
85          moveto(0, 0);          moveto(0, 0);
86  }  }
87    
88  int press_any_key()  inline int press_any_key()
89  {  {
90            return press_any_key_ex("                           \033[1;33m按任意键继续...\033[m", 60);
91    }
92    
93    int press_any_key_ex(const char *msg, int sec)
94    {
95            int ch = 0;
96            int duration = 0;
97            time_t t_begin = time(NULL);
98    
99          moveto(SCREEN_ROWS, 0);          moveto(SCREEN_ROWS, 0);
100          clrtoeol();          clrtoeol();
101    
102          prints("                           \033[1;33m按任意键继续...\033[0;37m");          prints(msg);
103          iflush();          iflush();
104    
105          return igetch_t(MIN(MAX_DELAY_TIME, 60));          igetch_reset();
106    
107            do
108            {
109                    ch = igetch_t(sec - duration);
110                    duration = (int)(time(NULL) - t_begin);
111            } while (!SYS_server_exit && ch == 0 && duration < 60);
112    
113            return ch;
114  }  }
115    
116  void set_input_echo(int echo)  void set_input_echo(int echo)
# Line 97  void set_input_echo(int echo) Line 118  void set_input_echo(int echo)
118          if (echo)          if (echo)
119          {          {
120                  outc('\x83'); // ASCII code 131                  outc('\x83'); // ASCII code 131
                 iflush();  
121          }          }
122          else          else
123          {          {
124                  //    outc ('\x85'); // ASCII code 133                  // outc ('\x85'); // ASCII code 133
125                  prints("\xff\xfb\x01\xff\xfb\x03");                  prints("\xff\xfb\x01\xff\xfb\x03");
                 iflush();  
                 igetch(0);  
                 igetch_reset();  
126          }          }
127            iflush();
128  }  }
129    
130  static int _str_input(char *buffer, int buf_size, int max_display_len, int echo_mode)  static int _str_input(char *buffer, int buf_size, int max_display_len, int echo_mode)
# Line 130  static int _str_input(char *buffer, int Line 148  static int _str_input(char *buffer, int
148    
149                  if (ch == CR)                  if (ch == CR)
150                  {                  {
                         igetch_reset();  
151                          break;                          break;
152                  }                  }
153                  else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe                  else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
# Line 148  static int _str_input(char *buffer, int Line 165  static int _str_input(char *buffer, int
165                                  offset--;                                  offset--;
166                                  if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8                                  if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
167                                  {                                  {
168                                          while (offset > 0 && (buffer[offset] & 0b11000000) != 0b11000000)                                          while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
169                                          {                                          {
170                                                  offset--;                                                  offset--;
171                                          }                                          }
# Line 169  static int _str_input(char *buffer, int Line 186  static int _str_input(char *buffer, int
186                  else if ((ch & 0xff80) == 0x80) // head of multi-byte character                  else if ((ch & 0xff80) == 0x80) // head of multi-byte character
187                  {                  {
188                          str_len = 0;                          str_len = 0;
189                          c = (char)(ch & 0b11110000);                          c = (char)(ch & 0xf0);
190                          while (c & 0b10000000)                          while (c & 0x80)
191                          {                          {
192                                  input_str[str_len] = (char)(ch - 256);                                  input_str[str_len] = (char)(ch - 256);
193                                  str_len++;                                  str_len++;
194                                  c = (c & 0b01111111) << 1;                                  c = (c & 0x7f) << 1;
195    
196                                  if ((c & 0b10000000) == 0) // Input completed                                  if ((c & 0x80) == 0) // Input completed
197                                  {                                  {
198                                          break;                                          break;
199                                  }                                  }
# Line 185  static int _str_input(char *buffer, int Line 202  static int _str_input(char *buffer, int
202                                  ch = igetch(100);                                                // 0.1 second                                  ch = igetch(100);                                                // 0.1 second
203                                  if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input                                  if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
204                                  {                                  {
205    #ifdef _DEBUG
206                                          log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);                                          log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
207    #endif
208                                          str_len = 0;                                          str_len = 0;
209                                          break;                                          break;
210                                  }                                  }
# Line 264  int str_input(char *buffer, int buf_size Line 283  int str_input(char *buffer, int buf_size
283          iflush();          iflush();
284    
285          return len;          return len;
286  };  }
287    
288  int get_data(int row, int col, char *prompt, char *buffer, int buf_size, int max_display_len, int echo_mode)  int get_data(int row, int col, char *prompt, char *buffer, int buf_size, int max_display_len)
289  {  {
290          int len;          int len = 0;
291            int col_cur = 0;
292            int ch;
293            int offset = 0;
294            int eol;
295            int display_len;
296            char input_str[4];
297            int str_len = 0;
298            char c;
299    
300            buffer[buf_size - 1] = '\0';
301            offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
302            buffer[offset] = '\0';
303            len = offset;
304            col_cur = col + str_length(prompt, 1) + display_len;
305    
306          moveto(row, col);          moveto(row, col);
307          prints("%s", prompt);          prints("%s", prompt);
308          prints("%s", buffer);          prints("%s", buffer);
309            prints("%*s", max_display_len - display_len, "");
310            moveto(row, col_cur);
311          iflush();          iflush();
312    
313          len = _str_input(buffer, buf_size, max_display_len, echo_mode);          igetch_reset();
314    
315            while (!SYS_server_exit)
316            {
317                    ch = igetch_t(MIN(MAX_DELAY_TIME, 60));
318    
319                    if (ch == CR)
320                    {
321                            break;
322                    }
323                    else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
324                    {
325                            return -1;
326                    }
327                    else if (ch == LF || ch == '\0')
328                    {
329                            continue;
330                    }
331                    else if (ch == BACKSPACE)
332                    {
333                            if (offset > 0)
334                            {
335                                    str_len = 1;
336                                    offset--;
337                                    if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
338                                    {
339                                            while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
340                                            {
341                                                    str_len++;
342                                                    offset--;
343                                            }
344                                            display_len--;
345                                            col_cur--;
346                                    }
347    
348                                    memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
349                                    len -= str_len;
350                                    buffer[len] = '\0';
351                                    display_len--;
352                                    col_cur--;
353    
354                                    moveto(row, col_cur);
355                                    prints("%s", buffer + offset);
356                                    prints("%*s", max_display_len - display_len, "");
357                                    moveto(row, col_cur);
358                                    iflush();
359                            }
360                            continue;
361                    }
362                    else if (ch == KEY_DEL)
363                    {
364                            if (offset < len)
365                            {
366                                    if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
367                                    {
368                                            str_len = 0;
369                                            c = (char)(buffer[offset] & 0xf0);
370                                            while (c & 0x80)
371                                            {
372                                                    str_len++;
373                                                    c = (c & 0x7f) << 1;
374                                            }
375                                            display_len--;
376                                    }
377                                    else
378                                    {
379                                            str_len = 1;
380                                    }
381    
382                                    memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
383                                    len -= str_len;
384                                    buffer[len] = '\0';
385                                    display_len--;
386    
387                                    moveto(row, col_cur);
388                                    prints("%s", buffer + offset);
389                                    prints("%*s", max_display_len - display_len, "");
390                                    moveto(row, col_cur);
391                                    iflush();
392                            }
393                            continue;
394                    }
395                    else if (ch == KEY_LEFT)
396                    {
397                            if (offset > 0)
398                            {
399                                    str_len = 1;
400                                    offset--;
401                                    if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
402                                    {
403                                            while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
404                                            {
405                                                    str_len++;
406                                                    offset--;
407                                            }
408                                            col_cur--;
409                                    }
410                                    col_cur--;
411    
412                                    moveto(row, col_cur);
413                                    iflush();
414                            }
415                            continue;
416                    }
417                    else if (ch == KEY_RIGHT)
418                    {
419                            if (offset < len)
420                            {
421                                    str_len = 0;
422                                    if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
423                                    {
424                                            c = (char)(buffer[offset] & 0xf0);
425                                            while (c & 0x80)
426                                            {
427                                                    str_len++;
428                                                    c = (c & 0x7f) << 1;
429                                            }
430                                            col_cur++;
431                                    }
432                                    else
433                                    {
434                                            str_len = 1;
435                                    }
436    
437                                    col_cur++;
438                                    offset += str_len;
439    
440                                    moveto(row, col_cur);
441                                    iflush();
442                            }
443                            continue;
444                    }
445                    else if (ch == KEY_HOME || ch == KEY_UP)
446                    {
447                            if (offset > 0)
448                            {
449                                    offset = 0;
450                                    col_cur = col + str_length(prompt, 1);
451    
452                                    moveto(row, col_cur);
453                                    iflush();
454                            }
455                            continue;
456                    }
457                    else if (ch == KEY_END || ch == KEY_DOWN)
458                    {
459                            if (offset < len)
460                            {
461                                    offset = len;
462                                    col_cur = col + str_length(prompt, 1) + display_len;
463    
464                                    moveto(row, col_cur);
465                                    iflush();
466                            }
467                            continue;
468                    }
469                    else if (ch > 255 || iscntrl(ch))
470                    {
471                            continue;
472                    }
473                    else if ((ch & 0xff80) == 0x80) // head of multi-byte character
474                    {
475                            str_len = 0;
476                            c = (char)(ch & 0xf0);
477                            while (c & 0x80)
478                            {
479                                    input_str[str_len] = (char)(ch - 256);
480                                    str_len++;
481                                    c = (c & 0x7f) << 1;
482    
483                                    if ((c & 0x80) == 0) // Input completed
484                                    {
485                                            break;
486                                    }
487    
488                                    // Expect additional bytes of input
489                                    ch = igetch(100);                                                // 0.1 second
490                                    if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
491                                    {
492    #ifdef _DEBUG
493                                            log_error("Ignore %d bytes of incomplete UTF8 character\n", str_len);
494    #endif
495                                            str_len = 0;
496                                            break;
497                                    }
498                            }
499    
500                            if (str_len == 0) // Incomplete input
501                            {
502                                    continue;
503                            }
504    
505                            if (len + str_len > buf_size - 1 || display_len + 2 > max_display_len) // No enough space for Chinese character
506                            {
507                                    outc('\a');
508                                    iflush();
509                                    continue;
510                            }
511    
512                            memmove(buffer + offset + str_len, buffer + offset, (size_t)(len - offset));
513                            memcpy(buffer + offset, input_str, (size_t)str_len);
514                            len += str_len;
515                            buffer[len] = '\0';
516                            display_len += 2;
517    
518                            moveto(row, col_cur);
519                            prints("%s", buffer + offset);
520                            prints("%*s", max_display_len - display_len, "");
521    
522                            col_cur += 2;
523    
524                            moveto(row, col_cur);
525                            iflush();
526    
527                            offset += str_len;
528                    }
529                    else if (ch >= 32 && ch < 127) // Printable character
530                    {
531                            if (len + 1 > buf_size - 1 || display_len + 1 > max_display_len)
532                            {
533                                    outc('\a');
534                                    iflush();
535                                    continue;
536                            }
537    
538                            memmove(buffer + offset + 1, buffer + offset, (size_t)(len - offset));
539                            buffer[offset] = (char)ch;
540                            len++;
541                            buffer[len] = '\0';
542                            display_len++;
543    
544                            moveto(row, col_cur);
545                            prints("%s", buffer + offset);
546                            prints("%*s", max_display_len - display_len, "");
547    
548                            col_cur++;
549    
550                            moveto(row, col_cur);
551                            iflush();
552    
553                            offset++;
554                    }
555                    else // Invalid character
556                    {
557                            continue;
558                    }
559            }
560    
561          return len;          return len;
562  }  }
# Line 367  int display_data(const void *p_data, lon Line 648  int display_data(const void *p_data, lon
648                                  ch = igetch_t(MAX_DELAY_TIME);                                  ch = igetch_t(MAX_DELAY_TIME);
649                                  input_ok = 1;                                  input_ok = 1;
650    
651                                    if (ch != KEY_NULL && ch != KEY_TIMEOUT)
652                                    {
653                                            BBS_last_access_tm = time(NULL);
654                                    }
655    
656                                  // extended key handler                                  // extended key handler
657                                  if (key_handler(&ch, &ctx) != 0)                                  if (key_handler(&ch, &ctx) != 0)
658                                  {                                  {
# Line 376  int display_data(const void *p_data, lon Line 662  int display_data(const void *p_data, lon
662                                  switch (ch)                                  switch (ch)
663                                  {                                  {
664                                  case KEY_NULL:                                  case KEY_NULL:
665                                            log_error("KEY_NULL\n");
666                                            goto cleanup;
667                                  case KEY_TIMEOUT:                                  case KEY_TIMEOUT:
668                                            log_error("User input timeout\n");
669                                          goto cleanup;                                          goto cleanup;
670                                  case KEY_HOME:                                  case KEY_HOME:
671                                          if (line_current - output_current_row < 0) // Reach begin                                          if (line_current - output_current_row < 0) // Reach begin
# Line 410  int display_data(const void *p_data, lon Line 699  int display_data(const void *p_data, lon
699                                          output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line                                          output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line
700                                          break;                                          break;
701                                  case CR:                                  case CR:
                                         igetch_reset();  
                                 case KEY_SPACE:  
702                                  case KEY_DOWN:                                  case KEY_DOWN:
703                                          if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= display_line_total) // Reach end                                          if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= display_line_total) // Reach end
704                                          {                                          {
# Line 439  int display_data(const void *p_data, lon Line 726  int display_data(const void *p_data, lon
726                                          output_end_row = SCREEN_ROWS - 1;                                          output_end_row = SCREEN_ROWS - 1;
727                                          clrline(output_current_row, SCREEN_ROWS);                                          clrline(output_current_row, SCREEN_ROWS);
728                                          break;                                          break;
729                                    case KEY_SPACE:
730                                  case KEY_PGDN:                                  case KEY_PGDN:
731                                          if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= display_line_total) // Reach end                                          if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= display_line_total) // Reach end
732                                          {                                          {
# Line 479  int display_data(const void *p_data, lon Line 767  int display_data(const void *p_data, lon
767                                          input_ok = 0;                                          input_ok = 0;
768                                          break;                                          break;
769                                  }                                  }
   
                                 BBS_last_access_tm = time(NULL);  
770                          }                          }
771    
772                          continue;                          continue;
# Line 597  int show_top(const char *str_left, const Line 883  int show_top(const char *str_left, const
883  int show_bottom(const char *msg)  int show_bottom(const char *msg)
884  {  {
885          char str_time[LINE_BUFFER_LEN];          char str_time[LINE_BUFFER_LEN];
886            int len_str_time;
887          time_t time_online;          time_t time_online;
888          struct tm *tm_online;          struct tm *tm_online;
889          char msg_f[LINE_BUFFER_LEN];          char msg_f[LINE_BUFFER_LEN];
890          int eol;          int eol;
891          int msg_len;          int len_msg;
892          int len;          int len;
893          int len_username;          int len_username;
894          char str_tm_online[LINE_BUFFER_LEN];          char str_tm_online[LINE_BUFFER_LEN];
895    
896          get_time_str(str_time, sizeof(str_time));          len_str_time = (int)get_time_str(str_time, sizeof(str_time));
897    
898          msg_f[0] = '\0';          msg_f[0] = '\0';
899          msg_len = 0;          len_msg = 0;
900          if (msg != NULL)          if (msg != NULL)
901          {          {
902                  strncpy(msg_f, msg, sizeof(msg_f) - 1);                  strncpy(msg_f, msg, sizeof(msg_f) - 1);
903                  msg_f[sizeof(msg_f) - 1] = '\0';                  msg_f[sizeof(msg_f) - 1] = '\0';
904                  len = split_line(msg_f, 23, &eol, &msg_len, 1);                  len = split_line(msg_f, 23, &eol, &len_msg, 1);
905                  msg_f[len] = '\0';                  msg_f[len] = '\0';
906          }          }
907    
# Line 625  int show_bottom(const char *msg) Line 912  int show_bottom(const char *msg)
912          if (tm_online->tm_mday > 1)          if (tm_online->tm_mday > 1)
913          {          {
914                  snprintf(str_tm_online, sizeof(str_tm_online),                  snprintf(str_tm_online, sizeof(str_tm_online),
915                                   "\033[36m%2d\033[33m天\033[36m%2d\033[33m时",                                   "\033[36m%d\033[33md \033[36m%d\033[33m:\033[36m%.2d",
916                                   tm_online->tm_mday - 1, tm_online->tm_hour);                                   tm_online->tm_mday - 1, tm_online->tm_hour, tm_online->tm_min);
917          }          }
918          else          else
919          {          {
920                  snprintf(str_tm_online, sizeof(str_tm_online),                  snprintf(str_tm_online, sizeof(str_tm_online),
921                                   "\033[36m%2d\033[33m时\033[36m%2d\033[33m分",                                   "\033[36m%d\033[33m:\033[36m%.2d",
922                                   tm_online->tm_hour, tm_online->tm_min);                                   tm_online->tm_hour, tm_online->tm_min);
923          }          }
924    
925          moveto(SCREEN_ROWS, 0);          moveto(SCREEN_ROWS, 0);
926          clrtoeol();          clrtoeol();
927          prints("\033[1;44;33m时间[\033[36m%s\033[33m]%s%*s \033[33m帐号[\033[36m%s\033[33m][%s\033[33m]\033[m",          prints("\033[1;44;33m时间[\033[36m%s\033[33m]%s%*s \033[33m用户[\033[36m%s\033[33m][%s\033[33m]\033[m",
928                     str_time, msg_f, 38 - msg_len - len_username, "", BBS_username, str_tm_online);                     str_time, msg_f, 61 - len_str_time - len_msg - len_username, "", BBS_username, str_tm_online);
929    
930          return 0;          return 0;
931  }  }


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

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