diff options
-rw-r--r-- | CmdLine/ClearScreen.swift | 8 | ||||
-rw-r--r-- | CmdLine/CmdTool.swift | 62 | ||||
-rw-r--r-- | CmdLine/main.swift | 76 | ||||
-rw-r--r-- | LibTerm/Term.swift | 280 | ||||
-rw-r--r-- | LibTerm/TermIO.swift | 38 | ||||
-rw-r--r-- | cmd/cmd-Bridging-Header.h | 6 | ||||
-rw-r--r-- | cmd/cmd.c | 721 | ||||
-rw-r--r-- | cmd/cmd.h | 174 | ||||
-rw-r--r-- | cmd/cmd.swift | 78 | ||||
-rw-r--r-- | cmd/cmd_parse.c | 328 | ||||
-rw-r--r-- | cmd/cmd_parse.h | 8 | ||||
-rw-r--r-- | cmd/debug.h | 69 | ||||
-rw-r--r-- | cmd/queue.h | 533 |
13 files changed, 2381 insertions, 0 deletions
diff --git a/CmdLine/ClearScreen.swift b/CmdLine/ClearScreen.swift new file mode 100644 index 0000000..bcb15e2 --- /dev/null +++ b/CmdLine/ClearScreen.swift @@ -0,0 +1,8 @@ +// +// ClearScreen.swift +// CmdLine +// +// Created by Jacky Jack on 31/05/2023. +// + +import Foundation diff --git a/CmdLine/CmdTool.swift b/CmdLine/CmdTool.swift new file mode 100644 index 0000000..41d35d8 --- /dev/null +++ b/CmdLine/CmdTool.swift @@ -0,0 +1,62 @@ +// +// CmdTool.swift +// CmdLine +// +// Created by Jacky Jack on 13/06/2023. +// + +import Foundation +import cmd + + +public class CmdTool { + init() { + + } +} + + + +public class CmdTableEntry { + var command:String + var callback:((Array<cmd.CmdToken>?) -> Void)? + //var helpDelegate:CmdTableHelp? + //var preconditionDelegate:CmdTablePrecondition? + //var autocompleteDelegate:CmdTableAutocomplete? + + init() { + command = "" + } +} + +public class CmdTable { + var table:Array<CmdTableEntry> = [] + + init() { + + } + + func addEntry(_ cmd: CmdTableEntry) { + table.append(cmd) + } + + func listCommands() { + for command in table { + print("CMD: \(command.command) callback:\(command.callback)") + } + } + + func execute(_ args: Array<CmdToken>) { + let cmd0 = args[0] + var params0 = Array<CmdToken>() + if args.count > 1 { + params0 = Array<CmdToken>(args[1..<args.count]) + } + for cmd in self.table { + if cmd.command == cmd0.val { + print("Found command executing ...") + cmd.callback!(params0) + } + } + } +} diff --git a/CmdLine/main.swift b/CmdLine/main.swift new file mode 100644 index 0000000..3876d05 --- /dev/null +++ b/CmdLine/main.swift @@ -0,0 +1,76 @@ +// +// main.swift +// CmdLine +// +// Created by Jacky Jack on 24/02/2023. +// + +import Foundation +import Darwin +//import cmd +import cmd + +print("Test CMD") +var tok:cmd_tok_t = cmd_tok_t() +var c="asd 123" +//cmd.(&tok, c, c.count) +//cmdparse_cmd(<#T##tl: UnsafeMutablePointer<cmd_tok_t>!##UnsafeMutablePointer<cmd_tok_t>!#>, <#T##str: UnsafePointer<CChar>!##UnsafePointer<CChar>!#>, <#T##str_size: Int##Int#>) +//var p = cmd.Par() +var p = cmd.CmdParser() +//p.parse() +let r = p.parse("123 0x0 0b1 \"this is me\" asd123 a@1 1.20 admin@main.lv") +let r1 = p.parse("ls") +let r2 = p.parse("one") +let r3 = p.parse("ls 123") +let r4 = p.parse("args 0x0 0b1 \"this is me\" asd123 a@1 1.20 admin@main.lv") +for e in 0..<r.count { + print("tok \(r[e].type) - \(r[e].val)") +} + +let cmd_ls = CmdTableEntry() +cmd_ls.command = "ls" +func call_ls(_ args:Array<CmdToken>?) { + print("List nothing") +} +cmd_ls.callback = call_ls + +let cmd_one = CmdTableEntry() +var cmd_one_i = 0 +cmd_one.command = "one" +func call_cmd(_ args:Array<CmdToken>?) { + print("+1 == \(cmd_one_i)") + cmd_one_i += 1 +} +cmd_one.callback = call_cmd + +let cmd_show_args = CmdTableEntry() +func call_show_args(_ _args:Array<CmdToken>?) { + if let args = _args { + for arg in args { + print("\(arg.val) ") + } + } +} +cmd_show_args.command = "args" +cmd_show_args.callback = call_show_args + +let commands = CmdTable() +commands.addEntry(cmd_ls) +commands.addEntry(cmd_one) +commands.addEntry(cmd_show_args) + + +commands.listCommands() + + +commands.execute(r) +commands.execute(r1) +commands.execute(r2) +commands.execute(r2) +commands.execute(r2) +commands.execute(r2) +commands.execute(r3) +commands.execute(r4) +print("Test CMD") + + diff --git a/LibTerm/Term.swift b/LibTerm/Term.swift new file mode 100644 index 0000000..9ca17dc --- /dev/null +++ b/LibTerm/Term.swift @@ -0,0 +1,280 @@ +// +// Term.swift +// CmdLine +// +// Created by Jacky Jack on 25/02/2023. +// + +import Foundation +import Darwin + +class Term { + let esc = "\u{001B}" + + var ifd:Int32 + var ofd:Int32 + var orig_i:termios + var orig_o:termios + var raw_i:termios + var raw_o:termios + + init() { + + + + self.ifd = Darwin.STDIN_FILENO + self.ofd = Darwin.STDOUT_FILENO + + self.orig_i = termios() + self.orig_o = termios() + self.raw_i = termios() + self.raw_o = termios() + + //let p_i<> = UnsafeMutablePointer(self.orig_i) + if (-1 == tcgetattr(self.ifd, UnsafeMutablePointer(&self.orig_i))) { + print("tcgetattr error") + return + } + self.raw_i = self.orig_i + + if ( -1 == tcgetattr(self.ofd, UnsafeMutablePointer(&self.orig_o))) { + print("tcgetattr error") + return + } + self.raw_o = self.orig_o + + if (isatty(STDIN_FILENO) == 0) { + print("isatty failed") + return + } + + } + + func setSpeed(speed: speed_t) { + var ret:Int32=0 + let raw_out = UnsafeMutablePointer(&self.raw_o) + ret = cfsetospeed(raw_out, speed) + tcsetattr(self.ofd, TCSANOW, raw_out) + + let raw_in = UnsafeMutablePointer(&self.raw_o) + ret = cfsetispeed(raw_in, speed) + tcsetattr(self.ifd, TCSANOW, raw_in) + } + + func getMaxCol() -> Int { + let orig_c = getC() + //go to right marging and get position + if (write(ofd, "\u{001B}[999C", 6) != 6) { + return -1 + } + //get the position + let cur_c = getC() + if (cur_c == -1) { + return -1 + } + + //restore previouse position + let restore_position = "\u{001B}[\(cur_c-orig_c)D" + write(ofd, restore_position, restore_position.count) + + return cur_c + } + + func getMaxRow() -> Int { + let orig_r = getR() + //go to right marging and get position + if (write(ofd, "\u{001B}[999B", 6) != 6) { + return -1 + } + //get the position + let cur_r = getR() + if (cur_r == -1) { + return -1 + } + + //restore previouse position + let restore_position = "\u{001B}[\(cur_r-orig_r)A" + write(ofd, restore_position, restore_position.count) + + return cur_r + } + + func getR() -> Int { + var buf = [UInt8](repeating: 0, count: 32) + + if (write(ofd, "\u{001B}[6n", 4) != 4) { + print("Cant push escape codes for column") + } + var i=0; + while (i<buf.capacity-1) { + if (read(ifd, &buf[i], 1) == -1) { + break + } + //if eq R + if (buf[i] == 0x52) { + break + } + i+=1 + } + //maybe not most optimal way + while (buf.count-1 > i) { + buf.removeLast() + } + if (buf[0] != 0x1b) && (buf[1] != 0x5b) { + return -1 + } + + var bufs:String = "" + for i in 0..<buf.count { + bufs += String(Character(UnicodeScalar(buf[i]))) + } + let sindex = bufs.index(bufs.startIndex, offsetBy: 2) + let split = bufs.suffix(from:sindex).components(separatedBy: ";") + let s1 = split[0] // row + let s2 = split[1] //column + + return Int(s1)! + } + + func getC() -> Int { + var buf = [UInt8](repeating: 0, count: 32) + if (write(ofd, "\u{001B}[6n", 4) != 4) { + //print("Cant push escape codes for column") + } + var i=0; + while (i<buf.capacity-1) { + if (read(ifd, &buf[i], 1) == -1) { + break + } + //if eq R + if (buf[i] == 0x52) { + break + } + i+=1 + } + //maybe not most optimal way + var j=0 + while (buf.count > i) { + buf.removeLast() + j+=1 + } + if (buf[0] != 0x1b) && (buf[1] != 0x5b) { + return -1 + } + + var bufs:String = "" + for i in 0..<buf.count { + bufs += String(Character(UnicodeScalar(buf[i]))) + } + let sindex = bufs.index(bufs.startIndex, offsetBy: 2) + let split = bufs.suffix(from:sindex).components(separatedBy: ";") + let s1 = split[0] // row + let s2 = split[1] //column + + return Int(s2)! + } + + func setC(_ pos_c: Int) { + let cur_r = getR() + let escape_string = "\u{001B}[\(cur_r);\(pos_c)H" + write(ofd, escape_string, escape_string.count) + } + + func setR(_ pos_r: Int) { + let cur_c = getC() + let escape_string = "\u{001B}[\(pos_r);\(cur_c)H" + write(ofd, escape_string, escape_string.count) + } + + func setCR(_ pos_c:Int, _ pos_r: Int) { + let escape_string = "\u{001B}[\(pos_c);\(pos_r)H" + write(ofd, escape_string, escape_string.count) + } + + func clearScreen() { + //let escape = String(Unicode.Scalar(0x1b)!) + let s = "\u{001B}[H\u{001B}[2J" + //print(s.count) + let ret = write(self.ofd, s, 7); + //let ret = write(self.ofd, String("\u{001b}[2J"),4); + //print("\(esc)[2J".utf8) + } + + func setRawMode() { + if ( tcgetattr(self.ifd, UnsafeMutablePointer(&self.orig_i)) == -1) { + print("Cannot get terminal attribures") + return + } + + raw_i = orig_i + var c_iflag:Int32 = Int32(raw_i.c_iflag) + c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) + raw_i.c_iflag = UInt(c_iflag) + + var c_oflag:Int32 = Int32(raw_i.c_oflag) + c_oflag &= ~(OPOST) + raw_i.c_oflag = UInt(c_oflag) + + var c_cflag:Int32 = Int32(raw_i.c_cflag) + c_cflag |= (CS8) + raw_i.c_cflag = UInt(c_cflag) + + var c_lflag:Int32 = Int32(raw_i.c_lflag) + c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG) + raw_i.c_lflag = UInt(c_lflag) + //https://stackoverflow.com/questions/31465943/using-termios-in-swift + //raw_i.c_cc[VTIME] = 1 + //raw_i.c_cc[VMIN] = 0; + /*withUnsafeMutablePointer(to: &raw_i.c_cc) { (tuplePtr) -> Void in + tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: raw_i.c_cc)) { + $0[Int(VMIN)] = 1 + //$0[Int(VTIME)] = 0 + } + }*/ + //print("\(raw_i)") + //print("VMIN=\(VMIN)") + raw_i.c_cc.16 = 1 + //print("VTIME=\(VTIME)") + raw_i.c_cc.17 = 0 + let p:UnsafePointer<termios> = UnsafePointer(&self.raw_i) + if (tcsetattr(self.ifd, TCSAFLUSH, UnsafePointer(p)) == -1) { + print("Cannot set new terminal input attribures") + } + } + + func setConfigMode(c_iflag:Int32, c_oflag:Int32, c_cflag:Int32, c_lflag:Int32, vmin: UInt8, vtime: UInt8) { + if ( tcgetattr(self.ifd, UnsafeMutablePointer(&self.orig_i)) == -1) { + print("Cannot get terminal attribures") + return + } + + raw_i.c_iflag = UInt(c_iflag) + raw_i.c_oflag = UInt(c_oflag) + raw_i.c_cflag = UInt(c_cflag) + raw_i.c_lflag = UInt(c_lflag) + raw_i.c_cc.16 = vmin + raw_i.c_cc.17 = vtime + let p:UnsafePointer<termios> = UnsafePointer(&self.raw_i) + if (tcsetattr(self.ifd, TCSAFLUSH, UnsafePointer(p)) == -1) { + print("Cannot set new terminal input attribures") + } + } + + func modeRows() { + + } + + func modeColumns() { + + } + + func setOrigMode() { + if (tcsetattr(self.ifd, TCSAFLUSH, UnsafePointer(&self.orig_i)) == -1) { + print("Cannot set new terminal input attribures") + } + } + + func print(_ s: String) { + write(self.ofd, s, s.count) + } +} diff --git a/LibTerm/TermIO.swift b/LibTerm/TermIO.swift new file mode 100644 index 0000000..cbfb7a5 --- /dev/null +++ b/LibTerm/TermIO.swift @@ -0,0 +1,38 @@ +// +// TermIO.swift +// CmdLine +// +// Created by Jacky Jack on 07/06/2023. +// + +import Foundation + +class TermIO { + var term:Term + + init(term: Term) { + self.term = term + } + + func print(s: String) { + + } + + func getC() -> UInt8 { + var c:UInt8 = 0x0 + let fret = read(self.term.ifd, UnsafeMutableRawPointer(&c), 1); + if (fret == 1) { + return c; + } + return 0 + } + + func putC(_ c: UInt8) { + var buf = c + write(self.term.ofd, UnsafeRawPointer(&buf), 1) + } + + func readline(_ flag: Int) -> String { + return "<Empty>" + } +} diff --git a/cmd/cmd-Bridging-Header.h b/cmd/cmd-Bridging-Header.h new file mode 100644 index 0000000..89d4ec5 --- /dev/null +++ b/cmd/cmd-Bridging-Header.h @@ -0,0 +1,6 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#include "cmd_parse.h" +#include "cmd.h" diff --git a/cmd/cmd.c b/cmd/cmd.c new file mode 100644 index 0000000..f743a7f --- /dev/null +++ b/cmd/cmd.c @@ -0,0 +1,721 @@ +#include "cmd.h" +#include "cmd_parse.h" + +cmd_tok_t* cmd_tok_create( char *s, char *e, int sz, int type ) +{ + cmd_tok_t *ret = NULL; + + ret = malloc( sizeof(cmd_tok_t) ); + if ( ret == NULL ) + return ret; + + memset( ret, 0, sizeof(cmd_tok_t) ); + + ret->s = s; + ret->e = e; + ret->sz = sz; + ret->type = type; + ret->next = NULL; //no need, but sec programming says we need it + + return ret; +} + + +int cmd_tok_add( cmd_tok_t *tok, cmd_tok_t *next ) +{ + int ret = 0; + + if ( tok == NULL ) + { + return -1; + } + + if ( next == NULL ) + { + return -1; + } + + if ( tok->next != NULL ) + { + printf("next token allready set\n"); + return -1; + } + + tok->next = next; + + return ret; +} + + +int cmd_tok_print( cmd_tok_t *tok ) +{ + int ret = 0; + + printf("TOK %p\n",tok); + if (tok) + { + printf("S:%p E:%p SZ:%d \n", tok->s, tok->e, tok->sz); + printf("TYPE: "); + switch (tok->type) + { + case CMDT_NONE: + printf("NONE"); + break; + case CMDT_INT: + printf("INT"); + break; + case CMDT_HEX: + printf("HEX"); + break; + case CMDT_BIN: + printf("BIN"); + break; + case CMDT_STR: + printf("STR"); + break; + case CMDT_WORD: + printf("WORD"); + break; + case CMDT_SP: + printf("SP"); + break; + case CMDT_FLOAT: + printf("FLOAT"); + break; + default: + printf("UNKNOWN"); + } + printf("\n"); + printf("NEXT: %p\n", tok->next ); + } + + return ret; +} + + +void cmd_tok_destroy( cmd_tok_t *tok ) +{ + cmd_tok_t *t=NULL, *n=NULL; + + if (tok == NULL) + { + return; + } + + if ( tok->next == NULL ) + { + free( tok ); + return; + } + + t = tok; + n = t; + while ( n != NULL) + { + n = t->next; + t->next = NULL; + free(t); + t = n; + } +} + + +int cmd_tok_count( cmd_tok_t *tok ) +{ + int ret = 0; + cmd_tok_t *iter = NULL; + + if (tok == NULL) + return 0; + + iter = tok; + while( iter != NULL ) + { + ret += 1; + iter = iter->next; + } + + return ret; +} + + + +cmd_arg_t* cmd_arg_create( cmd_tok_t *tok ) +{ + cmd_arg_t *ret = NULL; + int argc = -1; + cmd_tok_t *iter = NULL; + int i = 0; + + ret = malloc( sizeof(cmd_arg_t) ); + if ( ret == NULL ) + { + return NULL; + } + memset( ret, 0, sizeof( cmd_arg_t )); + + //get number of arguments in command line + argc = cmd_tok_count( tok ); + ret->argc = argc; + + + //alloc mem for argument string values + ret->argv = malloc( sizeof(int*)*argc ); + if ( ret->argv == NULL ) + { + //printf("ERR:err_malloc_argv\n"); + goto err_malloc_argv; + } + memset( ret->argv, 0, sizeof(int*)*argc ); + + //alloc mem for argument type values + ret->type = malloc( sizeof(int)*argc ); + if ( ret->type == NULL ) + { + //printf("ERR:err_malloc_type\n"); + goto err_malloc_type; + } + memset( ret->type, 0, sizeof(int)*argc ); + + //create for each cmd token string and set type + iter = tok; + for (i=0; i<argc; i++,iter=iter->next) + { + ret->argv[i] = malloc( iter->sz+1 ); + memcpy(ret->argv[i], iter->s, iter->sz ); + ret->argv[i][iter->sz] = 0x0; + ret->type[i] = iter->type; + } + + return ret; + +err_malloc_type: + free( ret->argv ); +err_malloc_argv: + free( ret ); + return NULL; +} + + +cmd_arg_t* cmd_arg_sub( cmd_arg_t *arg ) +{ + cmd_arg_t *ret = NULL; + + int i=0; + + if ( arg == NULL ) + return NULL; + + if ( arg->argc == 1 ) + { + ret = cmd_arg_sub_empty(); + return ret; + } + + ret = malloc( sizeof(cmd_arg_t) ); + + ret->argc = arg->argc-1; + + ret->type = malloc(sizeof(int)*(arg->argc-1)); + memset(ret->type, 0, sizeof(int)*(arg->argc-1) ); + + ret->argv = malloc( sizeof(char*)*(arg->argc-1) ); + memset(ret->argv, 0, sizeof(char*)*(arg->argc-1) ); + + ret->__sub_cmd = 1; + + for (i=0; i<ret->argc; i++) + { + ret->argv[i] = arg->argv[i+1]; + ret->type[i] = arg->type[i+1]; + } + + return ret; +} + + +cmd_arg_t* cmd_arg_sub_empty() +{ + cmd_arg_t *ret = NULL; + + ret = malloc( sizeof(cmd_arg_t) ); + ret->argc = 0; + ret->argv = NULL; + ret->type = NULL; + ret->__sub_cmd = 1; + + return ret; +} + +void cmd_arg_destroy( cmd_arg_t *arg ) +{ + int i; + + if ( arg == NULL ) + return; + + for ( i=0; i<arg->argc; i++) + { + if ( arg->__sub_cmd == 0 ) + free( arg->argv[i] ); + } + + free( arg->argv ); + + free( arg->type ); + + free( arg ); +} + +int cmd_exec( cmd_table_t *tbl, cmd_arg_t *arg ) +{ + int ret = -1; + int fret = 0; + int pret = 0; //pre condition return + int i; + + cmd_arg_t *sub_arg = NULL; + + //there could be 0 arguments + if ( arg->argc < 0 ) + { + printf("Hm ... no arguments\n"); + return -1; + } + + if ( arg->argc == 0 ) + return 0; + + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + //printf("tbl.cmd %s\n", tbl[i].cmd ); + if ((strlen(tbl[i].cmd) == strlen(arg->argv[0])) //if there is 0 args then here could be non-0 and we get troubles + && (strlen(tbl[i].cmd) != 0)) //combo if + if ( strncmp( tbl[i].cmd, arg->argv[0], strlen(arg->argv[0]) ) == 0 ) + { + //never will exec becouse of statment in while + if ( tbl[i].clb == NULL ) + { + printf("Empty callback %s\n", tbl[i].cmd); + ret = -1; + break; + } + + sub_arg = cmd_arg_sub( arg ); + //execute callback preconditions + if (tbl[i].pre != NULL) + { + pret = tbl[i].pre( sub_arg ); + } else { + pret = 0; //no precond just pass + } + if (pret == 0) + { + //execute callback + fret = tbl[i].clb( sub_arg ); + } + + //if command whent wrong or not still clean mem + if ( sub_arg != NULL ) + { + cmd_arg_destroy( sub_arg ); + } + + //command execution precondtions met but wrong execution + if ( pret == 0 ) + { + //command execution whent wrong lets go out + if ( fret != 0 ) + { + printf("Command broken execution\n"); + ret = -1; + break; + } + } + ret = 0; //succesfull execution + break; + } + + i++; + } + + return ret; +} + +int cmd_exec_ev( cmd_table_t *tbl, cmd_arg_t *arg, int event ) +{ + int ret = -1; + int fret = 0; + int i; + + cmd_arg_t *sub_arg = NULL; + + if ( arg->argc < 1 ) + { + printf("Hm ... no arguments\n"); + return -1; + } + + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + //printf("tbl.cmd %s\n", tbl[i].cmd ); + if ((strlen(tbl[i].cmd) == strlen(arg->argv[0])) //if there is 0 args then here could be non-0 and we get troubles + && (strlen(tbl[i].cmd) != 0)) //combo if + if ( strncmp( tbl[i].cmd, arg->argv[0], strlen(arg->argv[0]) ) == 0 ) + { + //never will exec becouse of statment in while + if ( tbl[i].clb == NULL ) + { + printf("Empty callback %s\n", tbl[i].cmd); + ret = -1; + break; + } + + sub_arg = cmd_arg_sub( arg ); + + if ( sub_arg == NULL ) + sub_arg = cmd_arg_sub_empty(); + + fret = tbl[i].clb( sub_arg ); + + //if command whent wrong or not still clean mem + if ( sub_arg != NULL ) + { + cmd_arg_destroy( sub_arg ); + } + + //command execution whent wrong lets go out + if ( fret != 0 ) + { + printf("Command broken execution\n"); + ret = -1; + break; + } + ret = 0; + break; + } + + i++; + } + + + return ret; +} + +/* +For now support only first command autocomplete, and return first cmd +RETURN: string to command, dont modify it +*/ +char* cmd_ac( cmd_table_t *tbl, const char *s ) +{ + char *ret = NULL; + int i = -1; + int idx = -1, match=-1;//best match + int ret_match; + int str_ac_sz = strlen(s); + + + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + ret_match = strncmp_ac( s, tbl[i].cmd, str_ac_sz ); + if (ret_match > 0) + { + if (ret_match == str_ac_sz+1) + { + idx = i; + break; + } else + { + if (ret_match > match) + { + idx = i; + match = ret_match; + } + } + } + i++; + } + + if ( idx >= 0 ) + { + ret = tbl[idx].cmd; + } + + return ret; +} + +struct cmd_acq_head_t* cmd_acq( cmd_table_t *tbl, const char *s ) +{ + struct cmd_acq_head_t *ret = NULL; + + int i = -1; + int ret_match; + int str_ac_sz = strlen(s); + + struct cmd_acq_head_t *ac = malloc(sizeof(struct cmd_acq_t)); + + SLIST_INIT(ac); + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + ret_match = strncmp_ac( s, tbl[i].cmd, str_ac_sz ); + if (ret_match > 0) + { + //found 100% match + if (ret_match == str_ac_sz+1) + { + PRINT("Unknown state\n"); + break; + //partial match + } else + { + struct cmd_acq_t *acq = malloc(sizeof(struct cmd_acq_t)); + acq->suggestion = tbl[i].cmd; + SLIST_INSERT_HEAD(ac,acq,next_sugg); + } + } + i++; + } + + ret = ac; + + return ret; +} + +void cmd_acq_free( struct cmd_acq_head_t *acq ) +{ + struct cmd_acq_t *iter; + struct cmd_acq_t *prev; + + prev = NULL; + iter = NULL; + SLIST_FOREACH(iter,acq,next_sugg) + { + if ( prev != NULL ) + { + free( prev ); + prev = NULL; + } + prev = iter; + } + + return; +} + +char* cmd_mng_history( cmd_mng_t *cmng, int index ) +{ + int idx; + char *ret=NULL; + + if (cmng == NULL) + { + return NULL; + } + + if (cmng->history_size < CMD_HISTORY_SIZE) + { + if (index < cmng->history_size) + { + ret = cmng->history[index]; + } + } else + { + idx = (cmng->history_size-CMD_HISTORY_SIZE+index)%CMD_HISTORY_SIZE; + ret = cmng->history[idx]; + } + + return ret; +} + +char* cmd_mng_autocomplete( cmd_mng_t *cmng, char *cmd, size_t cmd_sz ) +{ + char *ret=NULL; + + cmd_arg_t *args; + cmd_tok_t tl, *ptr = &tl, *iter = NULL; + cmd_table_t *tab = cmng->table; + struct cmd_acq_t *iter_sugg = NULL; + int ac_sz=0,cnt_sz=0; + char *ac_str; + memset( &tl, 0, sizeof( cmd_tok_t )); + + if ( parse_cmd(ptr, cmd, cmd_sz) == -1) + { + printf("Cmd problems\n"); + return NULL; + } + + iter = ptr->next; + args = cmd_arg_create( iter ); + + //if command not found offer auto complete options + if (args->argc > 0) + { + struct cmd_acq_head_t *ac = cmd_acq(tab,args->argv[0]); + if (ac != NULL) + { + //calculate string str + SLIST_FOREACH(iter_sugg,ac,next_sugg) + { + //printf("%s ", iter_sugg->suggestion); + ac_sz += strlen(iter_sugg->suggestion)+1; //1 for " " + } + ac_sz += 2; //"> " + ac_sz += 1; //"\0" + + ac_str = (char *)malloc(ac_sz); + + memcpy( ac_str, "> ", 2 ); + cnt_sz = 2; + cnt_sz = 0; + SLIST_FOREACH(iter_sugg,ac,next_sugg) + { + //double logical usage + ac_sz = strlen(iter_sugg->suggestion); + memcpy( ac_str+cnt_sz, iter_sugg->suggestion, ac_sz); + cnt_sz += ac_sz; + ac_str[cnt_sz] = ' '; + cnt_sz += 1; + } + ac_str[cnt_sz] = '\0'; + ret = ac_str; + } + cmd_acq_free( ac ); + } + + cmd_tok_destroy( ptr->next ); + ptr->next = NULL; + cmd_arg_destroy( args ); + + return ret; +} + +int cmd_mng_exec( cmd_mng_t *cmng, const char *cmd, size_t sz_cmd ) +{ + int ret = CMD_EOK; + int fret = 0; + cmd_tok_t tl, *ptr_tl = &tl, *iter = NULL; + cmd_arg_t *args = NULL; + + // Init values + memset( &tl, 0, sizeof( cmd_tok_t )); + + fret = parse_cmd( ptr_tl, cmd, sz_cmd ); + if ( fret != 0 ) + { + ret = CMD_EEXE; + goto error_exe; //if err memleak from parse_cmd? + } + + iter = ptr_tl->next; + args = cmd_arg_create( iter ); + cmd_tok_destroy( ptr_tl->next ); + ptr_tl->next = NULL; + + if (cmd_exec(cmng->table, args) != 0) + { + ret = CMD_ECMD; + goto error_cmd; + } + + /* if history is on then manage commands */ + if (cmng->flag_history) + { + /*replace with proper datatype in future*/ + char *p = malloc(sz_cmd); + int idx = (cmng->history_size)%CMD_HISTORY_SIZE; + memcpy(p,cmd,sz_cmd); + if (cmng->history[idx]!=NULL) free(cmng->history[idx]); + cmng->history[idx] = p; + cmng->history_size += 1; //one day there could be overflow after 2^31/2^63 cmds, good luck with this bug + } + + cmd_arg_destroy( args ); + + return ret; +error_cmd: + cmd_arg_destroy( args ); + +error_exe: + + return ret; +} + +int cmd_mng_free( cmd_mng_t *cmng) +{ + int ret=0; + int i; + + for (i=0;i<CMD_HISTORY_SIZE;i++) + { + if (cmng->history[i]) + { + free(cmng->history[i]); + cmng->history[i] = NULL; + } + } + + return ret; +} + +/* +Clothest match function +AA AB = (1) equile <100% +AA AA = (3) equite 100% +AA AAA = (2) equile 100% but there is more +A B = (0) not equile at all +*/ +int strncmp_ac(const char *s1, const char *s2, const int n) +{ + int i=0; + + if (n<0) + { + printf("n<0 wrong argument value\n"); + return 0; + } + + /* not equile at all */ + /* A B */ + if ( s1[0] != s2[0] ) + { + return 0; + } + + i = 0; + while ( (s1[i] == s2[i]) && (i<n)) + { + i++; + } + + //printf("i"); + /* AA AA */ + if ( (s1[i]==0x00) && (s2[i]==0x0) && (i==n) ) + { + //printf("1 "); + return i+1; + /* AA AAA */ + } else if ( (s1[i]==0x0) && (s2[i]!=0x0) && (i==n) ) + { + //printf("2 "); + return i; + /* AAA AA */ + } else if ( (s1[i]!=0x0) && (s2[i]==0x0) && (i<n) ) + { + //printf("3 "); + return -i; + /* AA AB */ + } else if ( (s1[i]!=0x0) && (s2[i]!=0x0) && (s1[i]!=s2[i]) && (i<n) ) + { + //printf("4 "); + return -i; + } else + { + printf("Unknown condition\n"); + } + + return 0; +}
\ No newline at end of file diff --git a/cmd/cmd.h b/cmd/cmd.h new file mode 100644 index 0000000..a7ba143 --- /dev/null +++ b/cmd/cmd.h @@ -0,0 +1,174 @@ +#ifndef __CMD_H +#define __CMD_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include "debug.h" +#include "queue.h" + +#define CMDT_NONE 0 +#define CMDT_INT 1 +#define CMDT_HEX 2 +#define CMDT_BIN 3 +#define CMDT_QSTR 4 +#define CMDT_STR 5 +#define CMDT_WORD 6 +#define CMDT_SP 7 +#define CMDT_FLOAT 8 + +#define CMDE_NONE 0 //do nothing +#define CMDE_AUTOCOMPLETE 1 //try to auto complete first command +#defi |