src/dietline.c
author pancake
Sat Nov 05 00:46:43 2011 +0100 (6 months ago)
changeset 1294 b761aed74540
parent 1245 563178270848
permissions -rw-r--r--
* Apply zlowram's book typos patch
* Minor fixes to build in osx
     1 /*
     2  * Copyright (C) 2007, 2008, 2009
     3  *       pancake <youterm.com>
     4  *
     5  * dietline is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * dietline is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with dietline; if not, write to the Free Software
    17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18  *
    19  */
    20 
    21 #include "dietline.h"
    22 
    23 /* dietline is a lighweight and portable library similar to GNU readline */
    24 
    25 #if RADARE_CORE
    26 #include "main.h"
    27 #else
    28 static void cons_set_raw(int b);
    29 static int cons_get_real_columns();
    30 #define __UNIX__ 1
    31 #endif
    32 
    33 #include <string.h>
    34 #include <stdlib.h>
    35 
    36 #if __WINDOWS__
    37 #include <windows.h>
    38 #else
    39 #include <sys/ioctl.h>
    40 #include <termios.h>
    41 #include <signal.h>
    42 #endif
    43 
    44 /* line input */
    45 int dl_echo = 1;
    46 const char *dl_prompt = "> ";
    47 const char *dl_clipboard = NULL;
    48 static char *dl_nullstr = "";
    49 static char dl_buffer[DL_BUFSIZE];
    50 static int dl_buffer_len = 0;
    51 static int dl_buffer_idx = 0;
    52 
    53 /* autocompletion callback */
    54 char **(*dl_callback)(const char *text, int start, int end) = NULL;
    55 
    56 /* history */
    57 char **dl_history = NULL;
    58 int dl_histsize = DL_HISTSIZE;
    59 int dl_histidx = 0;
    60 int dl_autosave = 0; // TODO
    61 int dl_disable = 0; // TODO use fgets..no autocompletion
    62 
    63 // TODO : FULL READLINE COMPATIBILITY
    64 // rl_attempted_completion_function = rad_autocompletion;
    65 // char **rad_autocompletion(const char *text, int start, int end)
    66 // return  matches = rl_completion_matches (text, rad_offset_matches);
    67 
    68 int dl_readchar()
    69 {
    70 	char buf[2];
    71 #if __WINDOWS__
    72 	LPDWORD out;
    73 	BOOL ret;
    74 	DWORD mode;
    75 	HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
    76 
    77 	GetConsoleMode(h, &mode);
    78 	SetConsoleMode(h, 0); // RAW
    79 	ret = ReadConsole(h, buf,1, &out, NULL);
    80 	if (!ret) {
    81 		// wine hack-around
    82 		if (read(0,buf,1) == 1)
    83 			return buf[0];
    84 		return -1;
    85 	}
    86 	SetConsoleMode(h, mode);
    87 #else
    88 	int ret = read(0,buf,1);
    89 	if (ret <1)
    90 		return -1;
    91 #endif
    92 	return buf[0];
    93 }
    94 
    95 /* scripting */
    96 
    97 #define BLOCK 4096
    98 static char *labels = NULL;
    99 static unsigned int size = 0;
   100 static unsigned int lsize = 0;
   101 
   102 static int label_get(const char *name)
   103 {
   104 	int i, n;
   105 	for(i=0;i<size;i++) {
   106 		if (!strcmp(name, labels+i+4)) {
   107 			memcpy(&n, labels+i, 4);
   108 			return n;
   109 		}
   110 		i+=strlen(labels+i+4)+4;
   111 	}
   112 	return -1;
   113 }
   114 
   115 static void label_add (const char *str) {
   116 	unsigned int size = dl_histidx;
   117 	unsigned int len = strlen(str)-1;
   118 
   119 	//eprintf("New label(%s)\n",str);
   120 	memset(labels+lsize+4, '\0', BLOCK-((lsize+len+4)%BLOCK));
   121 	memcpy(labels+lsize, &size, 4);
   122 	memcpy(labels+lsize+4, str, len);
   123 	lsize+=len+4+1;
   124 }
   125 
   126 void dl_label_show()
   127 {
   128 	unsigned int i, p, n = 0;
   129 	for(i=0;i<lsize;i++,n++) {
   130 		memcpy(&p, labels+i, 4);
   131 		printf(" %03d %03d  %s\n", i, p, labels+i+4);
   132 		i+=strlen(labels+i+4)+4;
   133 	}
   134 }
   135 
   136 static void label_reset()
   137 {
   138 	lsize = 0;
   139 	free(labels);
   140 	labels = NULL;
   141 }
   142 
   143 static int is_label(const char *str)
   144 {
   145 	/* crappy hack */
   146 	return 0;
   147 
   148 	if (str[0]=='\0')
   149 		return 0;
   150 	if (str[strlen(str)-1]==':') {
   151 		if (str[0]==':') {
   152 			dl_label_show();
   153 			return 2;
   154 		}
   155 		return 1;
   156 	}
   157 	return 0;
   158 }
   159 
   160 /* history stuff */
   161 
   162 int dl_hist_label(const char *label, void (*cb)(const char*))
   163 {
   164 	int i;
   165 #if 1
   166 	/* labelling stuff */
   167 	if (label[0]=='.') {
   168 		if (!is_label(label+1))
   169 			return 0;
   170 	} else {
   171 		switch(is_label(label)) {
   172 		case 0:
   173 		case 2:
   174 			return 0;
   175 		}
   176 	}
   177 
   178 	i = label_get(label);
   179 	if (i == -1) {
   180 		label_add(label);
   181 		return 1;
   182 	}
   183 #endif
   184 	if (dl_history != NULL)
   185 	for(i=0; i<dl_histsize; i++) {
   186 		if (dl_history[i] == NULL)
   187 			break;
   188 		fprintf(stderr, "%s\n", dl_history[i]);
   189 		if (cb != NULL)
   190 			cb(dl_history[i]);
   191 		else	fprintf(stderr, "%s\n", dl_history[i]);
   192 	}
   193 
   194 	return 1;
   195 }
   196 
   197 int dl_hist_add(const char *line)
   198 {
   199 #if HAVE_LIB_READLINE
   200 	add_history(line);
   201 #endif
   202 	if (dl_histidx>=dl_histsize)
   203 		dl_histidx = 0; // workaround
   204 	if (*line) { // && dl_histidx < dl_histsize) {
   205 		dl_history[dl_histidx++] = strdup(line);
   206 		return 1;
   207 	}
   208 	return 0;
   209 //#endif
   210 }
   211 
   212 int dl_hist_up()
   213 {
   214 	if (dl_histidx>0) {
   215 		strncpy(dl_buffer, dl_history[--dl_histidx], DL_BUFSIZE-1);
   216 		dl_buffer_idx=
   217 		dl_buffer_len = strlen(dl_buffer);
   218 		return 1;
   219 	}
   220 	return 0;
   221 }
   222 
   223 int dl_hist_down()
   224 {
   225 	dl_buffer_idx=0;
   226 	if (dl_histidx<dl_histsize) {
   227 		if (dl_history[dl_histidx] == NULL) {
   228 			dl_buffer[0]='\0';
   229 			dl_buffer_idx = dl_buffer_len = 0;
   230 			return 0;
   231 		}
   232 		strncpy(dl_buffer, dl_history[dl_histidx++], DL_BUFSIZE-1);
   233 		dl_buffer_idx=
   234 		dl_buffer_len = strlen(dl_buffer);
   235 		return 1;
   236 	}
   237 	return 0;
   238 }
   239 
   240 int dl_hist_list()
   241 {
   242 	int i = 0;
   243 
   244 	if (dl_history != NULL)
   245 	for(i=0;i<dl_histsize; i++) {
   246 		if (dl_history[i] == NULL)
   247 			break;
   248 		printf("%.3d  %s\n", i, dl_history[i]);
   249 	}
   250 
   251 	return i;
   252 }
   253 
   254 int dl_hist_free()
   255 {
   256 	int i;
   257 	if (dl_history != NULL)
   258 	for(i=0;i<dl_histsize; i++) {
   259 		free(dl_history[i]);
   260 		dl_history[i] = NULL;
   261 	}
   262 	return dl_histidx=0, dl_histsize;
   263 }
   264 
   265 void dl_free()
   266 {
   267 	printf("Bye!\n");
   268 	dl_hist_free();
   269 	label_reset();
   270 	free(dl_history);
   271 }
   272 
   273 /* load history from file. if file == NULL load from ~/.<prg>.history or so */
   274 int dl_hist_load(const char *file)
   275 {
   276 #if HAVE_LIB_READLINE
   277 	rad_readline_init();
   278 	return 0;
   279 #else
   280 	char buf[1024];
   281 	FILE *fd;
   282 
   283 	snprintf(buf, 1023, "%s/%s", get_home_directory(), file);
   284 	fd = fopen(buf, "r");
   285 	if (fd == NULL)
   286 		return 0;
   287 
   288 	fgets(buf, 1023, fd);
   289 	while (!feof(fd)) {
   290 		buf[strlen(buf)-1]='\0';
   291 		dl_hist_add(buf);
   292 		fgets(buf, 1023, fd);
   293 	}
   294 	fclose(fd);
   295 	return 1;
   296 #endif
   297 }
   298 
   299 int dl_hist_save(const char *file)
   300 {
   301 #if HAVE_LIB_READLINE
   302 	return rad_readline_finish();
   303 #else
   304 	char buf[1024];
   305 	FILE *fd;
   306 	int i;
   307 
   308 	snprintf(buf, 1023, "%s/%s", get_home_directory(), file);
   309 	fd = fopen(buf, "w");
   310 	if (fd == NULL)
   311 		return 0;
   312 	for(i=0;i<dl_histidx;i++) {
   313 		fputs(dl_history[i], fd);
   314 		fputs("\n", fd);
   315 	}
   316 	fclose(fd);
   317 	
   318 	return 1;
   319 #endif
   320 }
   321 
   322 int dl_hist_chop(const char *file, int limit)
   323 {
   324 	/* TODO */
   325 	return 0;
   326 }
   327 
   328 /* initialize history stuff */
   329 int dl_init()
   330 {
   331 #if HAVE_LIB_READLINE
   332 	rad_readline_init();
   333 #endif
   334 	if (labels==NULL)
   335 		labels = malloc(BLOCK);
   336 	dl_history = (char **)malloc(dl_histsize*sizeof(char *));
   337 	if (dl_history==NULL)
   338 		return 0;
   339 	memset(dl_history, '\0', dl_histsize*sizeof(char *));
   340 	dl_histidx = 0;
   341 	dl_histsize = DL_HISTSIZE;
   342 	dl_histidx = 0;
   343 	dl_autosave = 0;
   344 	dl_disable = 0;
   345 	return 1;
   346 }
   347 
   348 /* test */
   349 int dl_printchar()
   350 {
   351 	unsigned char buf[10];
   352 
   353 	cons_set_raw(1);
   354 	buf[0]=dl_readchar();
   355 
   356 	switch(buf[0]) {
   357 		case 226:
   358 		case 197:
   359 		case 195:
   360 		case 194:
   361 			buf[0] = dl_readchar();
   362 			printf("unicode-%02x-%02x\n", buf[0],buf[1]);
   363 			break;
   364 		case 8: // wtf is 127?
   365 		case 127: printf("backspace\n"); break;
   366 		case 32: printf("space\n"); break;
   367 		case 27:
   368 			read(0, buf, 5);
   369 			printf("esc-%02x-%02x-%02x-%02x\n",
   370 					buf[0],buf[1],buf[2],buf[3]);
   371 			break;
   372 		case 12: printf("^L\n"); break;
   373 		case 13: printf("intro\n"); break;
   374 		case 18: printf("^R\n"); break;
   375 		case 9: printf("tab\n"); break;
   376 		case 3: printf("control-c\n"); break;
   377 		case 0: printf("control-space\n"); break;
   378 		default:
   379 			printf("(code:%d)\n", buf[0]);
   380 			break;
   381 	}
   382 
   383 	cons_set_raw(0);
   384 
   385 	return buf[0];
   386 }
   387 
   388 /* main readline function */
   389 char *dl_readline(int argc, const char **argv)
   390 {
   391 	int buf[10];
   392 	int i, len = 0;
   393 	int opt = 0;
   394 	int columns = cons_get_real_columns()-2;
   395 
   396 	dl_buffer_idx = dl_buffer_len = 0;
   397 	dl_buffer[0]='\0';
   398 
   399 #if RADARE_CORE
   400 	dl_echo = config.verbose;
   401 #endif
   402 
   403 	if (dl_disable) {
   404 		dl_buffer[0]='\0';
   405 		fgets(dl_buffer, DL_BUFSIZE-1, stdin);
   406 		dl_buffer[strlen(dl_buffer)] = '\0';
   407 		return (*dl_buffer)? dl_buffer : NULL;
   408 	}
   409 
   410 	memset(&buf,0,sizeof buf);
   411 	cons_set_raw(1);
   412 
   413 	if (dl_echo) {
   414 		printf("%s", dl_prompt);
   415 		fflush(stdout);
   416 	}
   417 
   418 #if __UNIX__
   419 	if (feof(stdin))
   420 		return NULL;
   421 #endif
   422 
   423 	while(1) {
   424 #if 0
   425 		if (dl_echo) {
   426 			printf("  (");
   427 			for(i=1;i<argc;i++) {
   428 				if (dl_buffer_len==0||!strncmp(argv[i], dl_buffer, dl_buffer_len)) {
   429 					len+=strlen(argv[i])+1;
   430 					if (len+dl_buffer_len+4 >= columns) break;
   431 					printf("%s ", argv[i]);
   432 				}
   433 			}
   434 			printf(")");
   435 			fflush(stdout);
   436 		}
   437 #endif
   438 
   439 		dl_buffer[dl_buffer_len]='\0';
   440 		buf[0] = dl_readchar();
   441 		
   442 //		printf("\x1b[K\r");
   443 		columns = cons_get_real_columns()-2;
   444 		if (columns <1)
   445 			columns = 40;
   446 		if (dl_echo)
   447 		printf("\r%*c\r", columns, ' ');
   448 
   449 		switch(buf[0]) {
   450 			case -1:
   451 				return NULL;
   452 			case 0: // control-space
   453 				/* ignore atm */
   454 				break;
   455 			case 1: // ^A
   456 				dl_buffer_idx = 0;
   457 				break;
   458 			case 5: // ^E
   459 				dl_buffer_idx = dl_buffer_len;
   460 				break;
   461 			case 3: // ^C 
   462 				if (dl_echo)
   463 					printf("\n^C\n");
   464 				dl_buffer[dl_buffer_idx = dl_buffer_len = 0] = '\0';
   465 				goto _end;
   466 			case 4: // ^D
   467 				if (dl_echo)
   468 					printf("^D\n");
   469 				if (!dl_buffer[0]) { /* eof */
   470 					cons_set_raw(0);
   471 					return NULL;
   472 				}
   473 				break;
   474 			case 10: // ^J -- ignore
   475 				return dl_buffer;
   476 			case 11: // ^K -- ignore
   477 				break;
   478 			case 19: // ^S -- backspace
   479 				dl_buffer_idx = dl_buffer_idx?dl_buffer_idx-1:0;
   480 				break;
   481 			case 12: // ^L -- right
   482 				dl_buffer_idx = dl_buffer_idx<dl_buffer_len?dl_buffer_idx+1:dl_buffer_len;
   483 				if (dl_echo)
   484 					printf("\x1b[2J\x1b[0;0H");
   485 				fflush(stdout);
   486 				break;
   487 			case 21: // ^U - cut
   488 				dl_clipboard = strdup(dl_buffer);
   489 				dl_buffer[0]='\0';
   490 				dl_buffer_len = 0;
   491 				dl_buffer_idx = 0;
   492 				break;
   493 			case 23: // ^W
   494 				if (dl_buffer_idx>0) {
   495 					for(i=dl_buffer_idx-1;i&&dl_buffer[i]==' ';i--);
   496 					for(;i&&dl_buffer[i]!=' ';i--);
   497 					for(;i>0&&dl_buffer[i]==' ';i--);
   498 					if (i>1) {
   499 						if (dl_buffer[i+1]==' ')
   500 						i+=2;
   501 					} else if (i<0) i=0;
   502 					strcpy(dl_buffer+i, dl_buffer+dl_buffer_idx);
   503 					dl_buffer_len = strlen(dl_buffer);
   504 					dl_buffer_idx = i;
   505 				}
   506 				break;
   507 			case 25: // ^Y - paste
   508 				if (dl_clipboard != NULL) {
   509 					dl_buffer_len += strlen(dl_clipboard);
   510 					// TODO: support endless strings
   511 					if (dl_buffer_len < DL_BUFSIZE) {
   512 						dl_buffer_idx = dl_buffer_len;
   513 						strcat(dl_buffer, dl_clipboard);
   514 					} else dl_buffer_len -= strlen(dl_clipboard);
   515 				}
   516 				break;
   517 			case 16:
   518 				dl_hist_up();
   519 				break;
   520 			case 14:
   521 				dl_hist_down();
   522 				break;
   523 			case 27: //esc-5b-41-00-00
   524 				buf[0] = dl_readchar();
   525 				buf[1] = dl_readchar();
   526 				if (buf[0]==0x5b) {
   527 					switch(buf[1]) {
   528 					case 0x33: // supr
   529 						if (dl_buffer_idx<dl_buffer_len)
   530 							strcpy(dl_buffer, dl_buffer+1);
   531 						break;
   532 					/* arrows */
   533 					case 0x41:
   534 						dl_hist_up();
   535 						break;
   536 					case 0x42:
   537 						dl_hist_down();
   538 						break;
   539 					case 0x43:
   540 						dl_buffer_idx = dl_buffer_idx<dl_buffer_len?dl_buffer_idx+1:dl_buffer_len;
   541 						break;
   542 					case 0x44:
   543 						dl_buffer_idx = dl_buffer_idx?dl_buffer_idx-1:0;
   544 						break;
   545 					}
   546 				}
   547 
   548 				break;
   549 			case 8:
   550 			case 127:
   551 				if (dl_buffer_idx < dl_buffer_len) {
   552 					if (dl_buffer_idx>0) {
   553 						dl_buffer_idx--;
   554 						memcpy(dl_buffer+dl_buffer_idx, dl_buffer+dl_buffer_idx+1,strlen(dl_buffer+dl_buffer_idx));
   555 					}
   556 				} else {
   557 					dl_buffer_idx = --dl_buffer_len;
   558 					if (dl_buffer_len<0) dl_buffer_len=0;
   559 					dl_buffer[dl_buffer_len]='\0';
   560 				}
   561 				if (dl_buffer_idx<0)
   562 					dl_buffer_idx = 0;
   563 				break;
   564 			case 9:// tab
   565 				/* autocomplete */
   566 				// XXX does not autocompletes correctly
   567 				// XXX needs to check if valid results have the same prefix (from 1 to N)
   568 				if (dl_callback != NULL) {
   569 					//const char *from = strrchr(dl_buffer, ' ');
   570 					//char **res = dl_callback(dl_buffer, (from==NULL)?dl_buffer_idx:from-dl_buffer, dl_buffer_len);
   571 					/* TODO: manage res */
   572 				} else {
   573 					if (dl_buffer_idx>0)
   574 					for(i=1,opt=0;i<argc;i++)
   575 						if (!strncmp(argv[i], dl_buffer, dl_buffer_idx))
   576 							opt++;
   577 
   578 					if (dl_buffer_len>0&&opt==1)
   579 						for(i=1;i<argc;i++) {
   580 							if (!strncmp(dl_buffer, argv[i], dl_buffer_len)) {
   581 								strcpy(dl_buffer, argv[i]);
   582 								dl_buffer_idx = dl_buffer_len = strlen(dl_buffer);
   583 								// TODO: if only 1 keyword hits:
   584 								//		if (argv[i][dl_buffer_len]=='\0') {
   585 								//			strcat(dl_buffer, " ");
   586 								//			dl_buffer_len++;
   587 								//		}
   588 								break;
   589 							}
   590 						}
   591 
   592 					/* show options */
   593 					if (dl_buffer_idx==0 || opt>1) {
   594 						if (dl_echo)
   595 							printf("%s%s\n",dl_prompt,dl_buffer);
   596 						for(i=1;i<argc;i++) {
   597 							if (dl_buffer_len==0||!strncmp(argv[i], dl_buffer, dl_buffer_len)) {
   598 								len+=strlen(argv[i]);
   599 					//			if (len+dl_buffer_len+4 >= columns) break;
   600 								if (dl_echo)
   601 									printf("%s ", argv[i]);
   602 							}
   603 						}
   604 						if (dl_echo)
   605 							printf("\n");
   606 					}
   607 					fflush(stdout);
   608 				}
   609 				break;
   610 			case 18:
   611 				// TODO: SUPPORT FOR ^R (search command in history)
   612 				break;
   613 			case 13: 
   614 				goto _end;
   615 #if 0
   616 				// force command fit
   617 				for(i=1;i<argc;i++) {
   618 					if (dl_buffer_len==0 || !strncmp(argv[i], dl_buffer, dl_buffer_len)) {
   619 						printf("%*c", columns, ' ');
   620 						printf("\r");
   621 						printf("\n\n(%s)\n\n", dl_buffer);
   622 						cons_set_raw(0);
   623 						return dl_buffer;
   624 					}
   625 				}
   626 #endif
   627 			default:
   628 				/* XXX use ^A & ^E */
   629 				if (dl_buffer_idx<dl_buffer_len) {
   630 					for(i = ++dl_buffer_len;i>dl_buffer_idx;i--)
   631 						dl_buffer[i] = dl_buffer[i-1];
   632 					dl_buffer[dl_buffer_idx] = buf[0];
   633 				} else {
   634 					dl_buffer[dl_buffer_len]=buf[0];
   635 					dl_buffer_len++;
   636 					if (dl_buffer_len>1000)
   637 						dl_buffer_len--;
   638 					dl_buffer[dl_buffer_len]='\0';
   639 				}
   640 				dl_buffer_idx++;
   641 				break;
   642 		}
   643 		if (dl_echo) {
   644 			printf("\r%s%s", dl_prompt, dl_buffer);
   645 			printf("\r%s", dl_prompt);
   646 		
   647 			for(i=0;i<dl_buffer_idx;i++)
   648 				printf("%c", dl_buffer[i]);
   649 			fflush(stdout);
   650 		}
   651 	}
   652 
   653 _end:
   654 	cons_set_raw(0);
   655 	if (dl_echo) {
   656 		printf("\r%s%s\n", dl_prompt, dl_buffer);
   657 		fflush(stdout);
   658 	}
   659 
   660 	if (dl_buffer[0]=='!' && dl_buffer[1]=='\0') {
   661 		dl_hist_list();
   662 		return dl_nullstr;
   663 	}
   664 	//write(1,"\n",1);
   665 	return dl_buffer;
   666 }
   667 
   668 #ifndef RADARE_CORE
   669 
   670 
   671 #if __UNIX__
   672 static struct termios tio_old, tio_new;
   673 #include "main.h"
   674 #include <stdarg.h>
   675 #include <termios.h>
   676 #include <sys/ioctl.h>
   677 #include <sys/wait.h>
   678 #include <sys/socket.h>
   679 #endif
   680 
   681 static void cons_set_raw(int b)
   682 {
   683 #if __UNIX__
   684 	if (b) {
   685 		tcgetattr(0, &tio_old);
   686 		memcpy ((char *)&tio_new, (char *)&tio_old, sizeof(struct termios));
   687 		tio_new.c_iflag &= ~(BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
   688 		tio_new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
   689 		tio_new.c_cflag &= ~(CSIZE|PARENB);
   690 		tio_new.c_cflag |= CS8;
   691 		tio_new.c_cc[VMIN]=1; // Solaris stuff hehe
   692 		tcsetattr(0, TCSANOW, &tio_new);
   693 		fflush(stdout);
   694 		return;
   695 	}
   696 
   697 	tcsetattr(0, TCSANOW, &tio_old);
   698 	fflush(stdout);
   699 #endif
   700 }
   701 
   702 static int cons_get_real_columns()
   703 {
   704 #if __WINDOWS__
   705         return 78;
   706 #endif
   707         struct winsize win;
   708 
   709         if (ioctl(1, TIOCGWINSZ, &win)) {
   710                 /* default values */
   711 //                win.ws_col = 80;
   712  //               win.ws_row = 23;
   713         }
   714 
   715         return win.ws_col;
   716 }
   717 
   718 int main(int argc, const char **argv)
   719 {
   720 	char *ret;
   721 
   722 	dl_histsize = 100;
   723 	dl_prompt = "$ ";
   724 	dl_init();
   725 
   726 	dl_printchar();
   727 
   728 	do {
   729 		ret = dl_readline(argc, argv);
   730 		if (ret) {
   731 			printf(" [line] '%s'\n", ret);
   732 			dl_hist_add(ret);
   733 		}
   734 	} while(ret!=NULL);
   735 	dl_free();
   736 	return 0;
   737 }
   738 
   739 #endif