Nut/OS  4.10.3
API Reference
edline.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2009 by egnite GmbH
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  * 3. Neither the name of the copyright holders nor the names of
00016  *    contributors may be used to endorse or promote products derived
00017  *    from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00023  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  */
00034 
00035 /*
00036  * \file gorp/edline/edline.c
00037  * \brief Simple line editor.
00038  *
00039  * \verbatim
00040  * $Id$
00041  * \endverbatim
00042  */
00043 
00044 #include <gorp/edline.h>
00045 
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048 #include <ctype.h>
00049 #include <string.h>
00050 
00055 
00060 #if !defined(EDIT_MAX_HISTORY) && !defined(EDIT_DISABLE_HISTORY)
00061 #define EDIT_MAX_HISTORY    16
00062 #endif
00063 
00073 static int EdLineGetChar(void *param)
00074 {
00075     return getchar();
00076 }
00077 
00087 static int EdLinePutChar(void *param, int ch)
00088 {
00089     return putchar(ch);
00090 }
00091 
00105 void EdLineRegisterInput(EDLINE *el, EDLINEGET get, void *param)
00106 {
00107     if (get) {
00108         el->el_get = get;
00109     } else {
00110         el->el_get = EdLineGetChar;
00111     }
00112     el->el_iparm = param;
00113 }
00114 
00128 void EdLineRegisterOutput(EDLINE *el, EDLINEPUT put, void *param)
00129 {
00130     if (put) {
00131         el->el_put = put;
00132     } else {
00133         el->el_put = EdLinePutChar;
00134     }
00135     el->el_oparm = param;
00136 }
00137 
00156 int EdLineKeyMap(int key, int *seq)
00157 {
00158     if (key == '\r') {
00159         *seq = -1;
00160         key = EDIT_KEY_ENTER;
00161     }
00162     else {
00163         if (key == '\n') {
00164             if (*seq < 0) {
00165                 key = EDIT_KEY_IGNORE;
00166             } else {
00167                 key = EDIT_KEY_ENTER;
00168             }
00169         }
00170         *seq = 0;
00171     }
00172     return key;
00173 }
00174 
00183 void EdLineRegisterKeymap(EDLINE *el, EDLINEMAP map)
00184 {
00185     if (map) {
00186         el->el_map = map;
00187     } else {
00188         el->el_map = EdLineKeyMap;
00189     }
00190 }
00191 
00202 EDLINE *EdLineOpen(uint16_t mode)
00203 {
00204     EDLINE *el;
00205 
00206     el = calloc(1, sizeof(EDLINE));
00207     if (el) {
00208         el->el_mode = mode;
00209         EdLineRegisterInput(el, NULL, stdin);
00210         EdLineRegisterOutput(el, NULL, stdout);
00211         EdLineRegisterKeymap(el, NULL);
00212 #ifndef EDIT_DISABLE_HISTORY
00213         if (mode & EDIT_MODE_HISTORY) {
00214             el->el_hist = EditHistoryCreate(EDIT_MAX_HISTORY);
00215         }
00216 #endif
00217     }
00218     return el;
00219 }
00220 
00229 void EdLineClose(EDLINE *el)
00230 {
00231     if (el) {
00232 #ifndef EDIT_DISABLE_HISTORY
00233         EditHistoryDestroy(el->el_hist);
00234 #endif
00235         free(el);
00236     }
00237 }
00238 
00247 static int PrintString(EDLINE *el, char *str)
00248 {
00249     while (*str) {
00250         (*el->el_put)(el->el_oparm, *str);
00251         str++;
00252     }
00253     return 0;
00254 }
00255 
00266 static void PrintCharacter(EDLINE *el, int ch, int num)
00267 {
00268     while (num-- > 0) {
00269         (*el->el_put)(el->el_oparm, ch);
00270     }
00271 }
00272 
00273 #ifndef EDIT_DISABLE_HISTORY
00274 
00285 static void ClearLineEnd(EDLINE *el, int num)
00286 {
00287     PrintCharacter(el, EDIT_CHAR_SPACE, num);
00288     PrintCharacter(el, EDIT_CHAR_BACKSPACE, num);
00289 }
00290 #endif
00291 
00326 int EdLineRead(EDLINE *el, char *buf, int siz)
00327 {
00328     int ch;
00329     int cpos;
00330     int i;
00331 #ifndef EDIT_DISABLE_HISTORY
00332     int ipos;
00333     int hidx = 0;
00334     int refresh = 0;
00335 #endif
00336 
00337     /* Make sure that the string is terminated. */
00338     buf[siz - 1] = '\0';
00339 
00340 #ifndef EDIT_DISABLE_HISTORY
00341     EditHistorySet(el->el_hist, 0, buf);
00342 #endif
00343     PrintString(el, buf);
00344     cpos = strlen(buf);
00345 
00346     for (;;) {
00347         ch = (*el->el_get)(el->el_iparm);
00348         if (ch == EOF) {
00349             return -1;
00350         }
00351         ch = (*el->el_map)(ch, &el->el_seq);
00352         if (ch == EDIT_KEY_ENTER) {
00353             break;
00354         }
00355         /* Backspace removes the character in front of the cursor. */
00356         if (ch == EDIT_KEY_REMOVE) {
00357             if (cpos) {
00358                 cpos--;
00359                 for (i = cpos; i < siz - 1; i++) {
00360                     buf[i] = buf[i + 1];
00361                 }
00362                 if (el->el_mode & EDIT_MODE_ECHO) {
00363                     (*el->el_put)(el->el_oparm, EDIT_CHAR_BACKSPACE);
00364                 }
00365                 PrintString(el, &buf[cpos]);
00366                 (*el->el_put)(el->el_oparm, EDIT_CHAR_SPACE);
00367                 PrintCharacter(el, EDIT_CHAR_BACKSPACE, strlen(buf) + 1 - cpos);
00368             }
00369         }
00370 #ifndef EDIT_DISABLE_HISTORY
00371         else if (ch == EDIT_KEY_RESTORE) {
00372             hidx = 0;
00373             refresh = 1;
00374         }
00375         else if (ch == EDIT_KEY_UP) {
00376             if (EditHistoryGet(el->el_hist, hidx + 1, NULL, 0) >= 0) {
00377                 hidx++;
00378                 refresh = 1;
00379             }
00380         }
00381         else if (ch == EDIT_KEY_DOWN) {
00382             if (hidx > 0) {
00383                 hidx--;
00384                 refresh = 1;
00385             }
00386         }
00387 #endif
00388         else if (ch == EDIT_KEY_RIGHT) {
00389             if (cpos < strlen(buf)) {
00390                 if (el->el_mode & EDIT_MODE_ECHO) {
00391                     (*el->el_put)(el->el_oparm, buf[cpos]);
00392                 }
00393                 cpos++;
00394             }
00395         }
00396         else if (ch == EDIT_KEY_LEFT) {
00397             if (cpos) {
00398                 if (el->el_mode & EDIT_MODE_ECHO) {
00399                     (*el->el_put)(el->el_oparm, EDIT_CHAR_BACKSPACE);
00400                 }
00401                 cpos--;
00402             }
00403         }
00404         else if (ch == EDIT_KEY_HOME) {
00405             PrintCharacter(el, EDIT_CHAR_BACKSPACE, cpos);
00406             cpos = 0;
00407         }
00408         else if (ch == EDIT_KEY_END) {
00409             PrintString(el, &buf[cpos]);
00410             cpos = strlen(buf);
00411         }
00412         /* Normal character, insert at cursor position if buffer is not full. */
00413         else if (isprint(ch) && strlen(buf) < siz - 1) {
00414             for (i = siz - 1; i > cpos; i--) {
00415                 buf[i] = buf[i - 1];
00416             }
00417             buf[cpos++] = ch;
00418             if (el->el_mode & EDIT_MODE_ECHO) {
00419                 (*el->el_put)(el->el_oparm, ch);
00420             }
00421             PrintString(el, &buf[cpos]);
00422             PrintCharacter(el, EDIT_CHAR_BACKSPACE, strlen(buf) - cpos);
00423         } else {
00424             /* Beep on buffer overflow. */
00425             (*el->el_put)(el->el_oparm, EDIT_CHAR_ALARM);
00426         }
00427 #ifndef EDIT_DISABLE_HISTORY
00428         if (refresh && (el->el_mode & EDIT_MODE_HISTORY) != 0) {
00429             refresh = 0;
00430             PrintCharacter(el, EDIT_CHAR_BACKSPACE, cpos);
00431             ipos = strlen(buf);
00432             EditHistoryGet(el->el_hist, hidx, buf, siz);
00433             cpos = strlen(buf);
00434             PrintString(el, buf);
00435             ClearLineEnd(el, ipos - cpos);
00436         }
00437 #endif
00438     }
00439     PrintString(el, EDIT_STR_EOL);
00440 #ifndef EDIT_DISABLE_HISTORY
00441     EditHistoryInsert(el->el_hist, 1, buf);
00442 #endif
00443     return strlen(buf);
00444 }
00445