summaryrefslogblamecommitdiff
path: root/src/user/lib/libc/std/readline.c
blob: 5dfd442cbfc0d62e814de225947e1dc865634031 (plain) (tree)
1
2
3
4
5
6
7


                     

              
                                               
              
































                                                                
                                             

                                    

                                      



                                                                      




















                                                                                                  
                                         






















                                                                                       
                                 
                         
                             









                                                                  
                                        





                                                          
                                                                              









                                                        
                                                           
 



                                   
#include <readline.h>
#include <stdlib.h>

// ** READLINE

char *freadline(FILE *f, readline_history *h) {
	int i;

	if (h->str == 0) {
		h->str = (char**)malloc(h->max * sizeof(char*));
		for (i = 0; i < h->max; i++) h->str[i] = 0;
		h->n = 0;
	}

	int lid;
	if (h->n < h->max) {
		lid = h->n++;
	} else {
		free(h->str[0]);
		int i;
		for (i = 0; i < h->max - 1; i++) {
			h->str[i] = h->str[i+1];
		}
		lid = h->max - 1;
		h->str[lid] = 0;
	}

	if (h->str[lid] == 0) h->str[lid] = (char*)malloc(256);

	char *str = h->str[lid];
	str[0] = 0;
	char *cur = str;	// position in string
	int len = 0;		// string length

	while (1) {
		int finished = 0;

		int te = cur - str;

		char buf[16];
		int l = fread(buf, 16, 1, f);
		if (l < 0) return 0;

		char *in = buf;
		while (in < buf + l) {
			if (*in == 4) {				// eot
				fprintf(f, "^D\n");
				return 0;
			} else if (*in == 27) {
				in++;
				if (*in == '[') {
					in++;
					if (*in == 'A') {			// up
						if (lid > 0) {
							lid--;
							str = h->str[lid];
							len = strlen(str);
							cur = str + len;
						}
					} else if (*in == 'B') {		// down
						if (lid < h->n - 1) {
							lid++;
							str = h->str[lid];
							len = strlen(str);
							cur = str + len;
						}
					} else if (*in == 'C') {		// forward (right)
						if (cur < str + len) cur++;
					} else if (*in == 'D') {		// back (left)
						if (cur > str) cur--;
					}
				} else {
					// ALT sequence - ignore
					in++;
				}
			} else if (*in == '\n') {
				finished = 1;
				cur = str + len;
			} else if (*in == '\b') {
				if (cur > str) {
					cur--;
					len--;
					char* c;
					for (c = cur; *c != 0; c++) c[0] = c[1];
				}
			} else if (*in == '\t') {
				// ignore tabs -- todo: tab completion???? haha
			} else if (*in >= ' ') {
				if (l < 255) {
					char* c;
					for (c = cur + len; c >= cur; c--) c[1] = c[0];
					cur[0] = *in;
					cur++;
					len++;
				}
			}
			in++;
		}

		// ASSUMPTION : everything will fit on one line...
		if (te > 0) fprintf(f, "\x1b[%iD", te);
		fprintf(f, "\x1b[K%s", str);
		te = len - (cur - str);
		if (te > 0) fprintf(f, "\x1b[%iD", te);
		
		
		if (finished) {
			fprint(f, "\n");

			if (h->str[h->n-1] != str) h->n--;

			i = h->n - 1;
			while (h->str[i] != str) {
				if (i == 0) {
					fprint(f, "readline: internal error");
					return 0;
				}
				i--;
			}
			while (i < h->n - 1) {
				h->str[i] = h->str[i+1];
				i++;
			}
			h->str[i] = str;

			if (h->str[h->n-1][0] == 0) h->n--;

			return str;
		}
	}
}