Revision 697dba3c

View differences:

core/inc/aos_confcheck.h
164 164
    #error "AMIROOS_CFG_SHELL_MAXARGS not defined in aosconf.h"
165 165
  #endif /* !defined(AMIROOS_CFG_SHELL_MAXARGS) */
166 166

  
167
  #if !defined(AMIROOS_CFG_SHELL_HISTLENGTH)
168
    #error "AMIROOS_CFG_SHELL_HISTLENGTH not defined in aosconf.h"
169
  #endif /* !defined(AMIROOS_CFG_SHELL_HISTLENGTH) */
170

  
167 171
#else /* (AMIROOS_CFG_SHELL_ENABLE == true) */
168 172

  
169 173
  #if (AMIROOS_CFG_TESTS_ENABLE == true)
core/inc/aos_shell.h
50 50
/**
51 51
 * @brief   Shell event flag that is emitted when a command is executed.
52 52
 */
53
#define AOS_SHELL_EVTFLAG_EXEC                    ((eventflags_t)(1 << 1))
53
#define AOS_SHELL_EVTFLAG_EXECUTE                 ((eventflags_t)(1 << 1))
54 54

  
55 55
/**
56 56
 * @brief   Shell event flag that is emitted when a command execution finished.
......
239 239
} aos_shellexecstatus_t;
240 240

  
241 241
/**
242
 * @brief   Enumerator to encode shell actions.
243
 */
244
typedef enum aos_shellaction {
245
  AOS_SHELL_ACTION_NONE,
246
  AOS_SHELL_ACTION_READCHAR,
247
  AOS_SHELL_ACTION_AUTOFILL,
248
  AOS_SHELL_ACTION_SUGGEST,
249
  AOS_SHELL_ACTION_INSERTTOGGLE,
250
  AOS_SHELL_ACTION_DELETEFORWARD,
251
  AOS_SHELL_ACTION_DELETEBACKWARD,
252
  AOS_SHELL_ACTION_RECALLLAST,
253
  AOS_SHELL_ACTION_CLEAR,
254
  AOS_SHELL_ACTION_CURSOR2START,
255
  AOS_SHELL_ACTION_CURSOR2END,
256
  AOS_SHELL_ACTION_CURSORLEFT,
257
  AOS_SHELL_ACTION_CURSORRIGHT,
258
  AOS_SHELL_ACTION_CURSORWORDLEFT,
259
  AOS_SHELL_ACTION_CURSORWORDRIGHT,
260
  AOS_SHELL_ACTION_EXECUTE,
261
  AOS_SHELL_ACTION_ESCSTART,
262
  AOS_SHELL_ACTION_PRINTUNKNOWNSEQUENCE,
263
} aos_shellaction_t;
264

  
265
/**
266 242
 * @brief   Shell structure.
267 243
 */
268 244
typedef struct aos_shell {
......
277 253
  event_source_t eventSource;
278 254

  
279 255
  /**
280
   * @brief   Struct for OS related events
256
   * @brief   Listener for OS related events.
281 257
   */
282
  struct {
283
    /**
284
     * @brief   Pointer to the OS' event source.
285
     */
286
    event_source_t* eventSource;
287

  
288
    /**
289
     * @brief   Listener for OS related events.
290
     */
291
    event_listener_t eventListener;
292
  } os;
258
  event_listener_t osEventListener;
293 259

  
294 260
  /**
295 261
     * @brief   Pointer to the first I/O channel.
......
318 284
  struct {
319 285
    /**
320 286
     * @brief   Input buffer.
287
     * @details This buffer is interpreted as two dimensional array.
288
     *          It contains @p nentries elements of @p linewidth size each.
321 289
     */
322
    char* line;
323

  
324
    /**
325
     * @brief   Size of the input buffer.
326
     */
327
    size_t length;
328

  
329
    /**
330
     * @brief   Size of the argument buffer.
331
     */
332
    size_t nargs;
333
  } input;
334

  
335
  /**
336
   * @brief   Structure containing data for internal input parsing.
337
   */
338
  struct {
339
    /**
340
     * @brief   The last action executed by the shell.
341
     */
342
    aos_shellaction_t lastaction;
290
    char* buffer;
343 291

  
344 292
    /**
345
     * @brief   Buffer to store an escape sequence.
293
     * @brief   Number of entries in the buffer.
294
     * @note    Must be >0.
346 295
     */
347
    char escseq[AOS_SHELL_ESCSEQUENCE_LENGTH];
296
    size_t nentries;
348 297

  
349 298
    /**
350
     * @brief   Current curso position.
299
     * @brief   Width of each input line.
300
     * @brief   Must be >0.
351 301
     */
352
    size_t cursorpos;
302
    size_t linewidth;
353 303

  
354 304
    /**
355
     * @brief   Current line width.
356
     */
357
    size_t lineend;
358

  
359
    /**
360
     * @brief   Flag whether there was input since the prompt was printed the last time.
305
     * @brief   Size of the argument buffer.
306
     * @note    Must be >0.
361 307
     */
362
    bool noinput;
363
  } inputdata;
364

  
365

  
308
    size_t nargs;
309
  } input;
366 310

  
367 311
  /**
368 312
   * @brief   Configuration flags.
......
394 338
#if defined(__cplusplus)
395 339
extern "C" {
396 340
#endif /* defined(__cplusplus) */
397
  void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource, const char* prompt, char* line, size_t linesize, size_t numargs);
341
  void aosShellInit(aos_shell_t* shell, const char* prompt, char inbuf[], size_t entries, size_t linewidth, size_t numargs);
398 342
  void aosShellStreamInit(AosShellStream* stream);
399 343
  void aosShellChannelInit(AosShellChannel* channel, BaseAsynchronousChannel* asyncchannel);
400 344
  aos_status_t aosShellAddCommand(aos_shell_t* shell, aos_shellcommand_t* cmd);
core/src/aos_shell.c
35 35
/******************************************************************************/
36 36

  
37 37
/**
38
 * @brief   The character the input buffer is initialized with.
39
 */
40
#define INBUF_INIT_CHAR                         '\x07'
41

  
42
/**
38 43
 * @brief   Event mask to be set on OS related events.
39 44
 */
40
#define AOS_SHELL_EVENTMASK_OS                  EVENT_MASK(0)
45
#define EVENTMASK_OS                            EVENT_MASK(0)
41 46

  
42 47
/**
43 48
 * @brief   Event mask to be set on a input event.
44 49
 */
45
#define AOS_SHELL_EVENTMASK_INPUT               EVENT_MASK(1)
50
#define EVENTMASK_INPUT                         EVENT_MASK(1)
51

  
52
/**
53
 * @brief   String that defines the INSERT key as specified by VT100.
54
 */
55
#define KEYSTRING_INSERT                        "\x1B\x5B\x32\x7E"
56

  
57
/**
58
 * @brief   String that defines the DEL key as specified by VT100.
59
 */
60
#define KEYSTRING_DELETE                        "\x1B\x5B\x33\x7E"
61

  
62
/**
63
 * @brief   String that defines the HOME key as specified by VT100.
64
 */
65
#define KEYSTRING_HOME                          "\x1B\x5B\x48"
66

  
67
/**
68
 * @brief   String that defines the END key as specified by VT100.
69
 */
70
#define KEYSTRING_END                           "\x1B\x5B\x46"
71

  
72
/**
73
 * @brief   String that defines the PGUP key as specified by VT100.
74
 */
75
#define KEYSTRING_PAGEUP                        "\x1B\x5B\x35\x7E"
76

  
77
/**
78
 * @brief   String that defines the PGUP key as specified by VT100.
79
 */
80
#define KEYSTRING_PAGEDOWN                      "\x1B\x5B\x36\x7E"
81

  
82
/**
83
 * @brief   String that defines the 'arrow down' key as specified by VT100.
84
 */
85
#define KEYSTRING_ARROWUP                       "\x1B\x5B\x41"
86

  
87
/**
88
 * @brief   String that defines the 'arrow up' key as specified by VT100.
89
 */
90
#define KEYSTRING_ARROWDOWN                     "\x1B\x5B\x42"
91

  
92
/**
93
 * @brief   String that defines the 'arrow left' key as specified by VT100.
94
 */
95
#define KEYSTRING_ARROWLEFT                     "\x1B\x5B\x44"
96

  
97
/**
98
 * @brief   String that defines the 'arrow right' key as specified by VT100.
99
 */
100
#define KEYSTRING_ARROWRIGHT                    "\x1B\x5B\x43"
101

  
102
/**
103
 * @brief   String that defines the CRTL + 'arrow up' key combination as specified by VT100.
104
 */
105
#define KEYSTRING_CTRL_ARROWUP                  "\x1B\x5B\x31\x3B\x35\x41"
106

  
107
/**
108
 * @brief   String that defines the CRTL + 'arrow down' key combination as specified by VT100.
109
 */
110
#define KEYSTRING_CTRL_ARROWDOWN                "\x1B\x5B\x31\x3B\x35\x42"
111

  
112
/**
113
 * @brief   String that defines the CRTL + 'arrow left' key combination as specified by VT100.
114
 */
115
#define KEYSTRING_CTRL_ARROWLEFT                "\x1B\x5B\x31\x3B\x35\x44"
116

  
117
/**
118
 * @brief   String that defines the CRTL + 'arrow right' key combination as specified by VT100.
119
 */
120
#define KEYSTRING_CTRL_ARROWRIGHT               "\x1B\x5B\x31\x3B\x35\x43"
46 121

  
47 122
/******************************************************************************/
48 123
/* EXPORTED VARIABLES                                                         */
......
97 172
  KEY_UNKNOWN,          /**< any/unknow key */
98 173
  KEY_AMBIGUOUS,        /**< key is ambiguous */
99 174
  KEY_TAB,              /**< tabulator key */
100
  KEY_ESCAPE,           /**< escape key */
101 175
  KEY_BACKSPACE,        /**< backspace key */
102 176
  KEY_INSERT,           /**< insert key */
103 177
  KEY_DELETE,           /**< delete key */
178
  KEY_ESCAPE,           /**< escape key */
104 179
  KEY_HOME,             /**< home key */
105 180
  KEY_END,              /**< end key */
106
  KEY_PAGE_UP,          /**< page up key */
107
  KEY_PAGE_DOWN,        /**< page down key */
108
  KEY_ARROW_UP,         /**< arrow up key */
109
  KEY_ARROW_DOWN,       /**< arrow down key */
110
  KEY_ARROW_LEFT,       /**< arrow left key */
111
  KEY_ARROW_RIGHT,      /**< arrow right key */
112
  KEY_CTRL_ARROW_UP,    /**< CTRL + arrow up key */
113
  KEY_CTRL_ARROW_DOWN,  /**< CTRL + arrow down key */
114
  KEY_CTRL_ARROW_LEFT,  /**< CTRL + arrow left key */
115
  KEY_CTRL_ARROW_RIGHT, /**< CTRL + arrow right key */
181
  KEY_PAGEUP,           /**< page up key */
182
  KEY_PAGEDOWN,         /**< page down key */
183
  KEY_ARROWUP,          /**< arrow up key */
184
  KEY_ARROWDOWN,        /**< arrow down key */
185
  KEY_ARROWLEFT,        /**< arrow left key */
186
  KEY_ARROWRIGHT,       /**< arrow right key */
187
  KEY_CTRL_ARROWUP,     /**< CTRL + arrow up key */
188
  KEY_CTRL_ARROWDOWN,   /**< CTRL + arrow down key */
189
  KEY_CTRL_ARROWLEFT,   /**< CTRL + arrow left key */
190
  KEY_CTRL_ARROWRIGHT,  /**< CTRL + arrow right key */
191
  KEY_CTRL_C,           /**< CTRL + C key */
116 192
} special_key_t;
117 193

  
118 194
/**
......
124 200
  CHAR_MATCH_CASE   = 2,  /**< Characters do match with case. */
125 201
} charmatch_t;
126 202

  
203
/**
204
 * @brief   Enumerator to encode shell actions.
205
 */
206
typedef enum aos_shellaction {
207
  ACTION_NONE,                  /**< No action at all. */
208
  ACTION_READCHAR,              /**< Read a printable character. */
209
  ACTION_AUTOCOMPLETE,          /**< Automatically comlete input by using available command. */
210
  ACTION_SUGGEST,               /**< Suggest matching available commands. */
211
  ACTION_EXECUTE,               /**< Execute input. */
212
  ACTION_DELETEBACKWARD,        /**< Delete a single character backwards. */
213
  ACTION_DELETEFORWARD,         /**< Delete a single character forwards. */
214
  ACTION_CLEAR,                 /**< Clear the input. */
215
  ACTION_RECALLPREVIOUS,        /**< Recall the previous (older) entry in the history. */
216
  ACTION_RECALLNEXT,            /**< Recall the next (more recent) entry in the history. */
217
  ACTION_RECALLOLDEST,          /**< Recall the oldest entry in the history. */
218
  ACTION_RECALLCURRENT,         /**< Recall the current input. */
219
  ACTION_CURSORLEFT,            /**< Move cursor one character to the left. */
220
  ACTION_CURSORRIGHT,           /**< Move cursor one character to the right. */
221
  ACTION_CURSORWORDLEFT,        /**< Move cursor one word to the left. */
222
  ACTION_CURSORWORDRIGHT,       /**< Move cursor one word to the right. */
223
  ACTION_CURSOR2END,            /**< Move cursor to the very right. */
224
  ACTION_CURSOR2START,          /**< Move cursor to the very left. */
225
  ACTION_RESET,                 /**< Reset the current input. */
226
  ACTION_INSERTTOGGLE,          /**< Toggle insertion mode. */
227
  ACTION_ESCSTART,              /**< Start an escape sequence (special keys). */
228
  ACTION_PRINTUNKNOWNSEQUENCE,  /**< Print an unknown escape sequence. */
229
} action_t;
230

  
231
/**
232
 * @brief   Struct that holds most important runtime data for the shell.
233
 * @details The structure is to be used by the shell thread main function as some kind of structured stack, which can be easily passed to other functions.
234
 */
235
typedef struct runtimedata {
236
  /**
237
   * @brief   Data related to the current input.
238
   */
239
  struct {
240
    /**
241
     * @brief   Length of the input.
242
     */
243
    size_t length;
244

  
245
    /**
246
     * @brief   Current position of the cursor in the input line.
247
     */
248
    size_t cursorpos;
249

  
250
    /**
251
     * @brief   Buffer to store escape sequences, which describe special characters.
252
     */
253
    char escseq[AOS_SHELL_ESCSEQUENCE_LENGTH];
254
  } input;
255

  
256
  /**
257
   * @brief   Data related to the entry or history buffer.
258
   */
259
  struct {
260
    /**
261
     * @brief   Current entry to be filled and executed.
262
     */
263
    size_t current;
264

  
265
    /**
266
     * @brief   Selected entry in the 'history' as preview.
267
     * @details A value of 0 indicates, that the line is cleared as a preview.
268
     *          A value of 1 indicates, that the current entry is selected.
269
     *          A value of t>1 indicates, that the entry t-1 in the past is selected.
270
     *          The value must never be greater than the number of entries available, of course.
271
     */
272
    size_t selected;
273

  
274
    /**
275
     * @brief   Selected entry in the 'history' that has been edited by the user.
276
     *          A value of 0 indicates, that there was no modification by the user yet (i.e. charcters, deletions or autofill).
277
     *          A value of 1 indicates, that the current entry was edited.
278
     *          A value of t>1 indicated, that a history entry was recalled and then edited.
279
     */
280
    size_t edited;
281
  } buffer;
282

  
283
  /**
284
   * @brief   The last action executed by the shell.
285
   */
286
  action_t lastaction;
287
} runtimedata_t;
288

  
127 289
/******************************************************************************/
128 290
/* LOCAL VARIABLES                                                            */
129 291
/******************************************************************************/
......
248 410
  return MSG_OK;
249 411
}
250 412

  
413
/**
414
 * @brief   Implementation of the BaseSequentialStream write() method.
415
 */
251 416
static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
252 417
{
253 418
  aosDbgCheck(instance != NULL);
......
267 432
  return maxbytes;
268 433
}
269 434

  
435
/**
436
 * @brief   Implementation of the BaseSequentialStream read() method.
437
 */
270 438
static size_t _stremread(void *instance, uint8_t *bp, size_t n)
271 439
{
272 440
  (void)instance;
......
276 444
  return 0;
277 445
}
278 446

  
447
/**
448
 * @brief   Implementation of the BaseSequentialStream put() method.
449
 */
279 450
static msg_t _streamput(void *instance, uint8_t b)
280 451
{
281 452
  aosDbgCheck(instance != NULL);
......
294 465
  return ret;
295 466
}
296 467

  
468
/**
469
 * @brief   Implementation of the BaseSequentialStream get() method.
470
 */
297 471
static msg_t _streamget(void *instance)
298 472
{
299 473
  (void)instance;
......
302 476
}
303 477

  
304 478
/**
479
 * @brief   Retreive a pointer to the string buffer of a specified entry in the input buffer.
480
 *
481
 * @param[in] shell   Pointer to a shell object.
482
 * @param[in] entry   Entry to be retrieved.
483
 *
484
 * @return  Pointer to the entry in the input buffer.
485
 */
486
static inline char* _getAbsoluteEntry(const aos_shell_t* shell, size_t entry)
487
{
488
  aosDbgCheck(shell != NULL);
489
  aosDbgCheck(entry < shell->input.nentries);
490

  
491
  return &(shell->input.buffer[entry * shell->input.linewidth * sizeof(char)]);
492
}
493

  
494
/**
495
 * @brief   Calculate absolute entry from history offset.
496
 *
497
 * @param[in] shell   Pointer to a shell object.
498
 * @param[in] rdata   Pointer to a runtime data object.
499
 * @param[in] offset  Relative offset of the entry to be retreived.
500
 *
501
 * @return  Absolute index of the historic entry.
502
 */
503
static inline size_t _historyOffset2EntryIndex(const aos_shell_t* shell, const runtimedata_t* rdata, size_t offset)
504
{
505
  aosDbgCheck(shell != NULL);
506
  aosDbgCheck(rdata != NULL);
507
  aosDbgCheck(offset < shell->input.nentries);
508

  
509
  return ((shell->input.nentries + rdata->buffer.current - offset) % shell->input.nentries);
510
}
511

  
512
/**
513
 * @brief   Retreive a pointer to the string buffer of a historic entry in the input buffer.
514
 *
515
 * @param[in] shell   Pointer to a shell object.
516
 * @param[in] rdata   Pointer to a runtime data object.
517
 * @param[in] offset  Relative offset of the entry to be retreived.
518
 *
519
 * @return  Pointer to the entry in the input buffer.
520
 */
521
static inline char* _getRelativeEntry(const aos_shell_t* shell, const runtimedata_t* rdata, size_t offset)
522
{
523
  aosDbgCheck(shell != NULL);
524
  aosDbgCheck(rdata != NULL);
525
  aosDbgCheck(offset < shell->input.nentries);
526

  
527
  return _getAbsoluteEntry(shell, _historyOffset2EntryIndex(shell, rdata, offset));
528
}
529

  
530
/**
531
 * @brief   Retreive a pointer to the current entry string in the input buffer.
532
 *
533
 * @param[in] shell   Pointer to a shell object.
534
 * @param[in] rdata   Pointer to a runtime data object.
535
 *
536
 * @return  Pointer to the string of the current entry in the input buffer.
537
 */
538
static inline char* _getCurrentEntry(const aos_shell_t* shell, const runtimedata_t* rdata)
539
{
540
  aosDbgCheck(shell != NULL);
541
  aosDbgCheck(rdata != NULL);
542

  
543
  return _getAbsoluteEntry(shell, rdata->buffer.current);
544
}
545