iPXE
Defines | Functions
readline.c File Reference

Minimal readline. More...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ipxe/console.h>
#include <ipxe/keys.h>
#include <ipxe/editstring.h>
#include <readline/readline.h>

Go to the source code of this file.

Defines

#define READLINE_MAX   256

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void sync_console (struct edit_string *string)
 Synchronise console with edited string.
static struct
readline_history_entry
history_entry (struct readline_history *history, unsigned int depth)
 Locate history entry.
static const char * history_fetch (struct readline_history *history, unsigned int depth)
 Read string from history buffer.
static void history_store (struct readline_history *history, unsigned int depth, const char *string)
 Write temporary string copy to history buffer.
static const char * history_move (struct readline_history *history, int offset, const char *old_string)
 Move to new history depth.
static void history_append (struct readline_history *history, const char *string)
 Append new history entry.
static void history_cleanup (struct readline_history *history)
 Clean up history after editing.
void history_free (struct readline_history *history)
 Free history buffer.
int readline_history (const char *prompt, const char *prefill, struct readline_history *history, char **line)
 Read line from console (with history)
char * readline (const char *prompt)
 Read line from console.

Detailed Description

Minimal readline.

Definition in file readline.c.


Define Documentation

#define READLINE_MAX   256

Definition at line 41 of file readline.c.

Referenced by readline_history().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void sync_console ( struct edit_string string) [static]

Synchronise console with edited string.

Parameters:
stringEditable string

Definition at line 48 of file readline.c.

References edit_string::buf, edit_string::cursor, edit_string::last_cursor, len, mod_end, mod_start, putchar(), and strlen().

Referenced by readline_history().

                                                        {
        unsigned int mod_start = string->mod_start;
        unsigned int mod_end = string->mod_end;
        unsigned int cursor = string->last_cursor;
        size_t len = strlen ( string->buf );

        /* Expand region back to old cursor position if applicable */
        if ( mod_start > string->last_cursor )
                mod_start = string->last_cursor;

        /* Expand region forward to new cursor position if applicable */
        if ( mod_end < string->cursor )
                mod_end = string->cursor;

        /* Backspace to start of region */
        while ( cursor > mod_start ) {
                putchar ( '\b' );
                cursor--;
        }

        /* Print modified region */
        while ( cursor < mod_end ) {
                putchar ( ( cursor >= len ) ? ' ' : string->buf[cursor] );
                cursor++;
        }

        /* Backspace to new cursor position */
        while ( cursor > string->cursor ) {
                putchar ( '\b' );
                cursor--;
        }
}
static struct readline_history_entry* history_entry ( struct readline_history history,
unsigned int  depth 
) [static, read]

Locate history entry.

Parameters:
historyHistory buffer
depthDepth within history buffer
Return values:
entryHistory entry

Definition at line 89 of file readline.c.

References readline_history::entries, readline_history::next, and offset.

Referenced by history_append(), history_cleanup(), history_fetch(), and history_store().

                                                                       {
        unsigned int offset;

        offset = ( ( history->next - depth ) %
                   ( sizeof ( history->entries ) /
                     sizeof ( history->entries[0] ) ) );
        return &history->entries[offset];
}
static const char* history_fetch ( struct readline_history history,
unsigned int  depth 
) [static]

Read string from history buffer.

Parameters:
historyHistory buffer
depthDepth within history buffer
Return values:
stringString

Definition at line 105 of file readline.c.

References entry, history_entry(), readline_history_entry::string, and readline_history_entry::temp.

Referenced by history_move().

                                                         {
        struct readline_history_entry *entry;

        /* Return the temporary copy if it exists, otherwise return
         * the persistent copy.
         */
        entry = history_entry ( history, depth );
        return ( entry->temp ? entry->temp : entry->string );
}
static void history_store ( struct readline_history history,
unsigned int  depth,
const char *  string 
) [static]

Write temporary string copy to history buffer.

Parameters:
historyHistory buffer
depthDepth within history buffer
stringString

Definition at line 123 of file readline.c.

References DBGC, entry, free, history_entry(), strdup(), and readline_history_entry::temp.

Referenced by history_move().

                                                                     {
        struct readline_history_entry *entry;
        char *temp;

        /* Create temporary copy of string */
        temp = strdup ( string );
        if ( ! temp ) {
                /* Just discard the string; there's nothing we can do */
                DBGC ( history, "READLINE %p could not store string\n",
                       history );
                return;
        }

        /* Store temporary copy */
        entry = history_entry ( history, depth );
        free ( entry->temp );
        entry->temp = temp;
}
static const char* history_move ( struct readline_history history,
int  offset,
const char *  old_string 
) [static]

Move to new history depth.

Parameters:
historyHistory buffer
offsetOffset by which to change depth
old_stringString (possibly modified) at current depth
Return values:
new_stringString at new depth, or NULL for no movement

Definition at line 151 of file readline.c.

References readline_history::depth, history_fetch(), history_store(), NULL, offset, and READLINE_HISTORY_MAX_DEPTH.

Referenced by readline_history().

                                                                        {
        unsigned int new_depth = ( history->depth + offset );
        const char * new_string = history_fetch ( history, new_depth );

        /* Depth checks */
        if ( new_depth > READLINE_HISTORY_MAX_DEPTH )
                return NULL;
        if ( ! new_string )
                return NULL;

        /* Store temporary copy of old string at current depth */
        history_store ( history, history->depth, old_string );

        /* Update depth */
        history->depth = new_depth;

        /* Return new string */
        return new_string;
}
static void history_append ( struct readline_history history,
const char *  string 
) [static]

Append new history entry.

Parameters:
historyHistory buffer
stringString

Definition at line 178 of file readline.c.

References assert, DBGC, entry, free, history_entry(), readline_history::next, NULL, strdup(), and readline_history_entry::string.

Referenced by readline_history().

                                                  {
        struct readline_history_entry *entry;

        /* Store new entry */
        entry = history_entry ( history, 0 );
        assert ( entry->string == NULL );
        entry->string = strdup ( string );
        if ( ! entry->string ) {
                /* Just discard the string; there's nothing we can do */
                DBGC ( history, "READLINE %p could not append string\n",
                       history );
                return;
        }

        /* Increment history position */
        history->next++;

        /* Prepare empty "next" slot */
        entry = history_entry ( history, 0 );
        free ( entry->string );
        entry->string = NULL;
}
static void history_cleanup ( struct readline_history history) [static]

Clean up history after editing.

Parameters:
historyHistory buffer

Definition at line 207 of file readline.c.

References assert, readline_history::depth, readline_history::entries, entry, free, history_entry(), NULL, readline_history_entry::string, and readline_history_entry::temp.

Referenced by readline_history().

                                                                 {
        struct readline_history_entry *entry;
        unsigned int i;

        /* Discard any temporary strings */
        for ( i = 0 ; i < ( sizeof ( history->entries ) /
                            sizeof ( history->entries[0] ) ) ; i++ ) {
                entry = &history->entries[i];
                free ( entry->temp );
                entry->temp = NULL;
        }

        /* Reset depth */
        history->depth = 0;

        /* Sanity check */
        entry = history_entry ( history, 0 );
        assert ( entry->string == NULL );
}
void history_free ( struct readline_history history)

Free history buffer.

Parameters:
historyHistory buffer

Definition at line 232 of file readline.c.

References assert, readline_history::entries, entry, free, NULL, readline_history_entry::string, and readline_history_entry::temp.

Referenced by shell().

                                                       {
        struct readline_history_entry *entry;
        unsigned int i;

        /* Discard any temporary strings */
        for ( i = 0 ; i < ( sizeof ( history->entries ) /
                            sizeof ( history->entries[0] ) ) ; i++ ) {
                entry = &history->entries[i];
                assert ( entry->temp == NULL );
                free ( entry->string );
        }
}
int readline_history ( const char *  prompt,
const char *  prefill,
struct readline_history history,
char **  line 
)

Read line from console (with history)

Parameters:
promptPrompt string
prefillPrefill string, or NULL for no prefill
historyHistory buffer, or NULL for no history
Return values:
lineLine read from console (excluding terminating newline)
rcReturn status code

The returned line is allocated with malloc(); the caller must eventually call free() to release the storage.

Definition at line 257 of file readline.c.

References assert, CR, CTRL_C, done, ECANCELED, edit_string(), ENOMEM, getkey(), history_append(), history_cleanup(), history_move(), init_editstring(), key, KEY_DOWN, KEY_UP, LF, memset(), NULL, printf(), putchar(), rc, READLINE_MAX, replace_string(), strdup(), and sync_console().

Referenced by readline(), and shell().

                                                                       {
        char buf[READLINE_MAX];
        struct edit_string string;
        int key;
        int move_by;
        const char *new_string;
        int rc;

        /* Avoid returning uninitialised data on error */
        *line = NULL;

        /* Display prompt, if applicable */
        if ( prompt )
                printf ( "%s", prompt );

        /* Ensure cursor is visible */
        printf ( "\033[?25h" );

        /* Initialise editable string */
        memset ( &string, 0, sizeof ( string ) );
        init_editstring ( &string, buf, sizeof ( buf ) );
        buf[0] = '\0';

        /* Prefill string, if applicable */
        if ( prefill ) {
                replace_string ( &string, prefill );
                sync_console ( &string );
        }

        while ( 1 ) {
                /* Handle keypress */
                key = edit_string ( &string, getkey ( 0 ) );
                sync_console ( &string );
                move_by = 0;
                switch ( key ) {
                case CR:
                case LF:
                        *line = strdup ( buf );
                        rc = ( ( *line ) ? 0 : -ENOMEM );
                        goto done;
                case CTRL_C:
                        rc = -ECANCELED;
                        goto done;
                case KEY_UP:
                        move_by = 1;
                        break;
                case KEY_DOWN:
                        move_by = -1;
                        break;
                default:
                        /* Do nothing */
                        break;
                }

                /* Handle history movement, if applicable */
                if ( move_by && history ) {
                        new_string = history_move ( history, move_by, buf );
                        if ( new_string ) {
                                replace_string ( &string, new_string );
                                sync_console ( &string );
                        }
                }
        }

 done:
        putchar ( '\n' );
        if ( history ) {
                if ( *line && (*line)[0] )
                        history_append ( history, *line );
                history_cleanup ( history );
        }
        assert ( ( rc == 0 ) ^ ( *line == NULL ) );
        return rc;
}
char* readline ( const char *  prompt)

Read line from console.

Parameters:
promptPrompt string
Return values:
lineLine read from console (excluding terminating newline)

The returned line is allocated with malloc(); the caller must eventually call free() to release the storage.

Definition at line 342 of file readline.c.

References NULL, and readline_history().

                                       {
        char *line;

        readline_history ( prompt, NULL, NULL, &line );
        return line;
}