X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=debugger%2Fmcs51%2Fsdcdb.c;h=8df52526574ae2c77fc29e30d94becfd3d10f9d0;hb=HEAD;hp=5f764b301ccb459ff742c2a85a8cbb122a88454a;hpb=1883cb8232c73fdebbd89e5a0f97b5fb8b859c97;p=fw%2Fsdcc diff --git a/debugger/mcs51/sdcdb.c b/debugger/mcs51/sdcdb.c index 5f764b30..8df52526 100644 --- a/debugger/mcs51/sdcdb.c +++ b/debugger/mcs51/sdcdb.c @@ -21,12 +21,23 @@ what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ +#define link unix_link +#define _GNU_SOURCE +#include +#undef link #include "sdcdb.h" #include "symtab.h" #include "simi.h" #include "break.h" #include "cmd.h" #include "newalloc.h" +#if defined HAVE_LIBREADLINE && HAVE_LIBREADLINE != -1 +#define HAVE_READLINE_COMPLETITION 1 +#endif +#ifdef HAVE_LIBREADLINE +#include +#include +#endif /* HAVE_LIBREADLINE */ #ifdef SDCDB_DEBUG int sdcdbDebug = 0; @@ -48,161 +59,219 @@ short showfull = 0; char userinterrupt = 0; char nointerrupt = 0; char contsim = 0; -char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX "/small" ; +char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX DIR_SEPARATOR_STRING "small" ; char *simArgs[40]; int nsimArgs = 0; char model_str[20]; /* fake filename & lineno to make linker */ char *filename=NULL; +char *current_directory; int lineno = 0; int fatalError = 0; static void commandLoop(FILE *cmdfile); +#ifdef HAVE_READLINE_COMPLETITION +char *completionCmdSource(const char *text, int state); +char *completionCmdFile(const char *text, int state); +char *completionCmdInfo(const char *text, int state); +char *completionCmdShow(const char *text, int state); +char *completionCmdListSymbols(const char *text, int state); +char *completionCmdPrintType(const char *text, int state); +char *completionCmdPrint(const char *text, int state); +char *completionCmdDelUserBp(const char *text, int state); +char *completionCmdUnDisplay(const char *text, int state); +char *completionCmdSetUserBp(const char *text, int state); +char *completionCmdSetOption(const char *text, int state); +#else +#define completionCmdSource NULL +#define completionCmdFile NULL +#define completionCmdInfo NULL +#define completionCmdShow NULL +#define completionCmdListSymbols NULL +#define completionCmdPrintType NULL +#define completionCmdPrint NULL +#define completionCmdDelUserBp NULL +#define completionCmdUnDisplay NULL +#define completionCmdSetUserBp NULL +#define completionCmdSetOption NULL +#endif /* HAVE_READLINE_COMPLETITION */ /* command table */ struct cmdtab { char *cmd ; /* command the user will enter */ int (*cmdfunc)(char *,context *); /* function to execute when command is entered */ +#ifdef HAVE_READLINE_COMPLETITION + rl_compentry_func_t *completion_func; +#else + void *dummy; +#endif /* HAVE_READLINE_COMPLETITION */ char *htxt ; /* short help text */ } cmdTab[] = { /* NOTE:- the search is done from the top, so "break" should precede the synonym "b" */ /* break point */ - { "break" , cmdSetUserBp , + { "break" , cmdSetUserBp , completionCmdSetUserBp, "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *
]\n", }, - { "tbreak" , cmdSetTmpUserBp , + { "tbreak" , cmdSetTmpUserBp , completionCmdSetUserBp/*same as "break"*/, "tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *
]\n", }, - { "b" , cmdSetUserBp , NULL }, + { "b" , cmdSetUserBp , completionCmdSetUserBp , NULL,}, - { "jump" , cmdJump , + { "jump" , cmdJump , NULL, "jump\t\t\tContinue program being debugged at specified line or address\n [LINE | FILE:LINE | *
]\n", }, - { "clear" , cmdClrUserBp , + { "clear" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/, "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n" }, - { "cl" , cmdClrUserBp , NULL }, + { "cl" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/ , NULL,}, - { "continue" , cmdContinue , + { "continue" , cmdContinue , NULL, "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n" }, - { "condition" , cmdCondition , + { "condition" , cmdCondition , completionCmdDelUserBp/*same as "delete"*/, "condition brkpoint_number expr\t\tSet condition for breakpoint.\n" }, - { "ignore" , cmdIgnore , - "brkpoint_number count\t\tSet ignore count for breakpoint.\n" + { "ignore" , cmdIgnore , completionCmdDelUserBp/*same as "delete"*/, + "ignore brkpoint_number count\t\tSet ignore count for breakpoint.\n" }, - { "commands" , cmdCommands , + { "commands" , cmdCommands , completionCmdDelUserBp/*same as "delete"*/, "commands [brkpoint_number]\t\tSetting commands for breakpoint.\n" }, - { "c" , cmdContinue , NULL }, + { "c" , cmdContinue , NULL , NULL,}, - { "disassemble",cmdDisasmF , "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" }, - { "delete" , cmdDelUserBp , + { "disassemble",cmdDisasmF , NULL, "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" }, + { "delete" , cmdDelUserBp , completionCmdDelUserBp, "{d}elete n\t\t clears break point number n\n" }, - { "display" , cmdDisplay , + { "display" , cmdDisplay , completionCmdPrint/*same as "print"*/, "display [/] []\t print value of given variable each time the program stops\n" }, - { "undisplay" , cmdUnDisplay , + { "undisplay" , cmdUnDisplay , completionCmdUnDisplay, "undisplay []\t dont display this variable or all\n" }, - { "down" , cmdDown , + { "down" , cmdDown , NULL, "down\t\tSelect and print stack frame called by this one.\nAn argument says how many frames down to go.\n" }, - { "up" , cmdUp , + { "up" , cmdUp , NULL, "up\t\tSelect and print stack frame that called this one.\nAn argument says how many frames up to go.\n" }, - { "d" , cmdDelUserBp , NULL }, + { "d" , cmdDelUserBp , completionCmdDelUserBp, NULL }, - { "info" , cmdInfo , - "info \n" + { "info" , cmdInfo , completionCmdInfo, + "info \n" "\t list all break points, call-stack, frame or register information\n" }, - { "listasm" , cmdListAsm , + { "listasm" , cmdListAsm , NULL, "listasm {la}\t\t list assembler code for the current C line\n" }, - { "la" , cmdListAsm , NULL }, - { "ls" , cmdListSymbols , "ls,lf,lm\t\t list symbols,functions,modules\n" }, - { "lf" , cmdListFunctions, NULL }, - { "lm" , cmdListModules , NULL }, - { "list" , cmdListSrc , + { "la" , cmdListAsm , NULL, NULL }, + { "ls" , cmdListSymbols , completionCmdListSymbols, "ls,lf,lm\t\t list symbols,functions,modules\n" }, + { "lf" , cmdListFunctions, completionCmdListSymbols, NULL }, + { "lm" , cmdListModules , completionCmdListSymbols, NULL }, + { "list" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/, "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n" }, - { "l" , cmdListSrc , NULL }, - { "show" , cmdShow , + { "l" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/, NULL }, + { "show" , cmdShow , completionCmdShow, "show" " \t copying & distribution terms, warranty\n" }, - { "set" , cmdSetOption , "set \t\t toggle between c/asm.\nset variable = >value\t\tset variable to new value\n" }, - { "stepi" , cmdStepi , + { "set" , cmdSetOption , completionCmdSetOption, "set \t\t toggle between c/asm.\nset variable = >value\t\tset variable to new value\n" }, + { "stepi" , cmdStepi , NULL, "stepi\t\t\tStep one instruction exactly.\n" }, - { "step" , cmdStep , + { "step" , cmdStep , NULL, "{s}tep\t\t\tStep program until it reaches a different source line.\n" }, - { "source" , cmdSource , + { "source" , cmdSource , completionCmdSource, "source \t\t\tRead commands from a file named FILE.\n" }, - { "s" , cmdStep , NULL }, - { "nexti" , cmdNexti , + { "s" , cmdStep , NULL, NULL }, + { "nexti" , cmdNexti , NULL, "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n" }, - { "next" , cmdNext , + { "next" , cmdNext , NULL, "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n" }, - { "n" , cmdNext , NULL }, - { "run" , cmdRun , + { "n" , cmdNext , NULL, NULL }, + { "run" , cmdRun , NULL, "{r}un\t\t\tStart debugged program. \n" }, - { "r" , cmdRun , NULL }, - { "ptype" , cmdPrintType , + { "r" , cmdRun , NULL, NULL }, + { "ptype" , cmdPrintType , completionCmdPrintType, "{pt}ype \tprint type information of a variable\n" }, - { "pt" , cmdPrintType , NULL }, - { "print" , cmdPrint , + { "pt" , cmdPrintType , NULL, NULL }, + { "print" , cmdPrint , completionCmdPrintType, "{p}rint \t print value of given variable\n" }, - { "output" , cmdOutput , + { "output" , cmdOutput , completionCmdPrint/*same as "print"*/, "output \t print value of given variable without $ and newline \n" }, - { "p" , cmdPrint , NULL }, - { "file" , cmdFile , + { "p" , cmdPrint , completionCmdPrintType, NULL }, + { "file" , cmdFile , completionCmdFile, "file \t\t load symbolic information from \n" }, - { "frame" , cmdFrame , + { "frame" , cmdFrame , NULL, "{fr}ame\t\t print information about the current Stack\n" }, - { "finish" , cmdFinish , + { "finish" , cmdFinish , NULL, "{fi}nish\t\t execute till return of current function\n" }, - { "fi" , cmdFinish , NULL }, - { "where" , cmdWhere , "where\t\t print stack\n" }, - { "fr" , cmdFrame , NULL }, - { "f" , cmdFrame , NULL }, - { "x /i" , cmdDisasm1 , "x\t\t disassemble one asm command\n" }, - { "!" , cmdSimulator , + { "fi" , cmdFinish , NULL, NULL }, + { "where" , cmdWhere , NULL, "where\t\t print stack\n" }, + { "fr" , cmdFrame , NULL, NULL }, + { "f" , cmdFrame , NULL, NULL }, + { "x /i" , cmdDisasm1 , NULL, "x\t\t disassemble one asm command\n" }, + { "!" , cmdSimulator , NULL, "!\t send a command directly to the simulator\n" }, - { "." , cmdSimulator , + { "." , cmdSimulator , NULL, ".{cmd}\t switch from simulator or debugger command mode\n" }, - { "help" , cmdHelp , + { "help" , cmdHelp , NULL, "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n" }, - { "?" , cmdHelp , NULL }, - { "h" , cmdHelp , NULL }, + { "?" , cmdHelp , NULL, NULL }, + { "h" , cmdHelp , NULL, NULL }, - { "quit" , cmdQuit , + { "quit" , cmdQuit , NULL, "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n" }, - { "q" , cmdQuit , NULL } + { "q" , cmdQuit , NULL, NULL } }; +/*-----------------------------------------------------------------*/ +/* trimming functions */ +/*-----------------------------------------------------------------*/ +char *trim_left(char *s) +{ + while (isspace(*s)) + ++s; + + return s; +} + +char *trim_right(char *s) +{ + char *p = &s[strlen(s) - 1]; + + while (p >= s && isspace(*p)) + --p; + *++p = '\0'; + + return s; +} + +char *trim(char *s) +{ + return trim_right(trim_left(s)); +} + /*-----------------------------------------------------------------*/ /* gc_strdup - make a string duplicate garbage collector aware */ /*-----------------------------------------------------------------*/ @@ -318,7 +387,7 @@ char *searchDirsFname (char *fname) { char *dirs , *sdirs; FILE *rfile = NULL; - char buffer[128]; + char buffer[1024]; /* first try the current directory */ if ((rfile = fopen(fname,"r"))) { @@ -360,7 +429,7 @@ FILE *searchDirsFopen(char *fname) { char *dirs , *sdirs; FILE *rfile = NULL; - char buffer[128]; + char buffer[1024]; /* first try the current directory */ if ((rfile = fopen(fname,"r"))) @@ -433,7 +502,7 @@ static void loadModules (void) switch (loop->type) { /* for module records do */ case MOD_REC: - currMod = parseModule(loop->line,TRUE); + currMod = parseModule(loop->line, TRUE); currModName = currMod->name ; currMod->cfullname = searchDirsFname(currMod->c_name); @@ -624,38 +693,17 @@ static void functionPoints (void) } } - -/*-----------------------------------------------------------------*/ -/* setEntryExitBP - set the entry & exit Break Points for functions*/ -/*-----------------------------------------------------------------*/ -DEFSETFUNC(setEntryExitBP) -{ - function *func = item; - - if (func->sym && func->sym->addr && func->sym->eaddr) { - - /* set the entry break point */ - setBreakPoint (func->sym->addr , CODE , FENTRY , - fentryCB ,func->mod->c_name , func->entryline); - - /* set the exit break point */ - setBreakPoint (func->sym->eaddr , CODE , FEXIT , - fexitCB ,func->mod->c_name , func->exitline ); - } - - return 0; -} - /*-----------------------------------------------------------------*/ /* cmdFile - load file into the debugger */ /*-----------------------------------------------------------------*/ int cmdFile (char *s,context *cctxt) { FILE *cdbFile; - char buffer[128]; + char buffer[1024]; char *bp; - while (isspace(*s)) s++; + s = trim_left(s); + if (!*s) { fprintf(stdout,"No exec file now.\nNo symbol file now.\n"); return 0; @@ -690,7 +738,11 @@ int cmdFile (char *s,context *cctxt) specialFunctionRegs(); /* start the simulator & setup connection to it */ +#ifdef _WIN32 + if (INVALID_SOCKET == sock) +#else if ( sock == -1 ) +#endif openSimulator((char **)simArgs,nsimArgs); fprintf(stdout,"%s",simResponse()); /* now send the filename to be loaded to the simulator */ @@ -702,7 +754,7 @@ int cmdFile (char *s,context *cctxt) /*set the break points required by the debugger . i.e. the function entry and function exit break points */ - applyToSet(functions,setEntryExitBP); +// applyToSet(functions,setEntryExitBP); setMainContext(); return 0; @@ -714,13 +766,8 @@ int cmdFile (char *s,context *cctxt) int cmdSource (char *s, context *cctxt) { FILE *cmdfile; - char *bp = s+strlen(s) -1; - - while (isspace(*s)) - ++s; - while (isspace(*bp)) bp--; - *++bp = '\0'; + s = trim(s); if (!( cmdfile = searchDirsFopen(s))) { @@ -741,8 +788,8 @@ int cmdHelp (char *s, context *cctxt) int endline = 999; int startline = 0; - while (isspace(*s)) - ++s; + s = trim_left(s); + if (isdigit(*s)) { endline = ((*s - '0') * 20) + 20; if (endline > 0) @@ -783,6 +830,16 @@ int cmdHelp (char *s, context *cctxt) static char cmdbuff[MAX_CMD_LEN]; static int sim_cmd_mode = 0; +char * +canonname(char *file) +{ + static char buffer[1024]; + if (*file == '/') + return file; + sprintf(buffer,"%s/%s", current_directory, file); + return buffer; +} + /*----------------------------------------------------------------- interpretCmd - interpret and do the command. Return 0 to continue, return 1 to exit program. @@ -795,7 +852,7 @@ int interpretCmd (char *s) /* if nothing & previous command exists then execute the previous command again */ - if (*s == '\n' && pcmd) + if ((*s == '\n' || *s == '\0') && pcmd) strcpy(s,pcmd); /* if previous command exists & is different @@ -808,8 +865,8 @@ int interpretCmd (char *s) } else pcmd = strdup(s); - /* lookup the command table and do the task required */ - strtok(s,"\n"); + /* trim trailing blanks */ + s = trim_right(s); if (sim_cmd_mode) { if (strcmp(s,".") == 0) { @@ -848,11 +905,11 @@ int interpretCmd (char *s) showfull = 0; if (srcMode == SRC_CMODE) fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n", - currCtxt->func->mod->cfullname, + canonname(currCtxt->func->mod->cfullname), currCtxt->cline+1,currCtxt->addr); else fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n", - currCtxt->func->mod->afullname, + canonname(currCtxt->func->mod->afullname), currCtxt->asmline,currCtxt->addr); displayAll(currCtxt); } @@ -897,13 +954,533 @@ void stopCommandList() stopcmdlist = 1; } +#ifdef HAVE_READLINE_COMPLETITION +// helper function for doing readline completion. +// input: toknum=index of token to find (0=first token) +// output: *start=first character index of the token, +// or the index of '\0' +// *end=first blank character right after the token, +// or the index of '\0' +// return value: 0=token not found, 1=token found +int completionHelper_GetTokenNumber(int toknum, int *start, int *end) +{ + int tok_index; + const char *p = rl_line_buffer; + + tok_index = 0; + *start = *end = 0; + while (p[*end] != 0) + { + // start = skip blanks from end + *start = *end; + while (p[*start] && isspace( p[*start] )) + (*start)++; + + // end = skip non-blanks from start + *end = *start; + while (p[*end] && !isspace( p[*end] )) + (*end)++; + + if (tok_index == toknum) + return 1; // found + + tok_index++; + } + + return 0; // not found +} + +// helper function for doing readline completion. +// returns the token number that we were asked to complete. +// 0=first token (command name), 1=second token... +int completionHelper_GetCurrTokenNumber() +{ + int toknum, start, end; + + toknum = start = end = 0; + while (1) + { + if (!completionHelper_GetTokenNumber(toknum, &start, &end)) + return toknum; + + if (rl_point <= end) + return toknum; + + toknum++; + } +} + +// exapmle for vallist on entry: +// "copying\0warranty\0"; +char *completionCompleteFromStrList(const char *text, int state, char *vallist) +{ + static char *ptr; + int len; + + if (state == 0) + ptr = vallist; + else + ptr += strlen(ptr)+1; + + len = strlen(text); + while (*ptr) + { + if ( (len < strlen(ptr)) && + !strncmp(text, ptr, len) ) + return strdup(ptr); + + ptr += strlen(ptr)+1; + } + + return NULL; +} + +// readline library completion function. +// completes from the list of all sdcdb command. +char *completionCommandsList(const char *text, int state) +{ + static int i = 0; + + if (state == 0) // new completion? + { // yes, only complete if this is the first token on the line. + int ok = 0; // try to complete this request? + char *p = rl_line_buffer; + + // skip blanks + while (p && isspace(*p)) + { + if (p-rl_line_buffer == rl_point) + ok = 1; + p++; + } + + while (p && !isspace(*p)) + { + if (p-rl_line_buffer == rl_point) + ok = 1; + p++; + } + + if (p-rl_line_buffer == rl_point) + ok = 1; + + if ( !ok ) + return NULL; // no more completions + + i = 0; // ok, gonna complete. initialize static variable. + } + else i++; + + for (; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) + { + int len = strlen(text); + if (len <= strlen(cmdTab[i].cmd)) + { + if (strncmp(text,cmdTab[i].cmd,len) == 0) + return strdup(cmdTab[i].cmd); + } + } + + return NULL; // no more completions +} + +// readline library completion function. +// completes from the list of symbols. +char *completionSymbolName(const char *text, int state) +{ + static symbol *sy; + + if (state == 0) // new completion? + sy = setFirstItem(symbols); // yes + else + sy = setNextItem(symbols); + + for (; sy != NULL; ) + { + int len = strlen(text); + if (len <= strlen(sy->name)) + { + if (strncmp(text,sy->name,len) == 0) + return strdup(sy->name); + } + + sy = setNextItem(symbols); + } + return NULL; +} + +// readline library completion function. +// completes from the list known functions. +// module_flag - if false, ignore function module name +// if true, compare against module_name:fnction_name +char *completionFunctionName(const char *text, int state, int module_flag) +{ + static function *f; + + if (state == 0) // new completion? + f = setFirstItem(functions); // yes + else + f = setNextItem(functions); + + for (; f != NULL; ) + { + int text_len = strlen(text); + + if (!module_flag) + { + if (text_len <= strlen(f->sym->name) && + !strncmp(text,f->sym->name,text_len)) + return strdup(f->sym->name); + } + else + { + int modname_len = strlen(f->mod->c_name); + int funcname_len = strlen(f->sym->name); + char *functext = malloc(modname_len+funcname_len+2); + //assert(functext); + strcpy(functext,f->mod->c_name); + strcat(functext,":"); + strcat(functext,f->sym->name); + if (text_len <= strlen(functext) && + !strncmp(text,functext,text_len)) + return functext; + else + free(functext); + } + f = setNextItem(functions); + } + return NULL; +} + +// readline library completion function. +// completes from the list known modules. +char *completionModuleName(const char *text, int state) +{ + static module *m; + + if (state == 0) // new completion? + m = setFirstItem(modules); // yes + else + m = setNextItem(modules); + + for (; m != NULL; ) + { + int len = strlen(text); + if ( (len <= strlen(m->c_name)) && + !strncmp(text,m->c_name,len) ) + return strdup(m->c_name); + + if ( (len <= strlen(m->asm_name)) && + (strncmp(text,m->asm_name,len) == 0) ) + return strdup(m->asm_name); + + m = setNextItem(modules); + } + return NULL; +} + +// readline completion function for "file" command +char *completionCmdFile(const char *text, int state) +{ + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + } + + // we use filename_completion_function() from the readline library. + return rl_filename_completion_function(text, state); +} + +// readline completion function for "source" command +char *completionCmdSource(const char *text, int state) +{ + return completionCmdFile(text, state); +} + +// readline completion function for "info" command +char *completionCmdInfo(const char *text, int state) +{ + static char *ptr; + + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + } + + return completionCompleteFromStrList(text, state, + "break\0stack\0frame\0registers\0all-registers\0" + "line\0source\0functions\0symbols\0variables\0"); +} + +// readline completion function for "show" command +char *completionCmdShow(const char *text, int state) +{ + static char *ptr; + + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + } + return completionCompleteFromStrList(text, state, "copying\0warranty\0"); +} + +// readline completion function for "la" command +char *completionCmdListSymbols(const char *text, int state) +{ + static char *ptr; + + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + } + return completionCompleteFromStrList(text, state, "v1\0v2\0"); +} + +char *completionCmdPrintType(const char *text, int state) +{ + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + } + return completionSymbolName(text, state); +} + +char *completionCmdPrint(const char *text, int state) +{ + if (state == 0) + { + int i = completionHelper_GetCurrTokenNumber(); + if (i != 1 && i != 2) + return NULL; + } + return completionSymbolName(text, state); +} + +char *completionCmdDelUserBp(const char *text, int state) +{ + static breakp *bp; + static int k; + + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + + if (!userBpPresent) + return NULL; + + bp = hTabFirstItem(bptable,&k); + } + else + bp = hTabNextItem(bptable,&k); + + for ( ; bp ; bp = hTabNextItem(bptable,&k)) + { + if (bp->bpType == USER || bp->bpType == TMPUSER) + { + char buff[20]; + sprintf(buff, "%d", bp->bpnum); + return strdup(buff); + } + } + + return NULL; +} + +// readline completion function for "undisplay" command +char *completionCmdUnDisplay(const char *text, int state) +{ + static dsymbol *dsym; + + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + dsym = setFirstItem(dispsymbols); + } + + if (dsym) + { + char buff[30]; + sprintf(buff, "%d", dsym->dnum); + dsym = setNextItem(dispsymbols); + return strdup(buff); + } + return NULL; +} + +char *completionCmdSetUserBp(const char *text, int state) +{ + static int internal_state; // 0=calling completionFunctionName(text, state, 0) + // 1=calling completionFunctionName(text, 1, 1) + if (state == 0) + { + if (completionHelper_GetCurrTokenNumber() != 1) + return NULL; + + internal_state = 0; + } + if (internal_state == 0) + { + char *p = completionFunctionName(text, state, 0); + if (p) + return p; + internal_state = 1; + return completionFunctionName(text, 0, 1); + } + else + { + return completionFunctionName(text, 1, 1); + } +} + +char *completionCmdSetOption(const char *text, int state) +{ + static char *ptr; + static int currtok; + + if (state == 0) + { + int start,end; + + currtok = completionHelper_GetCurrTokenNumber(); + + if (currtok == 2 || currtok == 3) + { + // make sure token 1 == "variable" + completionHelper_GetTokenNumber(1, &start, &end); + if (end - start != 8 || + strncmp(rl_line_buffer+start,"variable",8)) + return NULL; + } + else if (currtok != 1) + { + return NULL; + } + } + + switch (currtok) + { + case 1: + return completionCompleteFromStrList(text, state, +#ifdef SDCDB_DEBUG + "debug\0" +#endif + "srcmode\0listsize\0variable\0"); + case 2: + return completionSymbolName(text, state); + + case 3: + return completionCompleteFromStrList(text, state, "=\0"); + } +} + +// our main readline completion function +// calls the other completion functions as needed. +char *completionMain(const char *text, int state) +{ + static rl_compentry_func_t *compl_func; + int i, start, end, len; + + if (state == 0) // new completion? + { + compl_func = NULL; + + if (completionHelper_GetCurrTokenNumber() == 0) + compl_func = &completionCommandsList; + else + { // not completing first token, find the right completion + // function according to the first token the user typed. + completionHelper_GetTokenNumber(0, &start, &end); + len = end-start; + + for (i=0; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) + { + if (!strncmp(rl_line_buffer+start,cmdTab[i].cmd,len) && + cmdTab[i].cmd[len] == '\0') + { + compl_func = cmdTab[i].completion_func; + break; + } + } + } + if (!compl_func) + return NULL; + } + + return (*compl_func)(text,state); +} +#endif /* HAVE_READLINE_COMPLETITION */ + /*-----------------------------------------------------------------*/ /* commandLoop - the main command loop or loop over command file */ /*-----------------------------------------------------------------*/ static void commandLoop(FILE *cmdfile) { char *line, save_ch, *s; + char *line_read; + +#ifdef HAVE_LIBREADLINE + FILE *old_rl_instream, *old_rl_outstream; actualcmdfile = cmdfile; + +#ifdef HAVE_READLINE_COMPLETITION + rl_completion_entry_function = completionMain; +#endif /* HAVE_READLINE_COMPLETITION */ + rl_readline_name = "sdcdb"; // Allow conditional parsing of the ~/.inputrc file. + + // save readline's input/output streams + // this is done to support nested calls to commandLoop() + // i wonder if it works... + old_rl_instream = rl_instream; + old_rl_outstream = rl_outstream; + + // set new streams for readline + if ( cmdfile == stdin ) + rl_instream = rl_outstream = NULL; // use stdin/stdout pair + else + rl_instream = rl_outstream = cmdfile; + + while (1) + { + if ( cmdfile == stdin ) + { + if (sim_cmd_mode) + line_read = (char*)readline ("(sim) "); + else + line_read = (char*)readline ("(sdcdb) "); + } + else + line_read = (char*)readline (""); + + if (line_read) + { + /* If the line has any text in it, + save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + // FIX: readline returns malloced string. + // should check the source to verify it can be used + // directly. for now - just copy it to cmdbuff. + strcpy(cmdbuff,line_read); +#if defined(_WIN32) || defined(HAVE_RL_FREE) + rl_free(line_read); +#else + free(line_read); +#endif + line_read = NULL; + } + else + break; // EOF +#else + actualcmdfile = cmdfile; + while (1) { if ( cmdfile == stdin ) @@ -914,14 +1491,14 @@ static void commandLoop(FILE *cmdfile) fprintf(stdout,"(sdcdb) "); fflush(stdout); } - //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n", // actualcmdfile,cmdfile); if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL) break; +#endif /* HAVE_LIBREADLINE */ - if (interpretCmd(cmdbuff)) - break; + if (interpretCmd(cmdbuff)) + break; while ( actualcmds ) { @@ -951,6 +1528,11 @@ static void commandLoop(FILE *cmdfile) } } } +#ifdef HAVE_LIBREADLINE + // restore readline's input/output streams + rl_instream = old_rl_instream; + rl_outstream = old_rl_outstream; +#endif /* HAVE_LIBREADLINE */ } /*-----------------------------------------------------------------*/ @@ -1014,7 +1596,7 @@ static void parseCmdLine (int argc, char **argv) } if (strncmp(argv[i],"-cd=",4) == 0) { - chdir(argv[i][4]); + chdir(argv[i]+4); continue; } @@ -1071,8 +1653,10 @@ static void parseCmdLine (int argc, char **argv) /* serial port */ if ( (strcmp(argv[i],"-S") == 0) || - (strcmp(argv[i],"-s") == 0)) { - simArgs[nsimArgs++] = strdup(argv[i]); + (strcmp(argv[i],"-s") == 0) || + (strcmp(argv[i],"-T") == 0) || + (strcmp(argv[i],"--tty") == 0)) { + simArgs[nsimArgs++] = "--tty"; simArgs[nsimArgs++] = strdup(argv[++i]); continue ; } @@ -1095,7 +1679,15 @@ static void parseCmdLine (int argc, char **argv) continue ; } - filename = strtok(argv[i],"."); + if (-1 != access(argv[i], 0)) { + /* file exists: strip the cdb or ihx externsion */ + char *p = strrchr(argv[i], '.'); + + if (NULL != p && + (0 == strcmp(p, ".cdb") || 0 == strcmp(p, ".ihx"))) + *p = '\0'; + } + filename = argv[i]; } } @@ -1167,7 +1759,8 @@ int main ( int argc, char **argv) printVersionInfo(); printf("WARNING: SDCDB is EXPERIMENTAL.\n"); - simArgs[nsimArgs++] = "s51"; + current_directory = get_current_dir_name(); + simArgs[nsimArgs++] = "ao-dbg"; simArgs[nsimArgs++] = "-P"; simArgs[nsimArgs++] = "-r 9756"; /* parse command line */