├── .gitignore ├── Makefile ├── README.md ├── package.json ├── readline.c ├── readline.h └── test.c /.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | *.o 3 | *.DS_Store 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -Wall -pedantic -std=c99 2 | 3 | test: readline.c test.c 4 | @$(CC) $^ $(CFLAGS) -o $@ 5 | @./test 6 | 7 | .PHONY: test 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | readline 2 | ================ 3 | 4 | Tiny C readline library, note: this is not used in CLI-readline's one. 5 | 6 | 7 | Installation 8 | ================== 9 | 10 | Install it with git 11 | 12 | ```bash 13 | $ git clone https://github.com/yorkie/readline.git master 14 | ``` 15 | 16 | Install it with [clib](https://github.com/clibs/clib) 17 | 18 | ```bash 19 | $ clib install clibs/readline 20 | ``` 21 | 22 | Get Started 23 | ================= 24 | 25 | ```c 26 | #include "readline.h" 27 | 28 | readline_t * rl = readline_new(text); 29 | char * line; 30 | 31 | do { 32 | line = readline_next(rl); 33 | // get line. 34 | 35 | } while (line != NULL); 36 | 37 | // free memory 38 | readline_free(rl); 39 | ``` 40 | 41 | API 42 | ================= 43 | 44 | ```c 45 | 46 | /* 47 | * Create a context of readline from a buffer 48 | */ 49 | readline_t * 50 | readline_new(char * buffer); 51 | 52 | /* 53 | * Get the next line of the context 54 | */ 55 | char * 56 | readline_next(readline_t * rl); 57 | 58 | /* 59 | * Get last line of a buffer, ignoring any context of readline 60 | */ 61 | char * 62 | readline_last_from_rl(readline_t * rl); 63 | 64 | /* 65 | * Get the last line directly buffer 66 | */ 67 | char * 68 | readline_last(char * buffer); 69 | 70 | /* 71 | * free the object 72 | */ 73 | void 74 | readline_free(readline_t * rl); 75 | ``` 76 | 77 | 78 | License 79 | =================== 80 | 81 | MIT 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "readline", 3 | "version": "0.0.2", 4 | "repo": "clibs/readline", 5 | "description": "Tiny C readline library", 6 | "keywords": ["readline", "tiny"], 7 | "license": "MIT", 8 | "src": ["readline.c", "readline.h"] 9 | } -------------------------------------------------------------------------------- /readline.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // readline.c 4 | // 5 | // Copyright (c) 2014 Yorkie Neil 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "readline.h" 13 | 14 | readline_t * 15 | readline_new(char * buffer) { 16 | readline_t * rl = (readline_t*) calloc(1, sizeof(readline_t)); 17 | if (NULL == rl) { 18 | return rl; 19 | } 20 | size_t len = strlen(buffer); 21 | 22 | rl->buffer = (char*) malloc(len); 23 | if( NULL == rl->buffer ) { 24 | free(rl); 25 | return NULL; 26 | } 27 | 28 | memcpy(rl->buffer, buffer, len); 29 | return rl; 30 | } 31 | 32 | char * 33 | readline_next(readline_t * rl) { 34 | char * ret = NULL; 35 | size_t cur = rl->cursor; 36 | size_t len; 37 | size_t buffer_len = strlen(rl->buffer); 38 | 39 | assert(rl->buffer != NULL); 40 | 41 | while ( 42 | rl->buffer[cur++] != '\n' && 43 | cur <= buffer_len); 44 | 45 | len = cur - rl->cursor - 1; 46 | ret = (char*) malloc(len); 47 | 48 | if (ret == NULL) { 49 | return NULL; 50 | } else if (len == 0 && cur > buffer_len) { 51 | free(ret); 52 | return NULL; 53 | } 54 | 55 | memcpy(ret, rl->buffer+rl->cursor, len); 56 | rl->cursor = cur; 57 | rl->line += 1; 58 | return ret; 59 | } 60 | 61 | char * 62 | readline_last_from_rl(readline_t * rl) { 63 | char * ret = NULL; 64 | size_t cur = strlen(rl->buffer)-1; /* skip \0 of the last line */ 65 | size_t len; 66 | size_t buffer_len = cur; 67 | 68 | assert(rl->buffer != NULL); 69 | 70 | while (cur--) { 71 | if (rl->buffer[cur] == '\n') { 72 | cur++; 73 | break; 74 | } 75 | } 76 | 77 | len = buffer_len - cur; 78 | ret = (char*) malloc(len); 79 | 80 | if (ret == NULL) { 81 | return NULL; 82 | } else if (len == 0 && cur > buffer_len) { 83 | free(ret); 84 | return NULL; 85 | } 86 | 87 | memcpy(ret, rl->buffer+cur, len); 88 | return ret; 89 | } 90 | 91 | char * 92 | readline_last(char * buffer) { 93 | readline_t * rl = readline_new(buffer); 94 | if (NULL == rl) { 95 | return NULL; 96 | } 97 | char * ret = readline_last_from_rl(rl); 98 | readline_free(rl); 99 | return ret; 100 | } 101 | 102 | void 103 | readline_free(readline_t * rl) { 104 | assert(rl->buffer != NULL); 105 | assert(rl != NULL); 106 | 107 | free(rl->buffer); 108 | free(rl); 109 | } 110 | -------------------------------------------------------------------------------- /readline.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // readline.h 4 | // 5 | // Copyright (c) 2014 Yorkie Neil 6 | // 7 | 8 | #ifndef READLINE__H_ 9 | #define READLINE__H_ 10 | 11 | /* 12 | * Readline struct 13 | */ 14 | 15 | typedef struct readline_s { 16 | char * buffer; 17 | size_t cursor; 18 | size_t line; 19 | } readline_t; 20 | 21 | /* 22 | * create a new readline struct 23 | */ 24 | readline_t * 25 | readline_new(char * buffer); 26 | 27 | /* 28 | * next cursor 29 | */ 30 | char * 31 | readline_next(readline_t * rl); 32 | 33 | /* 34 | * Get last line of a buffer, ignoring any context of readline 35 | */ 36 | char * 37 | readline_last_from_rl(readline_t * rl); 38 | 39 | /* 40 | * Get the last line directly buffer 41 | */ 42 | char * 43 | readline_last(char * buffer); 44 | 45 | /* 46 | * free the object 47 | */ 48 | void 49 | readline_free(readline_t * rl); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "readline.h" 7 | 8 | #define test_start() \ 9 | printf("\n================\n") \ 10 | 11 | /* 12 | * Reads two lines 13 | */ 14 | void 15 | test_readline_simple() { 16 | 17 | test_start(); 18 | char * buf = "" \ 19 | "c++\n" 20 | "lua\n"; 21 | 22 | readline_t * rl = readline_new(buf); 23 | char * line = NULL; 24 | size_t count = 0; 25 | 26 | while ((line = (readline_next(rl))) != NULL) { 27 | count++; 28 | printf("line: %s\n", line); 29 | } 30 | 31 | assert(count == 2); 32 | printf("\t OK\n"); 33 | } 34 | 35 | /* 36 | * Reads 3 lines, including an empty line 37 | */ 38 | void 39 | test_readline_empty_line() { 40 | test_start(); 41 | char * buf = "" \ 42 | "c++\n" 43 | "\n" 44 | "javascript"; 45 | 46 | readline_t * rl = readline_new(buf); 47 | char * line = NULL; 48 | size_t count = 0; 49 | 50 | while ((line = (readline_next(rl))) != NULL) { 51 | count++; 52 | printf("line: %s\n", line); 53 | } 54 | 55 | assert(count == 3); 56 | printf("\t OK\n"); 57 | } 58 | 59 | /* 60 | * Reads the last line 61 | */ 62 | void 63 | test_readline_last_line() { 64 | 65 | test_start(); 66 | char * buf = "" \ 67 | "c++\n" 68 | "lua\n" 69 | "javascript"; 70 | 71 | readline_t * rl = readline_new(buf); 72 | char * line = NULL; 73 | size_t count = 0; 74 | 75 | while ((line = (readline_next(rl))) != NULL) { 76 | count++; 77 | printf("line: %s\n", line); 78 | assert(count <= 3); 79 | } 80 | 81 | assert(count == 3); 82 | printf("\t OK\n"); 83 | } 84 | 85 | /* 86 | * Reads the last that isn't empty 87 | */ 88 | void 89 | test_readline_last_empty_line() { 90 | 91 | test_start(); 92 | char * buf = "" \ 93 | "c++\n" 94 | "lua\n" 95 | ""; 96 | 97 | readline_t * rl = readline_new(buf); 98 | char * line = NULL; 99 | size_t count = 0; 100 | 101 | while ((line = (readline_next(rl))) != NULL) { 102 | count++; 103 | printf("line: %s\n", line); 104 | } 105 | 106 | assert(count == 2); 107 | printf("\t OK\n"); 108 | } 109 | 110 | /* 111 | * Reads the last line 112 | */ 113 | void 114 | test_readline_last() { 115 | 116 | test_start(); 117 | char * buf = "" \ 118 | "c++\n" 119 | "lua\n" 120 | "javascript\n"; 121 | 122 | char * last = readline_last(buf); 123 | printf("last: %s\n", last); 124 | 125 | assert(strcmp("javascript", last) == 0); 126 | printf("\t OK\n"); 127 | } 128 | 129 | /* 130 | * Reads the last line without \n 131 | */ 132 | void 133 | test_readline_last_without_10() { 134 | 135 | test_start(); 136 | char * buf = "" \ 137 | "c++\n" 138 | "lua\n" 139 | "javascript"; 140 | 141 | char * last = readline_last(buf); 142 | printf("last: %s\n", last); 143 | 144 | assert(strcmp("javascript", last) == 0); 145 | printf("\t OK\n"); 146 | } 147 | 148 | 149 | int 150 | main() { 151 | 152 | /* next func */ 153 | test_readline_simple(); 154 | test_readline_empty_line(); 155 | test_readline_last_line(); 156 | test_readline_last_empty_line(); 157 | 158 | /* last line */ 159 | test_readline_last(); 160 | test_readline_last_without_10(); 161 | return 0; 162 | } 163 | --------------------------------------------------------------------------------