Check-in [357858a659]
Not logged in
Overview
Comment:Made readline an object command to fix a number of memory leaks. Added commands "readline text" to retrieve the current input and "readline update" to redraw the current input.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 357858a65919303bcab6cdceedac43e46af121e4
User & Date: mpatton@jhu.edu on 2000-08-27 13:23:15
Other Links: manifest | tags
Context
2000-08-27
13:25
Updated docs for text and update commands. check-in: 4f73d8af60 user: mpatton@jhu.edu tags: trunk
13:23
Made readline an object command to fix a number of memory leaks. Added commands "readline text" to retrieve the current input and "readline update" to redraw the current input. check-in: 357858a659 user: mpatton@jhu.edu tags: trunk
2000-07-27
13:14
* configure.in: changed a == to = in a sh test (reported by "Daniel O'Connor" <darius@dons.net.au>) check-in: 5096b666f4 user: johannes@zellner.org tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Modified tclreadline.c from [75b74b5625] to [bd4dbca0d1].

67
68
69
70
71
72
73
74


75
76
77
78
79
80
81
67
68
69
70
71
72
73

74
75
76
77
78
79
80
81
82







-
+
+







/* forward declarations. */
static char* stripleft(char* in);
static char* stripright(char* in);
static char* stripwhite(char* in);
static int TclReadlineLineComplete(void);
static void TclReadlineTerminate(int state);
static char* TclReadlineQuote(char* text, char* quotechars);
static int TclReadlineCmd(ClientData clientData, Tcl_Interp* interp, int argc, char** argv);
static int TclReadlineCmd(ClientData clientData, Tcl_Interp *interp, int objc,
                   Tcl_Obj *CONST objv[]);
static void TclReadlineReadHandler(ClientData clientData, int mask);
static void TclReadlineLineCompleteHandler(char* ptr);
static int TclReadlineInitialize(Tcl_Interp* interp, char* historyfile);
static int blank_line(char* str);
static char** TclReadlineCompletion(char* text, int start, int end);
static char* TclReadline0generator(char* text, int state);
static char* TclReadlineKnownCommands(char* text, int state, int mode);
193
194
195
196
197
198
199
200
201


202
203
204
205
206
207
208
209
210
211
212
213
214

215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251



252
253
254
255
256
257
258
194
195
196
197
198
199
200


201
202





203
204

205
206
207
208

209
210
211
212
213
214

215
216

217
218
219








220
221
222
223
224
225
226
227
228

229
230
231
232
233
234
235


236
237
238
239
240
241
242
243
244
245







-
-
+
+
-
-
-
-
-


-




-
+





-
+

-



-
-
-
-
-
-
-
-
+








-







-
-
+
+
+







	}
	Tcl_DStringAppend(&result, ptr, 1);
    }
    result_c = strdup(Tcl_DStringValue(&result));
    return result_c;
}

static int
TclReadlineCmd(
static int TclReadlineCmd(ClientData clientData, Tcl_Interp *interp, int objc,
			  Tcl_Obj *CONST objv[])
    ClientData  clientData,
    Tcl_Interp* interp,     /* Current interpreter */
    int         argc,       /* Number of arguments */
    char**      argv        /* Argument strings    */
	      )
{
    int i, obj_idx, status;
    Tcl_Obj** objv = (Tcl_Obj**) MALLOC((argc + 1) * sizeof(Tcl_Obj *));

    static char *subCmds[] = {
	"read", "initialize", "write", "add", "complete",
	"customcompleter", "builtincompleter", "eofchar",
	"reset-terminal", "bell",
	"reset-terminal", "bell", "text", "update",
	(char *) NULL
    };
    enum SubCmdIdx {
	TCLRL_READ, TCLRL_INITIALIZE, TCLRL_WRITE, TCLRL_ADD, TCLRL_COMPLETE,
	TCLRL_CUSTOMCOMPLETER, TCLRL_BUILTINCOMPLETER, TCLRL_EOFCHAR,
	TCLRL_RESET_TERMINAL, TCLRL_BELL
	TCLRL_RESET_TERMINAL, TCLRL_BELL, TCLRL_TEXT, TCLRL_UPDATE
    };


    Tcl_ResetResult(interp); /* clear the result space */

    for (i = 0;  i < argc;  i++) {
	Tcl_Obj* objPtr = Tcl_NewStringObj(argv[i], -1);
	Tcl_IncrRefCount(objPtr);
	objv[i] = objPtr;
    }
    objv[argc] = 0; /* terminate */

    if (argc < 2) {
    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
	return TCL_ERROR;
    }

    status = Tcl_GetIndexFromObj
    (interp, objv[1], subCmds, "option", 0, (int *) &obj_idx);

    if (status != TCL_OK) {
	FREE(objv)
	return status;
    }

    switch (obj_idx) {

	case TCLRL_READ:

	    rl_callback_handler_install(argc == 3 ? argv[2] : "%",
		TclReadlineLineCompleteHandler);
	    rl_callback_handler_install(
			       objc == 3 ? Tcl_GetStringFromObj(objv[2], 0)
			       : "%", TclReadlineLineCompleteHandler);

	    Tcl_CreateFileHandler(0, TCL_READABLE,
		TclReadlineReadHandler, (ClientData) NULL);

	    /**
	     * Main Loop.
	     * XXX each modification of the global variables
299
300
301
302
303
304
305
306

307
308
309
310


311
312
313
314
315

316
317
318

319
320

321
322
323

324

325
326
327
328
329
330

331
332
333



334
335

336
337
338
339
340

341
342
343

344
345
346
347
348
349
350
351

352
353
354

355
356
357
358



359
360
361
362
363
364

365
366
367

368
369



370
371
372
373
374
375
376
377
378
379
380
381
382
383

384
385
386

387
388
389
390



391
392
393
394
395
396
397

398
399
400
401

402
403

404
405
406
407
408

409
410
411
412
413
414
415
416






417
418
419
420

421
422


























423
424
425
426
427
428
429
286
287
288
289
290
291
292

293
294
295
296

297
298
299
300
301
302

303
304
305

306
307

308
309
310
311
312

313
314
315
316
317
318

319
320
321

322
323
324
325

326
327
328
329
330

331
332
333

334
335
336
337
338
339
340
341

342
343
344

345
346
347


348
349
350
351
352
353
354
355

356
357
358

359
360

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376

377
378
379

380
381
382


383
384
385
386
387
388
389
390
391

392
393
394
395

396
397

398
399
400
401
402

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457







-
+



-
+
+




-
+


-
+

-
+



+
-
+





-
+


-
+
+
+

-
+




-
+


-
+







-
+


-
+


-
-
+
+
+





-
+


-
+

-
+
+
+













-
+


-
+


-
-
+
+
+






-
+



-
+

-
+




-
+








+
+
+
+
+
+




+


+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







		    return tclrl_state;
		    /* NOTREACHED */
		    break;
	    }
	    break;

	case TCLRL_INITIALIZE:
	    if (3 != argc) {
	    if (3 != objc) {
		Tcl_WrongNumArgs(interp, 2, objv, "historyfile");
		return TCL_ERROR;
	    } else {
		return TclReadlineInitialize(interp, argv[2]);
		return TclReadlineInitialize(interp,
					     Tcl_GetStringFromObj(objv[2], 0));
	    }
	    break;

	case TCLRL_WRITE:
	    if (3 != argc) {
	    if (3 != objc) {
		Tcl_WrongNumArgs(interp, 2, objv, "historyfile");
		return TCL_ERROR;
	    }  else if (write_history(argv[2])) {
	    }  else if (write_history(Tcl_GetStringFromObj(objv[2], 0))) {
		Tcl_AppendResult(interp, "unable to write history to `",
		    argv[2], "'\n", (char*) NULL);
		    Tcl_GetStringFromObj(objv[2], 0), "'\n", (char*) NULL);
		return TCL_ERROR;
	    }
	    if (tclrl_history_length >= 0) {
		history_truncate_file(Tcl_GetStringFromObj(objv[2], 0),
		history_truncate_file(argv[2], tclrl_history_length);
				      tclrl_history_length);
	    }
	    return TCL_OK;
	    break;

	case TCLRL_ADD:
	    if (3 != argc) {
	    if (3 != objc) {
		Tcl_WrongNumArgs(interp, 2, objv, "completerLine");
		return TCL_ERROR;
	    } else if (TclReadlineKnownCommands(argv[2], (int) 0, _CMD_SET)) {
	    } else if (TclReadlineKnownCommands(
				     Tcl_GetStringFromObj(objv[2], 0),
				     (int) 0, _CMD_SET)) {
		Tcl_AppendResult(interp, "unable to add command \"",
		    argv[2], "\"\n", (char*) NULL);
		    Tcl_GetStringFromObj(objv[2], 0), "\"\n", (char*) NULL);
	    }
	    break;

	case TCLRL_COMPLETE:
	    if (3 != argc) {
	    if (3 != objc) {
		Tcl_WrongNumArgs(interp, 2, objv, "line");
		return TCL_ERROR;
	    } else if (Tcl_CommandComplete(argv[2])) {
	    } else if (Tcl_CommandComplete(Tcl_GetStringFromObj(objv[2], 0))) {
		Tcl_AppendResult(interp, "1", (char*) NULL);
	    } else {
		Tcl_AppendResult(interp, "0", (char*) NULL);
	    }
	    break;

	case TCLRL_CUSTOMCOMPLETER:
	    if (argc > 3) {
	    if (objc > 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "?scriptCompleter?");
		return TCL_ERROR;
	    } else if (3 == argc) {
	    } else if (3 == objc) {
		if (tclrl_custom_completer)
		    FREE(tclrl_custom_completer);
		if (!blank_line(argv[2]))
		    tclrl_custom_completer = stripwhite(strdup(argv[2]));
		if (!blank_line(Tcl_GetStringFromObj(objv[2], 0)))
		    tclrl_custom_completer =
		         stripwhite(strdup(Tcl_GetStringFromObj(objv[2], 0)));
	    }
	    Tcl_AppendResult(interp, tclrl_custom_completer, (char*) NULL);
	    break;

	case TCLRL_BUILTINCOMPLETER:
	    if (argc > 3) {
	    if (objc > 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
		return TCL_ERROR;
	    } else if (3 == argc) {
	    } else if (3 == objc) {
		int bool = tclrl_use_builtin_completer;
		if (TCL_OK != Tcl_GetBoolean(interp, argv[2], &bool)) {
		if (TCL_OK != Tcl_GetBoolean(interp,
					     Tcl_GetStringFromObj(objv[2], 0),
					     &bool)) {
		    Tcl_AppendResult(interp,
			"wrong # args: should be a boolean value.",
			(char*) NULL);
		    return TCL_ERROR;
		} else {
		    tclrl_use_builtin_completer = bool;
		}
	    }
	    Tcl_AppendResult(interp, tclrl_use_builtin_completer ? "1" : "0",
		(char*) NULL);
	    break;

	case TCLRL_EOFCHAR:
	    if (argc > 3) {
	    if (objc > 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "?script?");
		return TCL_ERROR;
	    } else if (3 == argc) {
	    } else if (3 == objc) {
		if (tclrl_eof_string)
		    FREE(tclrl_eof_string);
		if (!blank_line(argv[2]))
		    tclrl_eof_string = stripwhite(strdup(argv[2]));
		if (!blank_line(Tcl_GetStringFromObj(objv[2], 0)))
		    tclrl_eof_string = 
		        stripwhite(strdup(Tcl_GetStringFromObj(objv[2], 0)));
	    }
	    Tcl_AppendResult(interp, tclrl_eof_string, (char*) NULL);
	    break;

	case TCLRL_RESET_TERMINAL:
	    /* TODO: add this to the completer */
	    if (argc > 3) {
	    if (objc > 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "?terminal-name?");
		return TCL_ERROR;
	    }
	    if (3 == argc) {
	    if (3 == objc) {
		/*
		 * - tcl8.0 doesn't have Tcl_GetString()
		 * - tcl8.0 doesn't have Tcl_GetStringFromObj()
		 * - rl_reset_terminal() might be defined
		 *   to take no arguments. This might produce
		 *   a compiler warning.
		 */
		rl_reset_terminal(Tcl_GetStringFromObj(objv[2], (int*) NULL));
		rl_reset_terminal(Tcl_GetStringFromObj(objv[2], 0));
#ifdef CLEANUP_AFER_SIGNAL
	    } else {
		rl_cleanup_after_signal();
#endif
	    }
	    break;

	case TCLRL_BELL:
	    if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, "");
		return TCL_ERROR;
	    }


	    /*
	     * ring the terminal bell obeying the current
	     * settings -- audible or visible.
	     */

	    ding();
	    break;

        case TCLRL_UPDATE:
	    if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, "");
		return TCL_ERROR;
	    }

	    /* Update the input line */

	    if (rl_line_buffer) {
	        rl_forced_update_display();
	    }

	    break;


        case TCLRL_TEXT:
	    if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, "");
		return TCL_ERROR;
	    }

	    /* Return the current input line */
	    Tcl_SetObjResult(interp,
		   Tcl_NewStringObj(rl_line_buffer ? rl_line_buffer : "", -1));
	    break;

	default:
	    goto BAD_COMMAND;
	    /* NOTREACHED */
	    break;
    }

528
529
530
531
532
533
534
535

536
537
538
539
540
541
542
556
557
558
559
560
561
562

563
564
565
566
567
568
569
570







-
+







    return Tclreadline_Init(interp);
}

int
Tclreadline_Init(Tcl_Interp *interp)
{
    int status;
    Tcl_CreateCommand(interp, "::tclreadline::readline", TclReadlineCmd,
    Tcl_CreateObjCommand(interp, "::tclreadline::readline", TclReadlineCmd,
	(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
    tclrl_interp = interp;
    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::historyLength",
		(char*) &tclrl_history_length, TCL_LINK_INT)))
	return status;

    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::library",