📄 tinysh.c
字号:
/* * tinysh.c * * Minimal portable shell * * Copyright (C) 2001 Michel Gutierrez <mig@nerim.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "tinysh.h"#ifndef BUFFER_SIZE#define BUFFER_SIZE 256#endif#ifndef HISTORY_DEPTH#define HISTORY_DEPTH 16#endif#ifndef MAX_ARGS#define MAX_ARGS 16#endif#ifndef PROMPT_SIZE#define PROMPT_SIZE 16#endif#ifndef TOPCHAR#define TOPCHAR '/'#endiftypedef unsigned char uchar;/* redefine some useful and maybe missing utilities to avoid conflicts */#define strlen tinysh_strlen#define puts tinysh_puts#define putchar tinysh_char_outstatic void help_fnt(int argc, char **argv);static tinysh_cmd_t help_cmd={ 0,"help","display help","<cr>",help_fnt,0,0,0 };static uchar input_buffers[HISTORY_DEPTH][BUFFER_SIZE+1]={0};static uchar trash_buffer[BUFFER_SIZE+1]={0};static int cur_buf_index=0;static uchar context_buffer[BUFFER_SIZE+1]={0};static int cur_context=0;static int cur_index=0;static int echo=1;static char prompt[PROMPT_SIZE+1]="$ ";static tinysh_cmd_t *root_cmd=&help_cmd;static tinysh_cmd_t *cur_cmd_ctx=0;static void *tinysh_arg=0;/* few useful utilities that may be missing */static int strlen(uchar *s){ int i; for(i=0;*s;s++,i++); return i;}static void puts(char *s){ while(*s) putchar(*s++);}/* callback for help function */static void help_fnt(int argc, char **argv){ puts("? display help on given or available commands\n"); puts("<TAB> auto-completion\n"); puts("<cr> execute command line\n"); puts("CTRL-P recall previous input line\n"); puts("CTRL-N recall next input line\n"); puts("<any> treat as input character\n");}/* */enum { NULLMATCH,FULLMATCH,PARTMATCH,UNMATCH,MATCH,AMBIG };/* verify if the non-spaced part of s2 is included at the begining * of s1. * return FULLMATCH if s2 equal to s1, PARTMATCH if s1 starts with s2 * but there are remaining chars in s1, UNMATCH if s1 does not start with * s2 */int strstart(uchar *s1, uchar *s2){ while(*s1 && *s1==*s2) { s1++; s2++; } if(*s2==' ' || *s2==0) { if(*s1==0) return FULLMATCH; /* full match */ else return PARTMATCH; /* partial match */ } else return UNMATCH; /* no match */}/* * check commands at given level with input string. * _cmd: point to first command at this level, return matched cmd * _str: point to current unprocessed input, return next unprocessed */static int parse_command(tinysh_cmd_t **_cmd, uchar **_str){ uchar *str=*_str; tinysh_cmd_t *cmd; int matched_len=0; tinysh_cmd_t *matched_cmd=0; /* first eliminate first blanks */ while(*str==' ') str++; if(!*str) { *_str=str; return NULLMATCH; /* end of input */ } /* first pass: count matches */ for(cmd=*_cmd;cmd;cmd=cmd->next) { int ret=strstart(cmd->name,str); if(ret==FULLMATCH) { /* found full match */ while(*str && *str!=' ') str++; while(*str==' ') str++; *_str=str; *_cmd=cmd; return MATCH; } else if (ret==PARTMATCH) { if(matched_cmd) { *_cmd=matched_cmd; return AMBIG; } else { matched_cmd=cmd; } } else /* UNMATCH */ { } } if(matched_cmd) { while(*str && *str!=' ') str++; while(*str==' ') str++; *_cmd=matched_cmd; *_str=str; return MATCH; } else return UNMATCH;}/* create a context from current input line */static void do_context(tinysh_cmd_t *cmd, uchar *str){ while(*str) context_buffer[cur_context++]=*str++; context_buffer[cur_context]=0; cur_cmd_ctx=cmd;}/* execute the given command by calling callback with appropriate * arguments */static void exec_command(tinysh_cmd_t *cmd, uchar *str){ char *argv[MAX_ARGS]; int argc=0; int i;/* copy command line to preserve it for history */ for(i=0;i<BUFFER_SIZE;i++) trash_buffer[i]=str[i]; str=trash_buffer; /* cut into arguments */ argv[argc++]=cmd->name; while(*str && argc<MAX_ARGS) { while(*str==' ') str++; if(*str==0) break; argv[argc++]=str; while(*str!=' ' && *str) str++; if(!*str) break; *str++=0; }/* call command function if present */ if(cmd->function) { tinysh_arg=cmd->arg; cmd->function(argc,&argv[0]); }}/* try to execute the current command line */static int exec_command_line(tinysh_cmd_t *cmd, uchar *_str){ uchar *str=_str; while(1) { int ret; ret=parse_command(&cmd,&str); if(ret==MATCH) /* found unique match */ { if(cmd) { if(!cmd->child) /* no sub-command, execute */ { exec_command(cmd,str); return 0; } else { if(*str==0) /* no more input, this is a context */ { do_context(cmd,_str); return 0; } else /* process next command word */ { cmd=cmd->child; } } } else /* cmd == 0 */ { return 0; } } else if(ret==AMBIG) { puts("ambiguity: "); puts(str); putchar('\n'); return 0; } else if(ret==UNMATCH) /* UNMATCH */ { puts("no match: "); puts(str); putchar('\n'); return 0; } else /* NULLMATCH */ return 0; }}/* display help for list of commands */static void display_child_help(tinysh_cmd_t *cmd){ tinysh_cmd_t *cm; int len=0; putchar('\n'); for(cm=cmd;cm;cm=cm->next) if(len<strlen(cm->name)) len=strlen(cm->name); for(cm=cmd;cm;cm=cm->next) if(cm->help) { int i; puts(cm->name); for(i=strlen(cm->name);i<len+2;i++) putchar(' '); puts(cm->help); putchar('\n'); }}/* try to display help for current comand line */static int help_command_line(tinysh_cmd_t *cmd, uchar *_str){ uchar *str=_str; while(1) { int ret; ret=parse_command(&cmd,&str); if(ret==MATCH && *str==0) /* found unique match or empty line */ { tinysh_cmd_t *cm; int len=0; if(cmd->child) /* display sub-commands help */ { display_child_help(cmd->child); return 0; } else /* no sub-command, show single help */ { if(*(str-1)!=' ') putchar(' '); if(cmd->usage) puts(cmd->usage); puts(": "); if(cmd->help) puts(cmd->help); else puts("no help available"); putchar('\n'); } return 0; } else if(ret==MATCH && *str) { /* continue processing the line */ cmd=cmd->child; } else if(ret==AMBIG) { puts("\nambiguity: "); puts(str);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -