00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 # include "config.h"
00074
00075
00076 #if TCLREADLINE_ENABLED
00077
00078 #include <tcl.h>
00079 #include <stdio.h>
00080 #include <stdlib.h>
00081 #include <string.h>
00082
00083 #if defined (READLINE_LIBRARY)
00084 # include <readline.h>
00085 # include <history.h>
00086 #else
00087 # include <readline/readline.h>
00088 # include <readline/history.h>
00089 #endif
00090
00091 #ifdef READLINE_IS_EDITLINE
00092 #define rl_completion_matches completion_matches
00093 #endif
00094
00099 void rl_extend_line_buffer(int len);
00100
00101 #ifdef EXECUTING_MACRO_HACK
00102
00107 extern char* _rl_executing_macro;
00108 #endif
00109
00110 #include "tclreadline.h"
00111
00112 #define MALLOC(size) Tcl_Alloc((int) size)
00113 #define FREE(ptr) if (ptr) { Tcl_Free((char*) ptr); ptr = 0; }
00114
00115 enum {
00116 _CMD_SET = (1 << 0),
00117 _CMD_GET = (1 << 1)
00118 };
00119
00120
00121 typedef struct cmds_t {
00122 struct cmds_t* prev;
00123 char** cmd;
00124 struct cmds_t* next;
00125 } cmds_t;
00126
00127
00128 #define ISWHITE(c) ((' ' == c) || ('\t' == c) || ('\n' == c))
00129
00130
00131 static char* stripleft(char* in);
00132 static char* stripright(char* in);
00133 static char* stripwhite(char* in);
00134 static int TclReadlineLineComplete(void);
00135 static void TclReadlineTerminate(int state);
00136 static char* TclReadlineQuote(char* text, char* quotechars);
00137 static int TclReadlineCmd(ClientData clientData, Tcl_Interp* interp, int argc, CONST char** argv);
00138 static void TclReadlineReadHandler(ClientData clientData, int mask);
00139 static void TclReadlineLineCompleteHandler(char* ptr);
00140 static int TclReadlineInitialize(Tcl_Interp* interp, char* historyfile);
00141 static int blank_line(char* str);
00142 static char** TclReadlineCompletion(char* text, int start, int end);
00143 static char* TclReadline0generator(const char* text, int state);
00144 static char* TclReadlineKnownCommands(char* text, int state, int mode);
00145 static int TclReadlineParse(char** args, int maxargs, char* buf);
00146
00147
00148 int Tclreadline_SafeInit(Tcl_Interp* interp);
00149 int Tclreadline_Init(Tcl_Interp* interp);
00150
00151
00152 enum {
00153 LINE_PENDING = -1,
00154 LINE_EOF = (1 << 8),
00155 LINE_COMPLETE = (1 << 9)
00156 };
00157
00161 static int tclrl_state = TCL_OK;
00162 static char* tclrl_eof_string = (char*) NULL;
00163 static char* tclrl_custom_completer = (char*) NULL;
00164 static char* tclrl_last_line = (char*) NULL;
00165 static int tclrl_use_builtin_completer = 1;
00166 static int tclrl_history_length = -1;
00167 Tcl_Interp* tclrl_interp = (Tcl_Interp*) NULL;
00168
00169 static char* tclrl_license =
00170 " Copyright (c) 1998 - 2000, Johannes Zellner <johannes@zellner.org>\n"
00171 " All rights reserved.\n"
00172 " \n"
00173 " Redistribution and use in source and binary forms, with or without\n"
00174 " modification, are permitted provided that the following conditions\n"
00175 " are met:\n"
00176 " \n"
00177 " * Redistributions of source code must retain the above copyright\n"
00178 " notice, this list of conditions and the following disclaimer.\n"
00179 " * Redistributions in binary form must reproduce the above copyright\n"
00180 " notice, this list of conditions and the following disclaimer in the\n"
00181 " documentation and/or other materials provided with the distribution.\n"
00182 " * Neither the name of Johannes Zellner nor the names of contributors\n"
00183 " to this software may be used to endorse or promote products derived\n"
00184 " from this software without specific prior written permission.\n"
00185 " \n"
00186 " THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
00187 " ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
00188 " LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
00189 " A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR\n"
00190 " CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n"
00191 " EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n"
00192 " PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n"
00193 " PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n"
00194 " LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n"
00195 " NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"
00196 " SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
00197
00198
00199
00200 static char*
00201 stripleft(char* in)
00202 {
00203 char* ptr = in;
00204 while (*ptr && *ptr <= ' ')
00205 ptr++;
00206 if (in != ptr)
00207 memmove(in, ptr, strlen(ptr) + 1);
00208 return in;
00209 }
00210
00211 static char*
00212 stripright(char* in)
00213 {
00214 char* ptr;
00215 for (ptr = strchr(in, '\0') - 1; ptr >= in && *ptr <= ' '; ptr--)
00216 *ptr = '\0';
00217 return in;
00218 }
00219
00220 static char*
00221 stripwhite(char* in)
00222 {
00223 stripleft(in);
00224 stripright(in);
00225 return in;
00226 }
00227
00228 static int
00229 TclReadlineLineComplete(void)
00230 {
00231 return !(tclrl_state == LINE_PENDING);
00232 }
00233
00234 static void
00235 TclReadlineTerminate(int state)
00236 {
00237 tclrl_state = state;
00238 rl_callback_handler_remove();
00239 }
00240
00241 static char*
00242 TclReadlineQuote(char* text, char* quotechars)
00243 {
00244 char* ptr;
00245 char* result_c;
00246 int i, len = strlen(quotechars);
00247 Tcl_DString result;
00248
00249 Tcl_DStringInit(&result);
00250 for (ptr = text; ptr && *ptr; ptr++) {
00251 for (i = 0; i < len; i++) {
00252 if (quotechars[i] == *ptr) {
00253 Tcl_DStringAppend(&result, "\\", 1);
00254 break;
00255 }
00256 }
00257 Tcl_DStringAppend(&result, ptr, 1);
00258 }
00259 result_c = strdup(Tcl_DStringValue(&result));
00260 return result_c;
00261 }
00262
00263 static int
00264 TclReadlineCmd(
00265 ClientData clientData,
00266 Tcl_Interp* interp,
00267 int argc,
00268 CONST char** argv
00269 )
00270 {
00271 int i, obj_idx, status;
00272 Tcl_Obj** objv = (Tcl_Obj**) MALLOC((argc + 1) * sizeof(Tcl_Obj *));
00273
00274 static const char *subCmds[] = {
00275 "read", "initialize", "write", "add", "complete",
00276 "customcompleter", "builtincompleter", "eofchar",
00277 "reset-terminal", "bell", "eof",
00278 (char *) NULL
00279 };
00280 enum SubCmdIdx {
00281 TCLRL_READ, TCLRL_INITIALIZE, TCLRL_WRITE, TCLRL_ADD, TCLRL_COMPLETE,
00282 TCLRL_CUSTOMCOMPLETER, TCLRL_BUILTINCOMPLETER, TCLRL_EOFCHAR,
00283 TCLRL_RESET_TERMINAL, TCLRL_BELL, TCLRL_EOF
00284 };
00285
00286 (void)clientData;
00287
00288 Tcl_ResetResult(interp);
00289
00290 for (i = 0; i < argc; i++) {
00291 Tcl_Obj* objPtr = Tcl_NewStringObj(argv[i], -1);
00292 Tcl_IncrRefCount(objPtr);
00293 objv[i] = objPtr;
00294 }
00295 objv[argc] = 0;
00296
00297 if (argc < 2) {
00298 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
00299 return TCL_ERROR;
00300 }
00301
00302 status = Tcl_GetIndexFromObj
00303 (interp, objv[1], subCmds, "option", 0, (int *) &obj_idx);
00304
00305 if (status != TCL_OK) {
00306 FREE(objv)
00307 return status;
00308 }
00309
00310 switch (obj_idx) {
00311
00312 case TCLRL_READ:
00313
00314 if (tclrl_state == LINE_EOF) {
00315 return TCL_OK;
00316 }
00317
00318
00319
00320
00321 #if READLINE_IS_EDITLINE
00322 #define CALLBACK_CAST (void (*)(void))
00323 #else
00324 #define CALLBACK_CAST
00325 #endif
00326 rl_callback_handler_install(argc == 3 ? argv[2] : "%",
00327 CALLBACK_CAST TclReadlineLineCompleteHandler);
00328 #undef CALLBACK_CAST
00329
00330 Tcl_CreateFileHandler(0, TCL_READABLE,
00331 TclReadlineReadHandler, (ClientData) NULL);
00332
00340 tclrl_state = LINE_PENDING;
00341
00342 while (!TclReadlineLineComplete()) {
00343 #ifdef EXECUTING_MACRO_HACK
00344
00350 if (_rl_executing_macro)
00351 TclReadlineReadHandler((ClientData) NULL, TCL_READABLE);
00352 else
00353 #endif
00354 Tcl_DoOneEvent(TCL_ALL_EVENTS);
00355 }
00356
00357 Tcl_DeleteFileHandler(0);
00358
00359 switch (tclrl_state) {
00360
00361 case LINE_COMPLETE:
00362
00363 return TCL_OK;
00364
00365 break;
00366
00367 case LINE_EOF:
00368 if (tclrl_eof_string)
00369 return Tcl_Eval(interp, tclrl_eof_string);
00370 else
00371 return TCL_OK;
00372
00373 break;
00374
00375 default:
00376 return tclrl_state;
00377
00378 break;
00379 }
00380 break;
00381
00382 case TCLRL_INITIALIZE:
00383 if (3 != argc) {
00384 Tcl_WrongNumArgs(interp, 2, objv, "historyfile");
00385 return TCL_ERROR;
00386 } else {
00387 return TclReadlineInitialize(interp, (char*)argv[2]);
00388 }
00389 break;
00390
00391 case TCLRL_WRITE:
00392 if (3 != argc) {
00393 Tcl_WrongNumArgs(interp, 2, objv, "historyfile");
00394 return TCL_ERROR;
00395 } else if (write_history(argv[2])) {
00396 Tcl_AppendResult(interp, "unable to write history to `",
00397 argv[2], "'\n", (char*) NULL);
00398 return TCL_ERROR;
00399 }
00400 if (tclrl_history_length >= 0) {
00401 history_truncate_file(argv[2], tclrl_history_length);
00402 }
00403 return TCL_OK;
00404 break;
00405
00406 case TCLRL_ADD:
00407 if (3 != argc) {
00408 Tcl_WrongNumArgs(interp, 2, objv, "completerLine");
00409 return TCL_ERROR;
00410 } else if (TclReadlineKnownCommands((char*)argv[2], (int) 0, _CMD_SET)) {
00411 Tcl_AppendResult(interp, "unable to add command \"",
00412 argv[2], "\"\n", (char*) NULL);
00413 }
00414 break;
00415
00416 case TCLRL_COMPLETE:
00417 if (3 != argc) {
00418 Tcl_WrongNumArgs(interp, 2, objv, "line");
00419 return TCL_ERROR;
00420 } else if (Tcl_CommandComplete(argv[2])) {
00421 Tcl_AppendResult(interp, "1", (char*) NULL);
00422 } else {
00423 Tcl_AppendResult(interp, "0", (char*) NULL);
00424 }
00425 break;
00426
00427 case TCLRL_CUSTOMCOMPLETER:
00428 if (argc > 3) {
00429 Tcl_WrongNumArgs(interp, 2, objv, "?scriptCompleter?");
00430 return TCL_ERROR;
00431 } else if (3 == argc) {
00432 if (tclrl_custom_completer)
00433 free(tclrl_custom_completer);
00434 if (!blank_line((char*)argv[2]))
00435 tclrl_custom_completer = stripwhite(strdup(argv[2]));
00436 }
00437 Tcl_AppendResult(interp, tclrl_custom_completer, (char*) NULL);
00438 break;
00439
00440 case TCLRL_BUILTINCOMPLETER:
00441 if (argc > 3) {
00442 Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
00443 return TCL_ERROR;
00444 } else if (3 == argc) {
00445 int bool = tclrl_use_builtin_completer;
00446 if (TCL_OK != Tcl_GetBoolean(interp, argv[2], &bool)) {
00447 Tcl_AppendResult(interp,
00448 "wrong # args: should be a boolean value.",
00449 (char*) NULL);
00450 return TCL_ERROR;
00451 } else {
00452 tclrl_use_builtin_completer = bool;
00453 }
00454 }
00455 Tcl_AppendResult(interp, tclrl_use_builtin_completer ? "1" : "0",
00456 (char*) NULL);
00457 break;
00458
00459 case TCLRL_EOFCHAR:
00460 if (argc > 3) {
00461 Tcl_WrongNumArgs(interp, 2, objv, "?script?");
00462 return TCL_ERROR;
00463 } else if (3 == argc) {
00464 if (tclrl_eof_string)
00465 free(tclrl_eof_string);
00466 if (!blank_line((char*)argv[2]))
00467 tclrl_eof_string = stripwhite(strdup(argv[2]));
00468 }
00469 Tcl_AppendResult(interp, tclrl_eof_string, (char*) NULL);
00470 break;
00471
00472 case TCLRL_RESET_TERMINAL:
00473
00474 if (argc > 3) {
00475 Tcl_WrongNumArgs(interp, 2, objv, "?terminal-name?");
00476 return TCL_ERROR;
00477 }
00478 if (3 == argc) {
00479
00480
00481
00482
00483
00484
00485 rl_reset_terminal(Tcl_GetStringFromObj(objv[2], (int*) NULL));
00486 #ifdef CLEANUP_AFER_SIGNAL
00487 } else {
00488 rl_cleanup_after_signal();
00489 #endif
00490 }
00491 break;
00492
00493 case TCLRL_BELL:
00494
00495
00496
00497
00498 ding();
00499 break;
00500
00501 case TCLRL_EOF:
00502 tclrl_state = LINE_EOF;
00503 break;
00504
00505 default:
00506 goto BAD_COMMAND;
00507
00508 break;
00509 }
00510
00511 return TCL_OK;
00512
00513 BAD_COMMAND:
00514 Tcl_AppendResult(interp,
00515 "wrong # args: should be \"readline option ?arg ...?\"",
00516 (char*) NULL);
00517 return TCL_ERROR;
00518
00519 }
00520
00521 static void
00522 TclReadlineReadHandler(ClientData clientData, int mask)
00523 {
00524 (void)clientData;
00525 if (mask & TCL_READABLE) {
00526 #ifdef EXECUTING_MACRO_HACK
00527 do {
00528 #endif
00529 rl_callback_read_char();
00530 #ifdef EXECUTING_MACRO_HACK
00531
00536 } while (_rl_executing_macro && !TclReadlineLineComplete());
00537 #endif
00538 }
00539 }
00540
00541 static void
00542 TclReadlineLineCompleteHandler(char* ptr)
00543 {
00544 if (!ptr) {
00545
00546 TclReadlineTerminate(LINE_EOF);
00547
00548 } else {
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 char* expansion = (char*) NULL;
00559 int status = history_expand(ptr, &expansion);
00560
00561
00562
00563
00564
00565
00566 if (expansion == NULL && ptr[0] == '\0') {
00567 expansion = strdup("");
00568 }
00569
00570 if (status >= 1) {
00571
00572 printf("%s\n", expansion);
00573 } else if (-1 == status) {
00574 Tcl_AppendResult
00575 (tclrl_interp, "error in history expansion\n", (char*) NULL);
00576 TclReadlineTerminate(TCL_ERROR);
00577 }
00582 Tcl_AppendResult(tclrl_interp, expansion, (char*) NULL);
00583
00584 #ifdef EXECUTING_MACRO_HACK
00585
00589 if(!_rl_executing_macro) {
00590 #endif
00591
00597 if (expansion && *expansion && (!tclrl_last_line ||
00598 strcmp(tclrl_last_line, expansion))) {
00599 add_history(expansion);
00600 }
00601 if (tclrl_last_line)
00602 free(tclrl_last_line);
00603 tclrl_last_line = strdup(expansion);
00604 #ifdef EXECUTING_MACRO_HACK
00605 }
00606 #endif
00607
00610 TclReadlineTerminate(LINE_COMPLETE);
00611 free(ptr);
00612 free(expansion);
00613 }
00614 }
00615
00616 int
00617 Tclreadline_SafeInit(Tcl_Interp *interp)
00618 {
00619 return Tclreadline_Init(interp);
00620 }
00621
00622 int
00623 Tclreadline_Init(Tcl_Interp *interp)
00624 {
00625 int status;
00626 Tcl_CreateCommand(interp, "::tclreadline::readline", TclReadlineCmd,
00627 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
00628 tclrl_interp = interp;
00629 if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::historyLength",
00630 (char*) &tclrl_history_length, TCL_LINK_INT)))
00631 return status;
00632
00633 if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::library",
00634 (char*) &TCLRL_LIBRARY, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00635 return status;
00636 if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::version",
00637 (char*) &TCLRL_VERSION, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00638 return status;
00639 if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::patchLevel",
00640 (char*) &TCLRL_PATCHLEVEL, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00641 return status;
00642 if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::license",
00643 (char*) &tclrl_license, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00644 return status;
00645
00646 if (TCL_OK != (status = Tcl_LinkVar(interp, "tclreadline_library",
00647 (char*) &TCLRL_LIBRARY, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00648 return status;
00649 if (TCL_OK != (status = Tcl_LinkVar(interp, "tclreadline_version",
00650 (char*) &TCLRL_VERSION, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00651 return status;
00652 if (TCL_OK != (status = Tcl_LinkVar(interp, "tclreadline_patchLevel",
00653 (char*) &TCLRL_PATCHLEVEL, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
00654 return status;
00655
00656 return Tcl_PkgProvide(interp, "tclreadline", TCLRL_VERSION);
00657 }
00658
00659 static int
00660 TclReadlineInitialize(Tcl_Interp* interp, char* historyfile)
00661 {
00662 rl_readline_name = "tclreadline";
00663
00664 rl_special_prefixes = "$";
00673
00674
00675
00676
00677 rl_basic_word_break_characters = " \t\n\\@$=;|&[]";
00678 #if 0
00679 rl_basic_quote_characters = "\"{";
00680 rl_completer_quote_characters = "\"";
00681 #endif
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 using_history();
00694 if (!tclrl_eof_string)
00695 tclrl_eof_string = strdup("puts {}; exit");
00696
00697
00698
00699
00700
00701
00702 rl_attempted_completion_function = (CPPFunction *) TclReadlineCompletion;
00703 if (read_history(historyfile)) {
00704 if (write_history(historyfile)) {
00705 Tcl_AppendResult (interp, "warning: `",
00706 historyfile, "' is not writable.", (char*) NULL);
00707 }
00708 }
00709 return TCL_OK;
00710 }
00711
00712 static int
00713 blank_line(char* str)
00714 {
00715 char* ptr;
00716 for (ptr = str; ptr && *ptr; ptr++) {
00717 if (!ISWHITE(*ptr))
00718 return 0;
00719 }
00720 return 1;
00721 }
00722
00723 static char**
00724 TclReadlineCompletion(char* text, int start, int end)
00725 {
00726 char** matches = (char**) NULL;
00727 int status;
00728 rl_completion_append_character = ' ';
00729
00730 if (text && ('!' == text[0]
00731 || (start && rl_line_buffer[start - 1] == '!' ))) {
00732 char* expansion = (char*) NULL;
00733 int oldlen = strlen(rl_line_buffer);
00734 status = history_expand(rl_line_buffer, &expansion);
00735 if (status >= 1) {
00736 rl_extend_line_buffer(strlen(expansion) + 1);
00737 strcpy(rl_line_buffer, expansion);
00738 rl_end = strlen(expansion);
00739 rl_point += strlen(expansion) - oldlen;
00740 free(expansion);
00741
00742
00743
00744
00745
00746
00747 return matches;
00748 }
00749 free(expansion);
00750 }
00751
00752 if (tclrl_custom_completer) {
00753 char start_s[BUFSIZ], end_s[BUFSIZ];
00754 Tcl_Obj* obj;
00755 Tcl_Obj** objv;
00756 int objc;
00757 int state;
00758 char* quoted_text = TclReadlineQuote(text, "$[]{}\"");
00759 char* quoted_rl_line_buffer
00760 = TclReadlineQuote(rl_line_buffer, "$[]{}\"");
00761 sprintf(start_s, "%d", start);
00762 sprintf(end_s, "%d", end);
00763 Tcl_ResetResult(tclrl_interp);
00764 state = Tcl_VarEval(tclrl_interp, tclrl_custom_completer,
00765 " \"", quoted_text, "\" ", start_s, " ", end_s,
00766 " \"", quoted_rl_line_buffer, "\"", (char*) NULL);
00767 free(quoted_text);
00768 free(quoted_rl_line_buffer);
00769 if (TCL_OK != state) {
00770 Tcl_AppendResult (tclrl_interp, " `", tclrl_custom_completer,
00771 " \"", quoted_text, "\" ", start_s, " ", end_s,
00772 " \"", quoted_rl_line_buffer, "\"' failed.", (char*) NULL);
00773 TclReadlineTerminate(state);
00774 return matches;
00775 }
00776 obj = Tcl_GetObjResult(tclrl_interp);
00777 status = Tcl_ListObjGetElements(tclrl_interp, obj, &objc, &objv);
00778 if (TCL_OK != status)
00779 return matches;
00780
00781 if (objc) {
00782 int i, length;
00783 matches = (char**) malloc(sizeof(char*) * (objc + 1));
00784 for (i = 0; i < objc; i++) {
00785 matches[i] = strdup(Tcl_GetStringFromObj(objv[i], &length));
00786 if (1 == objc && !strlen(matches[i])) {
00787 free(matches[i]);
00788 free(matches);
00789 Tcl_ResetResult(tclrl_interp);
00790 return (char**) NULL;
00791 }
00792 }
00793
00801 if (2 == objc && !strlen(matches[1])) {
00802 i--;
00803 free(matches[1]);
00804 rl_completion_append_character = '\0';
00805 }
00806
00807 matches[i] = (char*) NULL;
00808 }
00809 Tcl_ResetResult(tclrl_interp);
00810 }
00811
00812 if (!matches && tclrl_use_builtin_completer) {
00813 matches = rl_completion_matches(text, TclReadline0generator);
00814 }
00815
00816 return matches;
00817 }
00818
00819 static char*
00820 TclReadline0generator(const char* text, int state)
00821 {
00822 return TclReadlineKnownCommands((char*)text, state, _CMD_GET);
00823 }
00824
00825 static char*
00826 TclReadlineKnownCommands(char* text, int state, int mode)
00827 {
00828 static int len;
00829 static cmds_t *cmds = (cmds_t *) NULL, *new;
00830 char* tmp;
00831 char* args[256];
00832 int i, argc;
00833 char** name;
00834
00835 char* local_line = (char*) NULL;
00836 int sub;
00837
00838
00839 switch (mode) {
00840
00841 case _CMD_SET:
00842
00843 new = (cmds_t *) MALLOC(sizeof(cmds_t));
00844 new->next = (cmds_t *) NULL;
00845
00846 if (!cmds) {
00847 cmds = new;
00848 cmds->prev = new;
00849 }
00850 else {
00851 cmds->prev->next = new;
00852 cmds->prev = new;
00853 }
00854
00855 tmp = strdup(text);
00856 argc = TclReadlineParse(args, sizeof(args), tmp);
00857
00858 new->cmd = (char**) MALLOC(sizeof(char*) * (argc + 1));
00859
00860 for (i = 0; i < argc; i++)
00861 new->cmd[i] = args[i];
00862
00863 new->cmd[argc] = (char*) NULL;
00864
00865 return (char*) NULL;
00866 break;
00867
00868
00869 case _CMD_GET:
00870
00871 local_line = strdup(rl_line_buffer);
00872 sub = TclReadlineParse(args, sizeof(args), local_line);
00873
00874 if (0 == sub || (1 == sub && '\0' != text[0])) {
00875 if (!state) {
00876 new = cmds;
00877 len = strlen(text);
00878 }
00879 while (new && (name = new->cmd)) {
00880 new = new->next;
00881 if (!strncmp(name[0], text, len))
00882 return strdup(name[0]);
00883 }
00884 return (char*) NULL;
00885 } else {
00886
00887 if (!state) {
00888
00889 new = cmds;
00890 len = strlen(text);
00891
00892 while (new && (name = new->cmd)) {
00893 if (!strcmp(name[0], args[0]))
00894 break;
00895 new = new->next;
00896 }
00897
00898 if (!new)
00899 return (char*) NULL;
00900
00901 for (i = 0; new->cmd[i]; i++) ;
00902
00903 if (sub < i && !strncmp(new->cmd[sub], text, len))
00904 return strdup(new->cmd[sub]);
00905 else
00906 return (char*) NULL;
00907
00908 }
00909 else
00910 return (char*) NULL;
00911
00912
00913 break;
00914 }
00915
00916
00917 default:
00918 return (char*) NULL;
00919 break;
00920
00921 }
00922
00923 }
00924
00925 static int
00926 TclReadlineParse(char** args, int maxargs, char* buf)
00927 {
00928 int nr = 0;
00929
00930 while (*buf != '\0' && nr < maxargs) {
00931
00932
00933
00934
00935
00936 while (ISWHITE(*buf))
00937 *buf++ = '\0';
00938
00939 if (!(*buf))
00940 break;
00941
00942 *args++ = buf;
00943 nr++;
00944
00945 while (('\0' != *buf) && !ISWHITE(*buf))
00946 buf++;
00947 }
00948
00949 *args = '\0';
00950 return nr;
00951 }
00952
00953 #endif