Annotation of qemu/roms/ipxe/src/hci/readline.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
                      3:  *
                      4:  * This program is free software; you can redistribute it and/or
                      5:  * modify it under the terms of the GNU General Public License as
                      6:  * published by the Free Software Foundation; either version 2 of the
                      7:  * License, or any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     12:  * General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: FILE_LICENCE ( GPL2_OR_LATER );
                     20: 
                     21: #include <stdio.h>
                     22: #include <string.h>
                     23: #include <stdlib.h>
                     24: #include <ipxe/console.h>
                     25: #include <ipxe/keys.h>
                     26: #include <ipxe/editstring.h>
                     27: #include <readline/readline.h>
                     28: 
                     29: /** @file
                     30:  *
                     31:  * Minimal readline
                     32:  *
                     33:  */
                     34: 
                     35: #define READLINE_MAX 256
                     36: 
                     37: /**
                     38:  * Synchronise console with edited string
                     39:  *
                     40:  * @v string           Editable string
                     41:  */
                     42: static void sync_console ( struct edit_string *string ) {
                     43:        unsigned int mod_start = string->mod_start;
                     44:        unsigned int mod_end = string->mod_end;
                     45:        unsigned int cursor = string->last_cursor;
                     46:        size_t len = strlen ( string->buf );
                     47: 
                     48:        /* Expand region back to old cursor position if applicable */
                     49:        if ( mod_start > string->last_cursor )
                     50:                mod_start = string->last_cursor;
                     51: 
                     52:        /* Expand region forward to new cursor position if applicable */
                     53:        if ( mod_end < string->cursor )
                     54:                mod_end = string->cursor;
                     55: 
                     56:        /* Backspace to start of region */
                     57:        while ( cursor > mod_start ) {
                     58:                putchar ( '\b' );
                     59:                cursor--;
                     60:        }
                     61: 
                     62:        /* Print modified region */
                     63:        while ( cursor < mod_end ) {
                     64:                putchar ( ( cursor >= len ) ? ' ' : string->buf[cursor] );
                     65:                cursor++;
                     66:        }
                     67: 
                     68:        /* Backspace to new cursor position */
                     69:        while ( cursor > string->cursor ) {
                     70:                putchar ( '\b' );
                     71:                cursor--;
                     72:        }
                     73: }
                     74: 
                     75: /**
                     76:  * Locate history entry
                     77:  *
                     78:  * @v history          History buffer
                     79:  * @v depth            Depth within history buffer
                     80:  * @ret entry          History entry
                     81:  */
                     82: static struct readline_history_entry *
                     83: history_entry ( struct readline_history *history, unsigned int depth ) {
                     84:        unsigned int offset;
                     85: 
                     86:        offset = ( ( history->next - depth ) %
                     87:                   ( sizeof ( history->entries ) /
                     88:                     sizeof ( history->entries[0] ) ) );
                     89:        return &history->entries[offset];
                     90: }
                     91: 
                     92: /**
                     93:  * Read string from history buffer
                     94:  *
                     95:  * @v history          History buffer
                     96:  * @v depth            Depth within history buffer
                     97:  * @ret string         String
                     98:  */
                     99: static const char * history_fetch ( struct readline_history *history,
                    100:                                    unsigned int depth ) {
                    101:        struct readline_history_entry *entry;
                    102: 
                    103:        /* Return the temporary copy if it exists, otherwise return
                    104:         * the persistent copy.
                    105:         */
                    106:        entry = history_entry ( history, depth );
                    107:        return ( entry->temp ? entry->temp : entry->string );
                    108: }
                    109: 
                    110: /**
                    111:  * Write temporary string copy to history buffer
                    112:  *
                    113:  * @v history          History buffer
                    114:  * @v depth            Depth within history buffer
                    115:  * @v string           String
                    116:  */
                    117: static void history_store ( struct readline_history *history,
                    118:                            unsigned int depth, const char *string ) {
                    119:        struct readline_history_entry *entry;
                    120:        char *temp;
                    121: 
                    122:        /* Create temporary copy of string */
                    123:        temp = strdup ( string );
                    124:        if ( ! temp ) {
                    125:                /* Just discard the string; there's nothing we can do */
                    126:                DBGC ( history, "READLINE %p could not store string\n",
                    127:                       history );
                    128:                return;
                    129:        }
                    130: 
                    131:        /* Store temporary copy */
                    132:        entry = history_entry ( history, depth );
                    133:        free ( entry->temp );
                    134:        entry->temp = temp;
                    135: }
                    136: 
                    137: /**
                    138:  * Move to new history depth
                    139:  *
                    140:  * @v history          History buffer
                    141:  * @v offset           Offset by which to change depth
                    142:  * @v old_string       String (possibly modified) at current depth
                    143:  * @ret new_string     String at new depth, or NULL for no movement
                    144:  */
                    145: static const char * history_move ( struct readline_history *history,
                    146:                                   int offset, const char *old_string ) {
                    147:        unsigned int new_depth = ( history->depth + offset );
                    148:        const char * new_string = history_fetch ( history, new_depth );
                    149: 
                    150:        /* Depth checks */
                    151:        if ( new_depth > READLINE_HISTORY_MAX_DEPTH )
                    152:                return NULL;
                    153:        if ( ! new_string )
                    154:                return NULL;
                    155: 
                    156:        /* Store temporary copy of old string at current depth */
                    157:        history_store ( history, history->depth, old_string );
                    158: 
                    159:        /* Update depth */
                    160:        history->depth = new_depth;
                    161: 
                    162:        /* Return new string */
                    163:        return new_string;
                    164: }
                    165: 
                    166: /**
                    167:  * Append new history entry
                    168:  *
                    169:  * @v history          History buffer
                    170:  * @v string           String
                    171:  */
                    172: static void history_append ( struct readline_history *history,
                    173:                             const char *string ) {
                    174:        struct readline_history_entry *entry;
                    175: 
                    176:        /* Store new entry */
                    177:        entry = history_entry ( history, 0 );
                    178:        assert ( entry->string == NULL );
                    179:        entry->string = strdup ( string );
                    180:        if ( ! entry->string ) {
                    181:                /* Just discard the string; there's nothing we can do */
                    182:                DBGC ( history, "READLINE %p could not append string\n",
                    183:                       history );
                    184:                return;
                    185:        }
                    186: 
                    187:        /* Increment history position */
                    188:        history->next++;
                    189: 
                    190:        /* Prepare empty "next" slot */
                    191:        entry = history_entry ( history, 0 );
                    192:        free ( entry->string );
                    193:        entry->string = NULL;
                    194: }
                    195: 
                    196: /**
                    197:  * Clean up history after editing
                    198:  *
                    199:  * @v history          History buffer
                    200:  */
                    201: static void history_cleanup ( struct readline_history *history ) {
                    202:        struct readline_history_entry *entry;
                    203:        unsigned int i;
                    204: 
                    205:        /* Discard any temporary strings */
                    206:        for ( i = 0 ; i < ( sizeof ( history->entries ) /
                    207:                            sizeof ( history->entries[0] ) ) ; i++ ) {
                    208:                entry = &history->entries[i];
                    209:                free ( entry->temp );
                    210:                entry->temp = NULL;
                    211:        }
                    212: 
                    213:        /* Reset depth */
                    214:        history->depth = 0;
                    215: 
                    216:        /* Sanity check */
                    217:        entry = history_entry ( history, 0 );
                    218:        assert ( entry->string == NULL );
                    219: }
                    220: 
                    221: /**
                    222:  * Free history buffer
                    223:  *
                    224:  * @v history          History buffer
                    225:  */
                    226: void history_free ( struct readline_history *history ) {
                    227:        struct readline_history_entry *entry;
                    228:        unsigned int i;
                    229: 
                    230:        /* Discard any temporary strings */
                    231:        for ( i = 0 ; i < ( sizeof ( history->entries ) /
                    232:                            sizeof ( history->entries[0] ) ) ; i++ ) {
                    233:                entry = &history->entries[i];
                    234:                assert ( entry->temp == NULL );
                    235:                free ( entry->string );
                    236:        }
                    237: }
                    238: 
                    239: /**
                    240:  * Read line from console (with history)
                    241:  *
                    242:  * @v prompt           Prompt string
                    243:  * @v history          History buffer, or NULL for no history
                    244:  * @ret line           Line read from console (excluding terminating newline)
                    245:  *
                    246:  * The returned line is allocated with malloc(); the caller must
                    247:  * eventually call free() to release the storage.
                    248:  */
                    249: char * readline_history ( const char *prompt,
                    250:                          struct readline_history *history ) {
                    251:        char buf[READLINE_MAX];
                    252:        struct edit_string string;
                    253:        int key;
                    254:        int move_by;
                    255:        const char *new_string;
                    256:        char *line;
                    257: 
                    258:        /* Display prompt, if applicable */
                    259:        if ( prompt )
                    260:                printf ( "%s", prompt );
                    261: 
                    262:        /* Initialise editable string */
                    263:        memset ( &string, 0, sizeof ( string ) );
                    264:        init_editstring ( &string, buf, sizeof ( buf ) );
                    265:        buf[0] = '\0';
                    266: 
                    267:        while ( 1 ) {
                    268:                /* Handle keypress */
                    269:                key = edit_string ( &string, getkey ( 0 ) );
                    270:                sync_console ( &string );
                    271:                move_by = 0;
                    272:                switch ( key ) {
                    273:                case CR:
                    274:                case LF:
                    275:                        line = strdup ( buf );
                    276:                        if ( ! line )
                    277:                                printf ( "\nOut of memory" );
                    278:                        goto done;
                    279:                case CTRL_C:
                    280:                        line = NULL;
                    281:                        goto done;
                    282:                case KEY_UP:
                    283:                        move_by = 1;
                    284:                        break;
                    285:                case KEY_DOWN:
                    286:                        move_by = -1;
                    287:                        break;
                    288:                default:
                    289:                        /* Do nothing */
                    290:                        break;
                    291:                }
                    292: 
                    293:                /* Handle history movement, if applicable */
                    294:                if ( move_by && history ) {
                    295:                        new_string = history_move ( history, move_by, buf );
                    296:                        if ( new_string ) {
                    297:                                replace_string ( &string, new_string );
                    298:                                sync_console ( &string );
                    299:                        }
                    300:                }
                    301:        }
                    302: 
                    303:  done:
                    304:        putchar ( '\n' );
                    305:        if ( history ) {
                    306:                if ( line && line[0] )
                    307:                        history_append ( history, line );
                    308:                history_cleanup ( history );
                    309:        }
                    310:        return line;
                    311: }
                    312: 
                    313: /**
                    314:  * Read line from console
                    315:  *
                    316:  * @v prompt           Prompt string
                    317:  * @ret line           Line read from console (excluding terminating newline)
                    318:  *
                    319:  * The returned line is allocated with malloc(); the caller must
                    320:  * eventually call free() to release the storage.
                    321:  */
                    322: char * readline ( const char *prompt ) {
                    323:        return readline_history ( prompt, NULL );
                    324: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.