#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 <readline/readline.h>
+#include <readline/history.h>
+#endif /* HAVE_LIBREADLINE */
#ifdef SDCDB_DEBUG
int sdcdbDebug = 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];
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 | *<address>]\n",
},
- { "tbreak" , cmdSetTmpUserBp ,
+ { "tbreak" , cmdSetTmpUserBp , completionCmdSetUserBp/*same as "break"*/,
"tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\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 | *<address>]\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 [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
},
- { "undisplay" , cmdUnDisplay ,
+ { "undisplay" , cmdUnDisplay , completionCmdUnDisplay,
"undisplay [<variable>]\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 <break stack frame registers all-registers>\n"
+ { "info" , cmdInfo , completionCmdInfo,
+ "info <break stack frame registers all-registers line source functions symbols variables>\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"
" <copying warranty>\t copying & distribution terms, warranty\n"
},
- { "set" , cmdSetOption , "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
- { "stepi" , cmdStepi ,
+ { "set" , cmdSetOption , completionCmdSetOption, "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >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 <FILE>\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 <variable>\tprint type information of a variable\n"
},
- { "pt" , cmdPrintType , NULL },
- { "print" , cmdPrint ,
+ { "pt" , cmdPrintType , NULL, NULL },
+ { "print" , cmdPrint , completionCmdPrintType,
"{p}rint <variable>\t print value of given variable\n"
},
- { "output" , cmdOutput ,
+ { "output" , cmdOutput , completionCmdPrint/*same as "print"*/,
"output <variable>\t print value of given variable without $ and newline \n"
},
- { "p" , cmdPrint , NULL },
- { "file" , cmdFile ,
+ { "p" , cmdPrint , completionCmdPrintType, NULL },
+ { "file" , cmdFile , completionCmdFile,
"file <filename>\t\t load symbolic information from <filename>\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,
"!<simulator command>\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 */
/*-----------------------------------------------------------------*/
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);
char buffer[128];
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;
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 */
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)))
{
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)
} 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) {
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 )
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 )
{
}
}
}
+#ifdef HAVE_LIBREADLINE
+ // restore readline's input/output streams
+ rl_instream = old_rl_instream;
+ rl_outstream = old_rl_outstream;
+#endif /* HAVE_LIBREADLINE */
}
/*-----------------------------------------------------------------*/
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];
}
}