Skip to content

Commit c3cb08f

Browse files
committed
License and example added
1 parent cc6c138 commit c3cb08f

File tree

10 files changed

+235
-727
lines changed

10 files changed

+235
-727
lines changed

LICENSE

Lines changed: 21 additions & 674 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,92 @@
11
# Commander API
2-
Commander API is a C API to interpret character based commands and map them to their functions easily
2+
3+
**Version 1.0.0**
4+
5+
Commander API is a C API to interpret character based commands and map them to their functions easily. It is designed mainly to work with low memory capacity devices for example small ARM devices or some embedded stuff.
6+
7+
8+
9+
## Installation
10+
11+
Installation is easy. Jus add __interpreter.h__, and __interpreter.c__ files to your project.
12+
13+
## Usage
14+
15+
First you have to add the two files to your project. Than you have to create the instruction data in __interpreter.c__ file under the following comment:
16+
17+
'''c
18+
// +---- Create instruction data for the API ----+
19+
// | |
20+
// | This is where you have to add |
21+
// | your commands! |
22+
// | |
23+
// +-----------------------------------------------+
24+
25+
create_instruction_data(stop, "basic stop command");
26+
'''
27+
28+
Use the __create_instruction_data()__ macro to add your commands to the interpreter like above. You have to do this for every instruction that you want to add. The first argument is the exact command name( this will be the exact command name! ), and the second one is a short description. Note that the first argument __must not have any quotes before and after!__
29+
30+
The next step is to match the functions to your commands. You have to do it in interpreter.c file, in the init_interpreter() function, under the following comment:
31+
32+
'''c
33+
// +---- Match instruction to it's function ----+
34+
// | |
35+
// | This is where you have to match |
36+
// | every instruction name to it's |
37+
// | function. |
38+
// | |
39+
// +-----------------------------------------------+
40+
add_instruction(stop, stop_func);
41+
'''
42+
43+
Use the __add_instruction()__ macro to match the name and the asociated function like above. You have to do this for every instruction that you have added previously. The first argument is the instruction name __exactly like the previous step__, the second argument is the function that you want to use when this command gets executed. This function has to be a __void__ return type with two arguments. The first argument is a __char*__ type and the second one is a __int(*resp_fn)(const char*, ...)__ type. I know that it looks scary but it can be very handy and you have to just copy the example function to create a new one.
44+
45+
The next thing you have to do is to specify the number of commands you have been added. It can be done in the __interpreter.h__ file under the following comment:
46+
47+
'''c
48+
// +---- Set the correct values ----+
49+
// | |
50+
// | NUM_OF_API_FUNCS value has |
51+
// | to be exact! |
52+
// | |
53+
// +----------------------------------+
54+
55+
#define NUM_OF_API_FUNCS 4
56+
'''
57+
58+
Modify the __NUM_OF_API_FUNCS__ value to the right number unless __the program will crash!__
59+
60+
The last thing you have to do is to actually create your functions. A simple example function can be like this:
61+
62+
'''c
63+
void stop_func(char *args, int(*resp_fn)(const char*, ...))
64+
{
65+
printf("STOP!\r\n");
66+
printf("Args: %s\r\n", args);
67+
68+
// Always check the response function channel!
69+
// If it's a NULL pointer you can't use it,
70+
// because itt will crash your porgram!
71+
if( resp_fn != NULL ){
72+
73+
resp_fn( "Wow! Magic!!!!\r\n" );
74+
75+
}
76+
}
77+
'''
78+
79+
The example function above shows the function of the response function. The interpreter can send messages back to the sender channel. If not used just pass a __null__ pointer to it.
80+
81+
## How it works, why to use?
82+
The library does not use any malloc or dynamic memory. The module creates a balanced binary tree by alphabetical order in initialization time. The memory requirement of this tree can be calculated at compile time if we know how many instructions we have. This is why you must configure __NUM_OF_API_FUNCS__ symbol correctly! To create the balanced tree it is a bit more compute hungry than the old strcmp method, but the tree method will boost significantly the speed in search time, so I think it's worth it. In the worst case it finds a command in O*log2(N). That means it can find a command(if it exists) in a __1024__ element long command list under __10__ search steps.
83+
84+
## Contributing
85+
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
86+
87+
Please make sure to update tests as appropriate.
88+
89+
90+
## License & copyright
91+
© Daniel Hajnal
92+
Licensed under the [MIT License](https://choosealicense.com/licenses/mit/)

inc/interpreter.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,21 @@
77
#include <stdint.h>
88
#include <string.h>
99

10-
#define NUM_OF_API_FUNCS 8
11-
#define MAX_RESP_LEN 100
12-
#define CMD_BUFF_LEN 30
10+
// +---- Set the correct values ----+
11+
// | |
12+
// | NUM_OF_API_FUNCS value has |
13+
// | to be exact! |
14+
// | |
15+
// +----------------------------------+
16+
17+
#define NUM_OF_API_FUNCS 4
18+
19+
// comment out if you does not want to get debug messages
20+
#define INTERPRETER_DBG printf
21+
22+
// configure it if necessary
23+
// it has to be printf like( int( * )( const char*, ... ) )
24+
#define INTERPRETER_PRINTF printf
1325

1426
// structure for instruction data
1527
typedef struct API_t{
@@ -19,13 +31,12 @@ typedef struct API_t{
1931
struct API_t *right; // Right element on a binary tree branch
2032
const char **name; // Name of the instruction
2133
const char **desc; // Description of the command
22-
void(*func)(char*,char*); // Function pointer to the command function
23-
//void(*resp_fn)(char*, ...)
34+
void(*func)(char*,int(*resp_fn)(const char*, ...)); // Function pointer to the command function
2435

2536
}API_t;
2637

2738

28-
void add_interpreter_instruction(const char **name, const char **desc, void(*func)(char*,char*));
39+
void add_interpreter_instruction(const char **name, const char **desc, void(*func)(char*,int(*resp_fn)(const char*, ...)));
2940

3041
void init_interpreter(void);
3142

@@ -43,7 +54,7 @@ void swap_api_elements( uint16_t index, uint16_t place );
4354

4455
void recursive_optimiser( int32_t start_index, int32_t stop_index );
4556

46-
void execute( char *cmd, char *response );
57+
void execute( char *cmd, int(*resp_fn)(const char*, ...) );
4758

4859
void teszt(void);
4960

interpreter.d

Lines changed: 0 additions & 1 deletion
This file was deleted.

main.d

Lines changed: 0 additions & 1 deletion
This file was deleted.

myapp.exe

-122 KB
Binary file not shown.

obj/interpreter.o

-5.93 KB
Binary file not shown.

obj/main.o

-1.16 KB
Binary file not shown.

src/interpreter.c

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,80 @@ uint32_t API_place_cntr;
1010
const char *name##_API_NAME = (const char *)#name; \
1111
const char *name##_API_DESC = (const char *)desc;
1212

13-
// ***** Create instruction data for the API *****
14-
create_instruction_data(cica, "cica fuggveny leirasa, jeeee :)");
15-
create_instruction_data(kutya, "kutya fuggveny leirasa, joooo :)");
16-
create_instruction_data(tehen, "tehen fuggveny leirasa, jii :)");
17-
create_instruction_data(majom, "majom fuggveny leirasa, jaaaa :)");
18-
create_instruction_data(eger, "eger fuggveny leirasa, gyoooo :)");
19-
create_instruction_data(okor, "eger fuggveny leirasa, gyaaa :)");
20-
create_instruction_data(csiga, "eger fuggveny leirasa, dikk :)");
21-
create_instruction_data(v, "Vagod csotany, hihihiiii ;)");
22-
2313
#define add_instruction(name, func) add_interpreter_instruction(&name##_API_NAME, &name##_API_DESC, func);
2414

25-
void cica_func(char *args, char *response)
15+
16+
// +---- Create instruction data for the API ----+
17+
// | |
18+
// | This is where you have to add |
19+
// | your commands! |
20+
// | |
21+
// +-----------------------------------------------+
22+
23+
create_instruction_data(stop, "basic stop command");
24+
create_instruction_data(start, "basic start command");
25+
create_instruction_data(left, "command used to turn left");
26+
create_instruction_data(right, "command used to turn right");
27+
28+
29+
// This is an example function for the stop command
30+
void stop_func(char *args, int(*resp_fn)(const char*, ...))
31+
{
32+
printf("STOP!\r\n");
33+
printf("Args: %s\r\n", args);
34+
35+
// Always check the response function channel!
36+
// If it's a NULL pointer you can't use it,
37+
// because itt will crash your porgram!
38+
if( resp_fn != NULL ){
39+
40+
resp_fn( "Wow! Magic!!!!\r\n" );
41+
42+
}
43+
}
44+
45+
// This is an example function for the start command
46+
void start_func(char *args, int(*resp_fn)(const char*, ...))
47+
{
48+
printf("START!\r\n");
49+
printf("Args: %s\r\n", args);
50+
51+
}
52+
53+
// This is an example function for the left command
54+
void left_func(char *args, int(*resp_fn)(const char*, ...))
2655
{
27-
printf("Cica!\r\n");
56+
printf("Turning left!\r\n");
2857
printf("Args: %s\r\n", args);
58+
2959
}
3060

31-
void kutya_func(char *args, char *response)
61+
// This is an example function for the right command
62+
void right_func(char *args, int(*resp_fn)(const char*, ...))
3263
{
33-
printf("Kutya!\r\n");
64+
printf("Turning right!\r\n");
3465
printf("Args: %s\r\n", args);
66+
3567
}
3668

69+
3770
void init_interpreter(void)
3871
{
3972
// Initialize the 'API_cntr' variable as zero before adding new items
4073
API_cntr = 0;
4174

42-
// ***** Create the binary tree of the instructions *****
43-
add_instruction(majom, kutya_func);
44-
add_instruction(tehen, kutya_func);
45-
add_instruction(cica, cica_func);
46-
add_instruction(kutya, kutya_func);
47-
add_instruction(eger, kutya_func);
48-
add_instruction(okor, kutya_func);
49-
add_instruction(csiga, kutya_func);
50-
add_instruction(v, kutya_func);
75+
// +---- Match instruction to it's function ----+
76+
// | |
77+
// | This is where you have to match |
78+
// | every instruction name to it's |
79+
// | function. |
80+
// | |
81+
// +-----------------------------------------------+
82+
add_instruction(stop, stop_func);
83+
add_instruction(start, start_func);
84+
add_instruction(left, left_func);
85+
add_instruction(right, right_func);
86+
5187

5288
// Index eache element to find their place in alphabetic order
5389
index_apis_in_order( &API_tree[0] );
@@ -59,11 +95,15 @@ void init_interpreter(void)
5995
print_apis_in_order( &API_tree[0] );
6096

6197
if( API_cntr != NUM_OF_API_FUNCS ){
62-
printf("**ERROR**\tAPI function number mismatch!!!\r\n");
98+
99+
#ifdef INTERPRETER_DBG
100+
INTERPRETER_DBG( "**ERROR**\tAPI function number mismatch!!!\r\n" );
101+
#endif
102+
63103
}
64104
}
65105

66-
void add_interpreter_instruction(const char **name, const char **desc, void (*func)(char *, char *))
106+
void add_interpreter_instruction(const char **name, const char **desc, void (*func)(char *, int(*resp_fn)(const char*, ...)))
67107
{
68108
API_t *next;
69109
API_t *prev;
@@ -74,7 +114,10 @@ void add_interpreter_instruction(const char **name, const char **desc, void (*fu
74114
if (API_cntr >= NUM_OF_API_FUNCS)
75115
{
76116

77-
printf("**ERROR**\tToo many instruction, memory is full!\r\n");
117+
#ifdef INTERPRETER_DBG
118+
INTERPRETER_DBG( "**ERROR**\tToo many instruction, memory is full!\r\n" );
119+
#endif
120+
78121
return;
79122
}
80123

@@ -141,7 +184,10 @@ void index_apis_in_order(API_t *head){
141184

142185
recursive_indexer( head );
143186

144-
printf( "Indexer finished...\r\n" );
187+
#ifdef INTERPRETER_DBG
188+
INTERPRETER_DBG( "Indexer finished...\r\n" );
189+
#endif
190+
145191

146192
}
147193

@@ -173,7 +219,7 @@ void print_apis_in_order(API_t *head){
173219
}
174220

175221
print_apis_in_order( head -> left );
176-
printf( "%d.\t%s\r\n", head -> place , *(head -> name) );
222+
INTERPRETER_PRINTF( "%d.\t%s\r\n", head -> place , *(head -> name) );
177223
print_apis_in_order( head -> right );
178224

179225
}
@@ -277,7 +323,7 @@ void recursive_optimiser( int32_t start_index, int32_t stop_index ){
277323

278324
}
279325

280-
void execute( char *cmd, char *response ){
326+
void execute( char *cmd, int(*resp_fn)(const char*, ...) ){
281327

282328
API_t *next;
283329
API_t *prev;
@@ -310,16 +356,14 @@ void execute( char *cmd, char *response ){
310356

311357
prev = &API_tree[0];
312358

313-
//comp_res = strncmp( (char*)*(prev->name), cmd, cmd_name_cntr );
314-
315359
comp_res = strncmp( (char*)*(prev->name), cmd, strlen( (char*)*(prev->name) ) );
316360

317361
(comp_res > 0) ? (next = (prev->left)) : ( next = (prev->right));
318362

319363
while( ( comp_res !=0 ) && ( next != NULL ) ){
320364

321365
prev = next;
322-
//comp_res = strncmp( (char*)*(prev->name), cmd, cmd_name_cntr );
366+
323367
comp_res = strncmp( (char*)*(prev->name), cmd, strlen( (char*)*(prev->name) ) );
324368

325369
(comp_res > 0) ? (next = (prev->left)) : ( next = (prev->right));
@@ -328,13 +372,13 @@ void execute( char *cmd, char *response ){
328372

329373
if( comp_res == 0 ){
330374

331-
(prev -> func)( arg, response );
375+
(prev -> func)( arg, resp_fn );
332376

333377
}
334378

335379
else{
336380

337-
printf( "Command \'%s\' not found!!!\r\n", cmd );
381+
INTERPRETER_PRINTF( "Command \'%s\' not found!!!\r\n", cmd );
338382

339383
}
340384

src/main.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,42 @@
55

66
int main(){
77

8-
char response[100];
8+
// The interpreter modifies the content of
9+
// the string it gets. Make shore you backup
10+
// it before use it is used after.
11+
// Also note that this variable must not have
12+
// a const type. const char* as argument will
13+
// cause crash!
14+
char cmd_to_execute[100] = "stop 10";
915

10-
char cmd[100] = "cica 1";
16+
printf("Program begin...\r\n");
1117

12-
printf("Program START...\r\n");
18+
// Interpreter initialization code
19+
init_interpreter();
1320

21+
// Execute string stored in cmd_to_execute
22+
execute( cmd_to_execute, printf );
1423

15-
init_interpreter();
24+
// Try with empty response function
25+
execute( cmd_to_execute, NULL );
1626

27+
// Modify the content of cmd_to_execute
28+
strcpy( cmd_to_execute, "start 31" );
29+
// Execute string stored in cmd_to_execute
30+
execute( cmd_to_execute, printf );
1731

18-
execute( cmd, response );
32+
// Modify the content of cmd_to_execute
33+
strcpy( cmd_to_execute, "left 3" );
34+
// Execute string stored in cmd_to_execute
35+
execute( cmd_to_execute, printf );
1936

20-
strcpy( cmd, "kutya 10" );
21-
execute( cmd, response );
37+
// Modify the content of cmd_to_execute
38+
strcpy( cmd_to_execute, "right 0" );
39+
// Execute string stored in cmd_to_execute
40+
execute( cmd_to_execute, printf );
2241

23-
strcpy( cmd, "retek 10" );
24-
execute( cmd, response );
2542

43+
printf( "Program end..." );
2644

2745
return 0;
2846
}

0 commit comments

Comments
 (0)