Ejemplo n.º 1
0
static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, size_t *len, size_t *pos, size_t cols) {
    linenoiseCompletions lc = { 0, NULL };
    int nwritten;
    char c = 0;

    completionCallback(buf,&lc);
    if (lc.len == 0) {
        beep();
    } else {
        size_t stop = 0, i = 0;
        size_t clen;

        while(!stop) {
            /* Show completion or original buffer */
            if (i < lc.len) {
                clen = strlen(lc.cvec[i]);
                refreshLine(fd,prompt,lc.cvec[i],clen,clen,cols);
            } else {
                refreshLine(fd,prompt,buf,*len,*pos,cols);
            }

            do {
                c = linenoiseReadChar(fd);
            } while (c == (char)-1);

            switch(c) {
                case 0:
                    freeCompletions(&lc);
                    return -1;
                case 9: /* tab */
                    i = (i+1) % (lc.len+1);
                    if (i == lc.len) beep();
                    break;
                case 27: /* escape */
                    /* Re-show original buffer */
                    if (i < lc.len) {
                        refreshLine(fd,prompt,buf,*len,*pos,cols);
                    }
                    stop = 1;
                    break;
                default:
                    /* Update buffer and return */
                    if (i < lc.len) {
                        nwritten = snprintf(buf,buflen,"%s",lc.cvec[i]);
                        *len = *pos = nwritten;
                    }
                    stop = 1;
                    break;
            }
        }
    }

    freeCompletions(&lc);
    return c; /* Return last read character */
}
Ejemplo n.º 2
0
static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) {
    size_t plen = strlen(prompt);
    size_t pos = 0;
    size_t len = 0;
    size_t cols = getColumns();

    buf[0] = '\0';
    buflen--; /* Make sure there is always space for the nulterm */

    /* The latest history entry is always our current buffer, that
     * initially is just an empty string. */
    linenoiseHistoryAdd("");
    history_index = history_len-1;
    
    if (write(1,prompt,plen) == -1) return -1;
    while(1) {
        char c = linenoiseReadChar(fd);

        if (c == 0) return len;
        if (c == (char)-1) {
            refreshLine(fd,prompt,buf,len,pos,cols);
            continue;
        }

        /* Only autocomplete when the callback is set. It returns < 0 when
         * there was an error reading from fd. Otherwise it will return the
         * character that should be handled next. */
        if (c == 9 && completionCallback != NULL) {
            c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols);
            /* Return on errors */
            if (c < 0) return len;
            /* Read next character when 0 */
            if (c == 0) continue;
        }

        switch(c) {
        case 13:    /* enter */
            history_len--;
            free(history[history_len]);
            return (int)len;
        case 3:     /* ctrl-c */
            errno = EAGAIN;
            return -1;
        case 127:   /* delete */
            if (len > 0 && pos < len) {
                memmove(buf+pos,buf+pos+1,len-pos-1);
                len--;
                buf[len] = '\0';
                refreshLine(fd,prompt,buf,len,pos,cols);
            }
            break;
        case 8:     /* backspace or ctrl-h */
            if (pos > 0 && len > 0) {
                memmove(buf+pos-1,buf+pos,len-pos);
                pos--;
                len--;
                buf[len] = '\0';
                refreshLine(fd,prompt,buf,len,pos,cols);
            }
            break;
        case 4:     /* ctrl-d, remove char at right of cursor */
            if (len > 1 && pos < (len-1)) {
                memmove(buf+pos,buf+pos+1,len-pos);
                len--;
                buf[len] = '\0';
                refreshLine(fd,prompt,buf,len,pos,cols);
            } else if (len == 0) {
                history_len--;
                free(history[history_len]);
                return -1;
            }
            break;
        case 20:    /* ctrl-t */
            if (pos > 0 && pos < len) {
                int aux = buf[pos-1];
                buf[pos-1] = buf[pos];
                buf[pos] = aux;
                if (pos != len-1) pos++;
                refreshLine(fd,prompt,buf,len,pos,cols);
            }
            break;
        case 2:     /* ctrl-b */ /* left arrow */
            if (pos > 0) {
                pos--;
                refreshLine(fd,prompt,buf,len,pos,cols);
            }
            break;
        case 6:     /* ctrl-f */
            /* right arrow */
            if (pos != len) {
                pos++;
                refreshLine(fd,prompt,buf,len,pos,cols);
            }
            break;
        case 16:    /* ctrl-p */
        case 14:    /* ctrl-n */
            /* up and down arrow: history */
            if (history_len > 1) {
                /* Update the current history entry before to
                 * overwrite it with tne next one. */
                free(history[history_index]);
                history[history_index] = strdup(buf);
                /* Show the new entry */
                history_index += (c == 16) ? -1 : 1;
                if (history_index < 0) {
                    history_index = 0;
                    break;
                } else if (history_index >= history_len) {
                    history_index = history_len-1;
                    break;
                }
                strncpy(buf,history[history_index],buflen);
                buf[buflen] = '\0';
                len = pos = strlen(buf);
                refreshLine(fd,prompt,buf,len,pos,cols);
            }
            break;
        case 27:    /* escape sequence */
            break; /* should be handled by linenoiseReadChar */
        default:
            if (len < buflen) {
                if (len == pos) {
                    buf[pos] = c;
                    pos++;
                    len++;
                    buf[len] = '\0';
                    if (plen+len < cols) {
                        /* Avoid a full update of the line in the
                         * trivial case. */
                        if (write(1,&c,1) == -1) return -1;
                    } else {
                        refreshLine(fd,prompt,buf,len,pos,cols);
                    }
                } else {
                    memmove(buf+pos+1,buf+pos,len-pos);
                    buf[pos] = c;
                    len++;
                    pos++;
                    buf[len] = '\0';
                    refreshLine(fd,prompt,buf,len,pos,cols);
                }
            }
            break;
        case 21: /* Ctrl+u, delete the whole line. */
            buf[0] = '\0';
            pos = len = 0;
            refreshLine(fd,prompt,buf,len,pos,cols);
            break;
        case 11: /* Ctrl+k, delete from current to end of line. */
            buf[pos] = '\0';
            len = pos;
            refreshLine(fd,prompt,buf,len,pos,cols);
            break;
        case 1: /* Ctrl+a, go to the start of the line */
            pos = 0;
            refreshLine(fd,prompt,buf,len,pos,cols);
            break;
        case 5: /* ctrl+e, go to the end of the line */
            pos = len;
            refreshLine(fd,prompt,buf,len,pos,cols);
            break;
        case 12: /* ctrl+l, clear screen */
            linenoiseClearScreen();
            refreshLine(fd,prompt,buf,len,pos,cols);
        }
    }
    return len;
}
Ejemplo n.º 3
0
int main(void)
{
    int epollFD;

    epollFD = epoll_create1(EPOLL_CLOEXEC);
    if (epollFD < 0) {
	printf("Failed to create epollFD: %m\n");
	exit(1);
    }

    struct epoll_event ev = {
	.events = EPOLLIN | EPOLLPRI,
	.data.fd = STDIN_FILENO };
    int ret = epoll_ctl(epollFD, EPOLL_CTL_ADD, ev.data.fd, &ev);
    if (ret < 0) {
	printf("epoll_ctl() failed: %m\n");
	exit(1);
    }

    linenoiseSetHandlerCallback(NULL, callback);
    linenoiseSetPrompt("input>");
    linenoiseForcedUpdateDisplay();

    while(!stopped) {
#define MAX_EVENTS 10
	struct epoll_event events[MAX_EVENTS];

	int nfds = epoll_wait(epollFD, events, MAX_EVENTS, -1);

	if (nfds < 0 ) {
	    printf("epoll_wait: %m\n");
	    if (errno == EINTR) continue;
	    return -1;
	}

	/* handle selected fds */
	for (int s=0; s<nfds; s++) {
	    int fd = events[s].data.fd;

	    if (fd < 0) continue;

	    if (events[s].events & EPOLLIN) {
		switch (fd) {
		case STDIN_FILENO:
		    linenoiseReadChar();
		    break;
		default:
		    printf("Data available on %d\n", fd);
		}
	    }
	    if (events[s].events & EPOLLHUP) {
		printf("HUP on sock %d\n", fd);
	    }
	    if (events[s].events & EPOLLERR) {
		printf("error happened on fd %d\n", fd);
		int r = epoll_ctl(epollFD, EPOLL_CTL_DEL, fd, NULL);
		printf("epoll_ctl(CTL_DEL) returns %d: %m\n", r);
		close(fd);
	    }
	}
    }

    sleep(1);

    linenoiseRemoveHandlerCallback();
    printf("\n");

    return 0;
}