#define _RDLINE_H_
/**
- * This file is a small equivalent to the GNU readline library, but it
- * was originally designed for small systems, like Atmel AVR
- * microcontrollers (8 bits). Indeed, we don't use any malloc that is
- * sometimes not implemented (or just not recommended) on such
- * systems.
+ * This file is a small equivalent to the GNU readline library, it was
+ * originally designed for very small systems (an 8-bits Atmel AVR
+ * microcontroller), but the library can now run on many emmbedded
+ * systems with or without OS.
*
* Obviously, it does not support as many things as the GNU readline,
* but at least it supports some interresting features like a kill
* buffer and a command history.
*
* It also have a feature that does not have the GNU readline (as far
- * as I know): we can have several instances of it running at the same
- * time, even on a monothread program, since it works with callbacks.
- *
- * The lib is designed for a client-side or a server-side use:
- * - server-side: the server receives all data from a socket, including
- * control chars, like arrows, tabulations, ... The client is
- * very simple, it can be a telnet or a minicom through a serial line.
- * - client-side: the client receives its data through its stdin for
- * instance.
+ * as I know): it is possible to have several instances of readline
+ * running at the same time, even on a monothread program, since it
+ * works with callbacks.
*/
#include <cmdline_cirbuf.h>
#define RDLINE_VT100_BUF_SIZE 8
#define RDLINE_HISTORY_BUF_SIZE BUFSIZ
#define RDLINE_HISTORY_MAX_LINE 64
+#define RDLINE_MAX_LINES 23
enum rdline_status {
RDLINE_INIT,
- RDLINE_RUNNING
+ RDLINE_RUNNING,
+ RDLINE_EXITED
};
struct rdline;
-typedef void (rdline_write_char_t)(struct rdline *rdl, char);
+/**
+ * callback given to rdline_help() to display the content of the
+ * help. The first argument is an opaque pointer. The other args
+ * are buffer and size.
+ */
+typedef ssize_t (rdline_write_t)(struct rdline *, void *, size_t);
+
+
typedef void (rdline_validate_t)(struct rdline *rdl,
const char *buf, unsigned int size);
typedef int (rdline_complete_t)(struct rdline *rdl, const char *buf,
- char *dstbuf, unsigned int dstsize,
- int *state);
+ char *dstbuf, unsigned int dstsize);
+typedef int (rdline_help_t)(struct rdline *rdl, const char *buf,
+ rdline_write_t *write, void *opaque);
+
+typedef void (rdline_asyncpager_cb_t)(struct rdline *, void *);
struct rdline {
enum rdline_status status;
+ int fd_in;
+ int fd_out;
+
/* rdline bufs */
struct cirbuf left;
struct cirbuf right;
char right_buf[RDLINE_BUF_SIZE];
char prompt[RDLINE_PROMPT_SIZE];
- unsigned int prompt_size;
#ifndef NO_RDLINE_KILL_BUF
char kill_buf[RDLINE_BUF_SIZE];
#endif
/* callbacks and func pointers */
- rdline_write_char_t *write_char;
rdline_validate_t *validate;
rdline_complete_t *complete;
+ rdline_help_t *help;
/* vt100 parser */
struct cmdline_vt100 vt100;
/* opaque pointer */
void *opaque;
+
+#ifndef NO_PAGER
+ char *pager_buf; /* buffer used to store paged data */
+ int pager_len; /* total len of buffer */
+ int pager_off; /* offset of next data */
+ int pager_lines; /* number of lines displayed */
+ rdline_asyncpager_cb_t *pager_cb;
+ void *pager_arg;
+#endif
};
/**
- * Init fields for a struct rdline. Call this only once at the beginning
- * of your program.
- * \param rdl A pointer to an uninitialized struct rdline
- * \param write_char The function used by the function to write a character
- * \param validate A pointer to the function to execute when the
- * user validates the buffer.
- * \param complete A pointer to the function to execute when the
- * user completes the buffer.
+ * Init fields for a struct rdline.
+ *
+ * @param rdl A pointer to an uninitialized struct rdline
+ * @param fd_in
+ * Input file descriptor
+ * @param fd_out
+ * Output file descriptor
+ * @param validate
+ * A pointer to the function to execute when the user validates the
+ * buffer.
+ * @param complete
+ * A pointer to the function to execute when the user completes the
+ * buffer.
+ * @param help
+ * A pointer to the function to execute when the user ask for
+ * contextual help.
*/
void rdline_init(struct rdline *rdl,
- rdline_write_char_t *write_char,
+ int fd_in, int fd_out,
rdline_validate_t *validate,
- rdline_complete_t *complete);
+ rdline_complete_t *complete,
+ rdline_help_t *help);
/**
* Init the current buffer, and display a prompt.
- * \param rdl A pointer to a struct rdline
- * \param prompt A string containing the prompt
+ *
+ * Also set the rdline status to "running", overriding previous
+ * rdline_stop() or rdline_quit().
+ *
+ * @param rdl
+ * A pointer to an initialized struct rdline
+ * @param prompt
+ * A string containing the prompt
*/
void rdline_newline(struct rdline *rdl, const char *prompt);
/**
- * Call it and all received chars will be ignored.
- * \param rdl A pointer to a struct rdline
+ * Ignore all subsequent received chars.
+ *
+ * @param rdl
+ * A pointer to a struct rdline
*/
void rdline_stop(struct rdline *rdl);
/**
- * Restart after a call to rdline_stop()
- * \param rdl A pointer to a struct rdline
+ * Exit from running rdline loop
+ *
+ * Same than rdline_stop() except that next calls to rdline_char_in()
+ * will return RDLINE_RES_EXITED. Hence, any running rdline() function is
+ * interrupted.
+ *
+ * @param rdl
+ * A pointer to a struct rdline
+ */
+void rdline_quit(struct rdline *rdl);
+
+/**
+ * Restart after a call to rdline_stop() or rdline_quit()
+ *
+ * @param rdl
+ * A pointer to a struct rdline
*/
void rdline_restart(struct rdline *rdl);
/**
* Redisplay the current buffer
- * \param rdl A pointer to a struct rdline
+ *
+ * @param rdl
+ * A pointer to a struct rdline
*/
void rdline_redisplay(struct rdline *rdl);
/* return status for rdline_char_in() */
#define RDLINE_RES_SUCCESS 0
#define RDLINE_RES_VALIDATED 1
-#define RDLINE_RES_COMPLETE 2
#define RDLINE_RES_NOT_RUNNING -1
#define RDLINE_RES_EOF -2
+#define RDLINE_RES_EXITED -3
/**
- * append a char to the readline buffer.
- * Return RDLINE_RES_VALIDATE when the line has been validated.
- * Return RDLINE_RES_COMPLETE when the user asked to complete the buffer.
- * Return RDLINE_RES_NOT_RUNNING if it is not running.
- * Return RDLINE_RES_EOF if EOF (ctrl-d on an empty line).
- * Else return RDLINE_RES_SUCCESS.
- * XXX error case when the buffer is full ?
+ * Append a char to the readline buffer.
*
- * \param rdl A pointer to a struct rdline
- * \param c The character to append
+ * @param rdl
+ * A pointer to a struct rdline
+ * @param c
+ * The character to append
+ * @return
+ * - RDLINE_RES_VALIDATED when the line has been validated.
+ * - RDLINE_RES_NOT_RUNNING if it is not running.
+ * - RDLINE_RES_EOF if EOF (ctrl-d on an empty line).
+ * - RDLINE_RES_EXITED if user called rdline_quit()
+ * - Else return RDLINE_RES_SUCCESS.
*/
int rdline_char_in(struct rdline *rdl, char c);
+/**
+ * Read (and edit) a line
+ *
+ * @param rdl
+ * A pointer to a struct rdline
+ * @param prompt
+ * The prompt string
+ * @return
+ * - RDLINE_RES_VALIDATED when the line has been validated.
+ * - RDLINE_RES_NOT_RUNNING if it is not running.
+ * - RDLINE_RES_EOF if EOF (ctrl-d on an empty line).
+ * - RDLINE_RES_EXITED if user called rdline_quit()
+ */
+int rdline(struct rdline *rdl, const char *prompt);
+
+/**
+ * write a buffer on rdline file descriptor
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param buf
+ * Pointer to the buffer
+ * @param count
+ * Number of bytes to write
+ * @return
+ * On success, the number of bytes written is returned (zero
+ * indicates nothing was written). On error, -1 is returned, and
+ * errno is set appropriately
+ */
+ssize_t rdline_write(const struct rdline *rdl, void *buf, size_t count);
+
+/**
+ * write on rdline file descriptor according to a format string
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param fmt
+ * The format strings
+ * @return
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings). On error, a negative value is returned.
+ */
+int rdline_printf(const struct rdline *rdl, const char *fmt, ...);
+
+/**
+ * write on rdline file descriptor according to a format string
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param fmt
+ * The format strings
+ * @param ap
+ * Variable argument list
+ * @return
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings). On error, a negative value is returned.
+ */
+int rdline_vprintf(const struct rdline *rdl, const char *fmt, va_list ap);
+
/**
* Return the current buffer, terminated by '\0'.
- * \param rdl A pointer to a struct rdline
+ *
+ * @param rdl
+ * A pointer to a struct rdline
+ * @return
+ * The rdline buffer
*/
const char *rdline_get_buffer(struct rdline *rdl);
-
/**
* Add the buffer to history.
- * return < 0 on error.
- * \param rdl A pointer to a struct rdline
- * \param buf A buffer that is terminated by '\0'
+ *
+ * @param rdl
+ * A pointer to a struct rdline
+ * @param buf
+ * A buffer that is terminated by '\0'
+ * @return
+ * - 0 on success
+ * - negative on error
*/
int rdline_add_history(struct rdline *rdl, const char *buf);
/**
* Clear current history
- * \param rdl A pointer to a struct rdline
+ *
+ * @param rdl
+ * A pointer to a struct rdline
*/
void rdline_clear_history(struct rdline *rdl);
/**
* Get the i-th history item
+ *
+ * @param rdl
+ * A pointer to a struct rdline
+ * @param i
+ * The index of the history item
+ * @return
+ * The i-th string of history, or NULL on error.
*/
char *rdline_get_history_item(struct rdline *rdl, unsigned int i);
+#ifndef NO_PAGER
+/**
+ * Write data asynchronously (using pager if needed)
+ *
+ * If there is enough place to print data on the current page, it is
+ * printed synchronously. Else, a temporary buffer is allocated and
+ * the data is stored in it. When the main rdline is called again, the
+ * pager is flushed before parsing any other commands.
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param buf
+ * Buffer to be sent
+ * @param len
+ * Length of buffer to be sent
+ * @return
+ * On success, the number of bytes written is returned (zero
+ * indicates nothing was written). On error, -1 is returned, and
+ * errno is set appropriately
+ */
+ssize_t rdline_asyncpager_write(struct rdline *rdl, void *buf, size_t len);
+
+/**
+ * Print data asynchronously (using pager if needed)
+ *
+ * If there is enough place to print data on the current page, it is
+ * printed synchronously. Else, a temporary buffer is allocated and
+ * the data is stored in it. When the main rdline is called again, the
+ * pager is flushed before parsing any other commands.
+ *
+ * @param rdl
+ * The rdline descriptor
+ * @param fmt
+ * The format strings
+ * @return
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings). On error, a negative value is returned.
+ */
+int rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...);
+
+/**
+ * Set the callback for the pager
+ *
+ * If there is some data in the pager to be printed, set a callback
+ * function that will be called when all the data will be printed. If
+ * the pager is empty, don't do anything and return -1.
+ * @param rdl
+ * The rdline descriptor
+ * @return
+ * - 0 if there is some data in the pager buffer and the callback
+ * is loaded
+ * - -1 if there is no data in pager buffer (in this case the callback
+ * is not called)
+ */
+int rdline_asyncpager_set_cb(struct rdline *rdl, rdline_asyncpager_cb_t *cb,
+ void *arg);
+#endif
+
+
#endif /* _RDLINE_H_ */