12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022 |
- /*
- * Copyright (c) 2006-2025, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2006-04-30 Bernard the first version for FinSH
- * 2006-05-08 Bernard change finsh thread stack to 2048
- * 2006-06-03 Bernard add support for skyeye
- * 2006-09-24 Bernard remove the code related with hardware
- * 2010-01-18 Bernard fix down then up key bug.
- * 2010-03-19 Bernard fix backspace issue and fix device read in shell.
- * 2010-04-01 Bernard add prompt output when start and remove the empty history
- * 2011-02-23 Bernard fix variable section end issue of finsh shell
- * initialization when use GNU GCC compiler.
- * 2016-11-26 armink add password authentication
- * 2018-07-02 aozima add custom prompt support.
- */
- #include <rthw.h>
- #include <string.h>
- #include <stdio.h>
- #ifdef RT_USING_FINSH
- #include "shell.h"
- #include "msh.h"
- #ifdef DFS_USING_POSIX
- #include <unistd.h>
- #include <fcntl.h>
- #endif /* DFS_USING_POSIX */
- #ifdef RT_USING_POSIX_STDIO
- #include <unistd.h>
- #include <posix/stdio.h>
- #endif /* RT_USING_POSIX_STDIO */
- /* finsh thread */
- #ifndef RT_USING_HEAP
- static struct rt_thread finsh_thread;
- rt_align(RT_ALIGN_SIZE)
- static char finsh_thread_stack[FINSH_THREAD_STACK_SIZE];
- struct finsh_shell _shell;
- #endif
- /* finsh symtab */
- #ifdef FINSH_USING_SYMTAB
- struct finsh_syscall *_syscall_table_begin = NULL;
- struct finsh_syscall *_syscall_table_end = NULL;
- #endif
- struct finsh_shell *shell;
- static char *finsh_prompt_custom = RT_NULL;
- #if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__))
- struct finsh_syscall *finsh_syscall_next(struct finsh_syscall *call)
- {
- unsigned int *ptr;
- ptr = (unsigned int *)(call + 1);
- while ((*ptr == 0) && ((unsigned int *)ptr < (unsigned int *) _syscall_table_end))
- ptr ++;
- return (struct finsh_syscall *)ptr;
- }
- #endif /* defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__)) */
- #ifdef RT_USING_HEAP
- int finsh_set_prompt(const char *prompt)
- {
- if (finsh_prompt_custom)
- {
- rt_free(finsh_prompt_custom);
- finsh_prompt_custom = RT_NULL;
- }
- /* strdup */
- if (prompt)
- {
- finsh_prompt_custom = (char *)rt_malloc(strlen(prompt) + 1);
- if (finsh_prompt_custom)
- {
- strcpy(finsh_prompt_custom, prompt);
- }
- }
- return 0;
- }
- #endif /* RT_USING_HEAP */
- #define _MSH_PROMPT "msh "
- const char *finsh_get_prompt(void)
- {
- static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0};
- /* check prompt mode */
- if (!shell->prompt_mode)
- {
- finsh_prompt[0] = '\0';
- return finsh_prompt;
- }
- if (finsh_prompt_custom)
- {
- strncpy(finsh_prompt, finsh_prompt_custom, sizeof(finsh_prompt) - 1);
- }
- else
- {
- strcpy(finsh_prompt, _MSH_PROMPT);
- }
- #if defined(DFS_USING_POSIX) && defined(DFS_USING_WORKDIR)
- /* get current working directory */
- getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt));
- #endif
- if (rt_strlen(finsh_prompt) + 2 < RT_CONSOLEBUF_SIZE)
- {
- finsh_prompt[rt_strlen(finsh_prompt)] = '>';
- finsh_prompt[rt_strlen(finsh_prompt) + 1] = '\0';
- }
- return finsh_prompt;
- }
- /**
- * @ingroup group_finsh
- *
- * This function get the prompt mode of finsh shell.
- *
- * @return prompt the prompt mode, 0 disable prompt mode, other values enable prompt mode.
- */
- rt_uint32_t finsh_get_prompt_mode(void)
- {
- RT_ASSERT(shell != RT_NULL);
- return shell->prompt_mode;
- }
- /**
- * @ingroup group_finsh
- *
- * This function set the prompt mode of finsh shell.
- *
- * The parameter 0 disable prompt mode, other values enable prompt mode.
- *
- * @param prompt_mode the prompt mode
- */
- void finsh_set_prompt_mode(rt_uint32_t prompt_mode)
- {
- RT_ASSERT(shell != RT_NULL);
- shell->prompt_mode = prompt_mode;
- }
- int finsh_getchar(void)
- {
- #ifdef RT_USING_DEVICE
- char ch = 0;
- #ifdef RT_USING_POSIX_STDIO
- if(read(rt_posix_stdio_get_console(), &ch, 1) > 0)
- {
- return ch;
- }
- else
- {
- return -1; /* EOF */
- }
- #else
- rt_device_t device;
- RT_ASSERT(shell != RT_NULL);
- device = shell->device;
- if (device == RT_NULL)
- {
- return -1; /* EOF */
- }
- while (rt_device_read(device, -1, &ch, 1) != 1)
- {
- rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER);
- if (shell->device != device)
- {
- device = shell->device;
- if (device == RT_NULL)
- {
- return -1;
- }
- }
- }
- return ch;
- #endif /* RT_USING_POSIX_STDIO */
- #else
- extern signed char rt_hw_console_getchar(void);
- return rt_hw_console_getchar();
- #endif /* RT_USING_DEVICE */
- }
- #if !defined(RT_USING_POSIX_STDIO) && defined(RT_USING_DEVICE)
- static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size)
- {
- RT_ASSERT(shell != RT_NULL);
- /* release semaphore to let finsh thread rx data */
- rt_sem_release(&shell->rx_sem);
- return RT_EOK;
- }
- /**
- * @ingroup group_finsh
- *
- * This function sets the input device of finsh shell.
- *
- * @param device_name the name of new input device.
- */
- void finsh_set_device(const char *device_name)
- {
- rt_device_t dev = RT_NULL;
- RT_ASSERT(shell != RT_NULL);
- dev = rt_device_find(device_name);
- if (dev == RT_NULL)
- {
- rt_kprintf("finsh: can not find device: %s\n", device_name);
- return;
- }
- /* check whether it's a same device */
- if (dev == shell->device) return;
- /* open this device and set the new device in finsh shell */
- if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \
- RT_DEVICE_FLAG_STREAM) == RT_EOK)
- {
- if (shell->device != RT_NULL)
- {
- /* close old finsh device */
- rt_device_close(shell->device);
- rt_device_set_rx_indicate(shell->device, RT_NULL);
- }
- /* clear line buffer before switch to new device */
- rt_memset(shell->line, 0, sizeof(shell->line));
- shell->line_curpos = shell->line_position = 0;
- shell->device = dev;
- rt_device_set_rx_indicate(dev, finsh_rx_ind);
- }
- }
- /**
- * @ingroup group_finsh
- *
- * This function returns current finsh shell input device.
- *
- * @return the finsh shell input device name is returned.
- */
- const char *finsh_get_device()
- {
- RT_ASSERT(shell != RT_NULL);
- return shell->device->parent.name;
- }
- #endif /* !defined(RT_USING_POSIX_STDIO) && defined(RT_USING_DEVICE) */
- /**
- * @ingroup group_finsh
- *
- * This function set the echo mode of finsh shell.
- *
- * FINSH_OPTION_ECHO=0x01 is echo mode, other values are none-echo mode.
- *
- * @param echo the echo mode
- */
- void finsh_set_echo(rt_uint32_t echo)
- {
- RT_ASSERT(shell != RT_NULL);
- shell->echo_mode = (rt_uint8_t)echo;
- }
- /**
- * @ingroup group_finsh
- *
- * This function gets the echo mode of finsh shell.
- *
- * @return the echo mode
- */
- rt_uint32_t finsh_get_echo()
- {
- RT_ASSERT(shell != RT_NULL);
- return shell->echo_mode;
- }
- #ifdef FINSH_USING_AUTH
- /**
- * set a new password for finsh
- *
- * @param password new password
- *
- * @return result, RT_EOK on OK, -RT_ERROR on the new password length is less than
- * FINSH_PASSWORD_MIN or greater than FINSH_PASSWORD_MAX
- */
- rt_err_t finsh_set_password(const char *password)
- {
- rt_base_t level;
- rt_size_t pw_len = rt_strlen(password);
- if (pw_len < FINSH_PASSWORD_MIN || pw_len > FINSH_PASSWORD_MAX)
- return -RT_ERROR;
- level = rt_hw_interrupt_disable();
- rt_strncpy(shell->password, password, FINSH_PASSWORD_MAX);
- rt_hw_interrupt_enable(level);
- return RT_EOK;
- }
- /**
- * get the finsh password
- *
- * @return password
- */
- const char *finsh_get_password(void)
- {
- return shell->password;
- }
- static void finsh_wait_auth(void)
- {
- int ch;
- rt_bool_t input_finish = RT_FALSE;
- char password[FINSH_PASSWORD_MAX] = { 0 };
- rt_size_t cur_pos = 0;
- /* password not set */
- if (rt_strlen(finsh_get_password()) == 0) return;
- while (1)
- {
- rt_kprintf("Password for login: ");
- while (!input_finish)
- {
- while (1)
- {
- /* read one character from device */
- ch = (int)finsh_getchar();
- if (ch < 0)
- {
- continue;
- }
- if (ch >= ' ' && ch <= '~' && cur_pos < FINSH_PASSWORD_MAX)
- {
- /* change the printable characters to '*' */
- rt_kprintf("*");
- password[cur_pos++] = ch;
- }
- else if (ch == '\b' && cur_pos > 0)
- {
- /* backspace */
- cur_pos--;
- password[cur_pos] = '\0';
- rt_kprintf("\b \b");
- }
- else if (ch == '\r' || ch == '\n')
- {
- rt_kprintf("\n");
- input_finish = RT_TRUE;
- break;
- }
- }
- }
- if (!rt_strncmp(shell->password, password, FINSH_PASSWORD_MAX)) return;
- else
- {
- /* authentication failed, delay 2S for retry */
- rt_thread_delay(2 * RT_TICK_PER_SECOND);
- rt_kprintf("Sorry, try again.\n");
- cur_pos = 0;
- input_finish = RT_FALSE;
- rt_memset(password, '\0', FINSH_PASSWORD_MAX);
- }
- }
- }
- #endif /* FINSH_USING_AUTH */
- static void shell_auto_complete(char *prefix)
- {
- rt_kprintf("\n");
- msh_auto_complete(prefix);
- #ifdef FINSH_USING_OPTION_COMPLETION
- msh_opt_auto_complete(prefix);
- #endif
- rt_kprintf("%s%s", FINSH_PROMPT, prefix);
- }
- #ifdef FINSH_USING_HISTORY
- static rt_bool_t shell_handle_history(struct finsh_shell *shell)
- {
- #if defined(_WIN32)
- int i;
- rt_kprintf("\r");
- for (i = 0; i <= 60; i++)
- putchar(' ');
- rt_kprintf("\r");
- #else
- rt_kprintf("\033[2K\r");
- #endif
- rt_kprintf("%s%s", FINSH_PROMPT, shell->line);
- return RT_FALSE;
- }
- static void shell_push_history(struct finsh_shell *shell)
- {
- if (shell->line_position != 0)
- {
- /* push history */
- if (shell->history_count >= FINSH_HISTORY_LINES)
- {
- /* if current cmd is same as last cmd, don't push */
- if (memcmp(&shell->cmd_history[FINSH_HISTORY_LINES - 1], shell->line, FINSH_CMD_SIZE))
- {
- /* move history */
- int index;
- for (index = 0; index < FINSH_HISTORY_LINES - 1; index ++)
- {
- rt_memcpy(&shell->cmd_history[index][0],
- &shell->cmd_history[index + 1][0], FINSH_CMD_SIZE);
- }
- rt_memset(&shell->cmd_history[index][0], 0, FINSH_CMD_SIZE);
- rt_memcpy(&shell->cmd_history[index][0], shell->line, shell->line_position);
- /* it's the maximum history */
- shell->history_count = FINSH_HISTORY_LINES;
- }
- }
- else
- {
- /* if current cmd is same as last cmd, don't push */
- if (shell->history_count == 0 || memcmp(&shell->cmd_history[shell->history_count - 1], shell->line, FINSH_CMD_SIZE))
- {
- shell->current_history = shell->history_count;
- rt_memset(&shell->cmd_history[shell->history_count][0], 0, FINSH_CMD_SIZE);
- rt_memcpy(&shell->cmd_history[shell->history_count][0], shell->line, shell->line_position);
- /* increase count and set current history position */
- shell->history_count ++;
- }
- }
- }
- shell->current_history = shell->history_count;
- }
- #endif
- #if defined(FINSH_USING_WORD_OPERATION)
- static int find_prev_word_start(const char *line, int curpos)
- {
- if (curpos <= 0) return 0;
- /* Skip whitespace */
- while (--curpos > 0 && (line[curpos] == ' ' || line[curpos] == '\t'));
- /* Find word start */
- while (curpos > 0 && !(line[curpos] == ' ' || line[curpos] == '\t'))
- curpos--;
- return (curpos <= 0) ? 0 : curpos + 1;
- }
- static int find_next_word_end(const char *line, int curpos, int max)
- {
- if (curpos >= max) return max;
- /* Skip to next word */
- while (curpos < max && (line[curpos] == ' ' || line[curpos] == '\t'))
- curpos++;
- /* Find word end */
- while (curpos < max && !(line[curpos] == ' ' || line[curpos] == '\t'))
- curpos++;
- return curpos;
- }
- #endif /* defined(FINSH_USING_WORD_OPERATION) */
- #ifdef RT_USING_HOOK
- static void (*_finsh_thread_entry_hook)(void);
- /**
- * @ingroup group_finsh
- *
- * @brief This function set a hook function at the entry of finsh thread
- *
- * @param hook the function point to be called
- */
- void finsh_thread_entry_sethook(void (*hook)(void))
- {
- _finsh_thread_entry_hook = hook;
- }
- #endif /* RT_USING_HOOK */
- static void finsh_thread_entry(void *parameter)
- {
- int ch;
- RT_OBJECT_HOOK_CALL(_finsh_thread_entry_hook, ());
- /* normal is echo mode */
- #ifndef FINSH_ECHO_DISABLE_DEFAULT
- shell->echo_mode = 1;
- #else
- shell->echo_mode = 0;
- #endif
- #if !defined(RT_USING_POSIX_STDIO) && defined(RT_USING_DEVICE)
- /* set console device as shell device */
- if (shell->device == RT_NULL)
- {
- rt_device_t console = rt_console_get_device();
- if (console)
- {
- finsh_set_device(console->parent.name);
- }
- }
- #endif /* !defined(RT_USING_POSIX_STDIO) && defined(RT_USING_DEVICE) */
- #ifdef FINSH_USING_AUTH
- /* set the default password when the password isn't setting */
- if (rt_strlen(finsh_get_password()) == 0)
- {
- if (finsh_set_password(FINSH_DEFAULT_PASSWORD) != RT_EOK)
- {
- rt_kprintf("Finsh password set failed.\n");
- }
- }
- /* waiting authenticate success */
- finsh_wait_auth();
- #endif
- rt_kprintf(FINSH_PROMPT);
- while (1)
- {
- ch = (int)finsh_getchar();
- if (ch < 0)
- {
- continue;
- }
- /*
- * handle control key
- * up key : 0x1b 0x5b 0x41
- * down key: 0x1b 0x5b 0x42
- * right key:0x1b 0x5b 0x43
- * left key: 0x1b 0x5b 0x44
- * home : 0x1b 0x5b 0x31 0x7E
- * insert : 0x1b 0x5b 0x32 0x7E
- * del : 0x1b 0x5b 0x33 0x7E
- * end : 0x1b 0x5b 0x34 0x7E
- */
- if (ch == 0x1b)
- {
- shell->stat = WAIT_SPEC_KEY;
- continue;
- }
- else if (shell->stat == WAIT_SPEC_KEY)
- {
- if (ch == 0x5b || ch == 0x41 || ch == 0x42 || ch == 0x43 || ch == 0x44)
- {
- shell->stat = WAIT_FUNC_KEY;
- continue;
- }
- shell->stat = WAIT_NORMAL;
- }
- else if (shell->stat == WAIT_FUNC_KEY)
- {
- shell->stat = WAIT_NORMAL;
- if (ch == 0x41) /* up key */
- {
- #ifdef FINSH_USING_HISTORY
- /* prev history */
- if (shell->current_history > 0)
- shell->current_history --;
- else
- {
- shell->current_history = 0;
- continue;
- }
- /* copy the history command */
- rt_memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
- FINSH_CMD_SIZE);
- shell->line_curpos = shell->line_position = (rt_uint16_t)strlen(shell->line);
- shell_handle_history(shell);
- #endif
- continue;
- }
- else if (ch == 0x42) /* down key */
- {
- #ifdef FINSH_USING_HISTORY
- /* next history */
- if (shell->current_history < shell->history_count - 1)
- shell->current_history ++;
- else
- {
- /* set to the end of history */
- if (shell->history_count != 0)
- shell->current_history = shell->history_count - 1;
- else
- continue;
- }
- rt_memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
- FINSH_CMD_SIZE);
- shell->line_curpos = shell->line_position = (rt_uint16_t)strlen(shell->line);
- shell_handle_history(shell);
- #endif
- continue;
- }
- else if (ch == 0x44) /* left key */
- {
- if (shell->line_curpos)
- {
- rt_kprintf("\b");
- shell->line_curpos --;
- }
- continue;
- }
- else if (ch == 0x43) /* right key */
- {
- if (shell->line_curpos < shell->line_position)
- {
- rt_kprintf("%c", shell->line[shell->line_curpos]);
- shell->line_curpos ++;
- }
- continue;
- }
- #if defined(FINSH_USING_WORD_OPERATION)
- /* Add Ctrl+Left/Right handling */
- else if (ch == '1')
- {
- /* Read modifier sequence [1;5D/C] */
- int next_ch = finsh_getchar();
- if (next_ch == ';')
- {
- next_ch = finsh_getchar();
- if (next_ch == '5')
- {
- next_ch = finsh_getchar();
- if (next_ch == 'D') /* Ctrl+Left */
- {
- int new_pos = find_prev_word_start(shell->line, shell->line_curpos);
- if (new_pos != shell->line_curpos)
- {
- rt_kprintf("\033[%dD", shell->line_curpos - new_pos);
- shell->line_curpos = new_pos;
- }
- continue;
- }
- else if (next_ch == 'C') /* Ctrl+Right */
- {
- int new_pos = find_next_word_end(shell->line, shell->line_curpos, shell->line_position);
- if (new_pos != shell->line_curpos)
- {
- rt_kprintf("\033[%dC", new_pos - shell->line_curpos);
- shell->line_curpos = new_pos;
- }
- continue;
- }
- }
- }
- }
- #endif /*defined(FINSH_USING_WORD_OPERATION) */
- #if defined(FINSH_USING_FUNC_EXT)
- else if (ch >= 0x31 && ch <= 0x34) /* home(0x31), insert(0x32), del(0x33), end(0x34) */
- {
- shell->stat = WAIT_EXT_KEY;
- shell->line[shell->line_position + 1] = ch; /* store the key code */
- continue;
- }
- }
- else if (shell->stat == WAIT_EXT_KEY)
- {
- shell->stat = WAIT_NORMAL;
- if (ch == 0x7E) /* extended key terminator */
- {
- rt_uint8_t key_code = shell->line[shell->line_position + 1];
- if (key_code == 0x31) /* home key */
- {
- /* move cursor to beginning of line */
- while (shell->line_curpos > 0)
- {
- rt_kprintf("\b");
- shell->line_curpos--;
- }
- }
- else if (key_code == 0x32) /* insert key */
- {
- /* toggle insert mode */
- shell->overwrite_mode = !shell->overwrite_mode;
- }
- else if (key_code == 0x33) /* del key */
- {
- /* delete character at current cursor position */
- if (shell->line_curpos < shell->line_position)
- {
- int i;
- shell->line_position--;
- rt_memmove(&shell->line[shell->line_curpos],
- &shell->line[shell->line_curpos + 1],
- shell->line_position - shell->line_curpos);
- shell->line[shell->line_position] = 0;
- rt_kprintf("%s ", &shell->line[shell->line_curpos]);
- /* move cursor back to original position */
- for (i = shell->line_curpos; i <= shell->line_position; i++)
- rt_kprintf("\b");
- }
- }
- else if (key_code == 0x34) /* end key */
- {
- /* move cursor to end of line */
- while (shell->line_curpos < shell->line_position)
- {
- rt_kprintf("%c", shell->line[shell->line_curpos]);
- shell->line_curpos++;
- }
- }
- continue;
- }
- #endif /*defined(FINSH_USING_FUNC_EXT) */
- }
- /* received null or error */
- if (ch == '\0' || ch == 0xFF) continue;
- /* handle tab key */
- else if (ch == '\t')
- {
- int i;
- /* move the cursor to the beginning of line */
- for (i = 0; i < shell->line_curpos; i++)
- rt_kprintf("\b");
- /* auto complete */
- shell_auto_complete(&shell->line[0]);
- /* re-calculate position */
- shell->line_curpos = shell->line_position = (rt_uint16_t)strlen(shell->line);
- continue;
- }
- /* handle backspace key */
- else if (ch == 0x7f || ch == 0x08)
- {
- /* note that shell->line_curpos >= 0 */
- if (shell->line_curpos == 0)
- continue;
- shell->line_position--;
- shell->line_curpos--;
- if (shell->line_position > shell->line_curpos)
- {
- int i;
- rt_memmove(&shell->line[shell->line_curpos],
- &shell->line[shell->line_curpos + 1],
- shell->line_position - shell->line_curpos);
- shell->line[shell->line_position] = 0;
- rt_kprintf("\b%s \b", &shell->line[shell->line_curpos]);
- /* move the cursor to the origin position */
- for (i = shell->line_curpos; i <= shell->line_position; i++)
- rt_kprintf("\b");
- }
- else
- {
- rt_kprintf("\b \b");
- shell->line[shell->line_position] = 0;
- }
- continue;
- }
- #if defined(FINSH_USING_WORD_OPERATION)
- /* Add Ctrl+Backspace handling */
- else if (ch == 0x17) /* Ctrl+Backspace (typically ^W) */
- {
- if (shell->line_curpos == 0) continue;
- int start = find_prev_word_start(shell->line, shell->line_curpos);
- int del_count = shell->line_curpos - start;
- int new_len = shell->line_position - del_count;
- /* Delete characters and properly add RT_NULL termination */
- rt_memmove(&shell->line[start],
- &shell->line[start + del_count],
- new_len - start + 1);
- /* Clear residual data */
- rt_memset(&shell->line[new_len], 0, shell->line_position - new_len);
- /* Update positions */
- shell->line_position = new_len;
- shell->line_curpos = start;
- /* Redraw the affected line section */
- rt_kprintf("\033[%dD", del_count);
- /* Rewrite the remaining content */
- rt_kprintf("%.*s", shell->line_position - start, &shell->line[start]);
- /* Clear trailing artifacts */
- rt_kprintf("\033[K");
- if (shell->line_position > start)
- {
- /* Reset cursor */
- rt_kprintf("\033[%dD", shell->line_position - start);
- }
- continue;
- }
- #endif /*defined(FINSH_USING_WORD_OPERATION) */
- /* handle end of line, break */
- if (ch == '\r' || ch == '\n')
- {
- #ifdef FINSH_USING_HISTORY
- shell_push_history(shell);
- #endif
- if (shell->echo_mode)
- rt_kprintf("\n");
- msh_exec(shell->line, shell->line_position);
- rt_kprintf(FINSH_PROMPT);
- rt_memset(shell->line, 0, sizeof(shell->line));
- shell->line_curpos = shell->line_position = 0;
- continue;
- }
- /* it's a large line, discard it */
- if (shell->line_position >= FINSH_CMD_SIZE)
- shell->line_position = 0;
- /* normal character */
- if (shell->line_curpos < shell->line_position)
- {
- int i;
- #if defined(FINSH_USING_FUNC_EXT)
- if (shell->overwrite_mode) /* overwrite mode */
- {
- /* directly overwrite the character */
- shell->line[shell->line_curpos] = ch;
- if (shell->echo_mode)
- rt_kprintf("%c", ch);
- shell->line_curpos++;
- }
- else /* insert mode */
- #endif /*defined(FINSH_USING_FUNC_EXT)*/
- {
- shell->line_position++;
- /* move existing characters to the right */
- rt_memmove(&shell->line[shell->line_curpos + 1],
- &shell->line[shell->line_curpos],
- shell->line_position - shell->line_curpos);
- shell->line[shell->line_curpos] = ch;
- if (shell->echo_mode)
- {
- rt_kprintf("%s", &shell->line[shell->line_curpos]);
- /* move cursor back to correct position */
- for (i = shell->line_curpos + 1; i < shell->line_position; i++)
- rt_kprintf("\b");
- }
- shell->line_curpos++;
- }
- }
- else
- {
- /* append character at end of line */
- shell->line[shell->line_position] = ch;
- if (shell->echo_mode)
- rt_kprintf("%c", ch);
- shell->line_position++;
- shell->line_curpos++;
- }
- ch = 0;
- if (shell->line_position >= FINSH_CMD_SIZE)
- {
- /* clear command line */
- shell->line_position = 0;
- shell->line_curpos = 0;
- }
- } /* end of device read */
- }
- static void finsh_system_function_init(const void *begin, const void *end)
- {
- _syscall_table_begin = (struct finsh_syscall *) begin;
- _syscall_table_end = (struct finsh_syscall *) end;
- }
- #if defined(__ICCARM__) || defined(__ICCRX__) /* for IAR compiler */
- #ifdef FINSH_USING_SYMTAB
- #pragma section="FSymTab"
- #endif
- #elif defined(__ADSPBLACKFIN__) /* for VisaulDSP++ Compiler*/
- #ifdef FINSH_USING_SYMTAB
- extern "asm" int __fsymtab_start;
- extern "asm" int __fsymtab_end;
- #endif
- #elif defined(_MSC_VER)
- #pragma section("FSymTab$a", read)
- const char __fsym_begin_name[] = "__start";
- const char __fsym_begin_desc[] = "begin of finsh";
- __declspec(allocate("FSymTab$a")) const struct finsh_syscall __fsym_begin =
- {
- __fsym_begin_name,
- __fsym_begin_desc,
- NULL
- };
- #pragma section("FSymTab$z", read)
- const char __fsym_end_name[] = "__end";
- const char __fsym_end_desc[] = "end of finsh";
- __declspec(allocate("FSymTab$z")) const struct finsh_syscall __fsym_end =
- {
- __fsym_end_name,
- __fsym_end_desc,
- NULL
- };
- #endif
- /*
- * @ingroup group_finsh
- *
- * This function will initialize finsh shell
- */
- int finsh_system_init(void)
- {
- rt_err_t result = RT_EOK;
- rt_thread_t tid;
- #ifdef FINSH_USING_SYMTAB
- #ifdef __ARMCC_VERSION /* ARM C Compiler */
- extern const int FSymTab$$Base;
- extern const int FSymTab$$Limit;
- finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);
- #elif defined (__ICCARM__) || defined(__ICCRX__) /* for IAR Compiler */
- finsh_system_function_init(__section_begin("FSymTab"),
- __section_end("FSymTab"));
- #elif defined (__GNUC__) || defined(__TI_COMPILER_VERSION__) || defined(__TASKING__)
- /* GNU GCC Compiler and TI CCS */
- extern const int __fsymtab_start;
- extern const int __fsymtab_end;
- finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
- #elif defined(__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */
- finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
- #elif defined(_MSC_VER)
- unsigned int *ptr_begin, *ptr_end;
- if (shell)
- {
- rt_kprintf("finsh shell already init.\n");
- return RT_EOK;
- }
- ptr_begin = (unsigned int *)&__fsym_begin;
- ptr_begin += (sizeof(struct finsh_syscall) / sizeof(unsigned int));
- while (*ptr_begin == 0) ptr_begin ++;
- ptr_end = (unsigned int *) &__fsym_end;
- ptr_end --;
- while (*ptr_end == 0) ptr_end --;
- finsh_system_function_init(ptr_begin, ptr_end);
- #endif
- #endif
- #ifdef RT_USING_HEAP
- /* create or set shell structure */
- shell = (struct finsh_shell *)rt_calloc(1, sizeof(struct finsh_shell));
- if (shell == RT_NULL)
- {
- rt_kprintf("no memory for shell\n");
- return -1;
- }
- tid = rt_thread_create(FINSH_THREAD_NAME,
- finsh_thread_entry, RT_NULL,
- FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10);
- #else
- shell = &_shell;
- tid = &finsh_thread;
- result = rt_thread_init(&finsh_thread,
- FINSH_THREAD_NAME,
- finsh_thread_entry, RT_NULL,
- &finsh_thread_stack[0], sizeof(finsh_thread_stack),
- FINSH_THREAD_PRIORITY, 10);
- #endif /* RT_USING_HEAP */
- rt_sem_init(&(shell->rx_sem), "shrx", 0, 0);
- finsh_set_prompt_mode(1);
- if (tid != NULL && result == RT_EOK)
- rt_thread_startup(tid);
- return 0;
- }
- INIT_APP_EXPORT(finsh_system_init);
- #endif /* RT_USING_FINSH */
|