Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ronen25/libcmdf

Single-header library for writing CLI applications in C/C++
https://github.com/ronen25/libcmdf

c cli cmd cmdf cmdline cmdline-parser command-line-parser cplusplus gnu-readline readline single-header single-header-lib

Last synced: 3 months ago
JSON representation

Single-header library for writing CLI applications in C/C++

Awesome Lists containing this project

README

        

libcmdf.h
=============
A simple library for writing command-line applications, inspired by Python's [cmd](https://docs.python.org/3/library/cmd.html) module.

----------------------------------------------

***Latest version: v.1.4.0 (2022-12-09)***

----------------------------------------------

Features
--------
1. Written using 100% ANSI C
2. Header only: no linkage! No separate compilation!
3. Cross-platform
4. GNU Readline support
5. Can be used from C++ (without `-fpermissive`)

Requirements
------------
1. **Any ANSI C/ISO C90-compliant compiler**

*Tested on GCC 5.4+, clang 4.0+, Apple Clang 14, and MSVC 14.0*
2. **Linux/Windows/Mac**

*Tested on Ubuntu 16.04 - 20.04, Fedora 26 - 30, Windows 10 (all AMD64) and Mac (M1)*
3. **GNU Readline development libraries (optional)**

*Required for GNU Readline support, if enabled.*

Usage
------
Being a header-only library, you don't need to do any complex linkage - just drop it in your project tree and you're done!

You will, however, need to define LIBCMDF_IMPL **only once**, and **before you include the library**, like this:

```
#define LIBCMDF_IMPL
#include

...
```

API in a nutshell
--------------------
First of all, you must initialize libcmdf by calling either `cmdf_init_quick()` or `cmdf_init`:
```
void cmdf_init(const char *prompt, const char *intro, const char *doc_header,
const char *undoc_header, char ruler, int use_default_exit);
#define cmdf_init_quick() cmdf_init(NULL, NULL, NULL, NULL, 0, 1)
```

The two most important parameters are the prompt and the intro:

**prompt** - The prompt for every command.

**intro** - A text that is displayed to the user on program startup.

After initialization is done, you must then register some **command callbacks**.
A command callback has a **command name** associated with it, and that can be executed
by the user, which in turn will execute the associated command callback.

The command callback has the following format:
```
typedef CMDF_RETURN (* cmdf_command_callback)(cmdf_arglist *arglist);
```

CMDF_RETURN is a typedefd integer specifying a return code.
arglist is a pointer to the arguments passed by the user along with the command,
which libcmdf transperantly handles behind the scenes. It is destroyed by libcmdf when the command callback
returns.

This simple structure contains two elements:
```
/* libcmdf command list and arglist */
typedef struct cmdf___arglist_s {
char **args; /* NULL-terminated string list */
size_t count; /* Argument list count */
} cmdf_arglist;

```

This way you can quickly iterate the command-line arguments and act accordingly.

After you have your command callback, simply register it using `cmdf_register_command`:
```
CMDF_RETURN cmdf_register_command(cmdf_command_callback callback, const char *cmdname,
const char *help);
```

Note that you may provide an optional help message. If you do, the user will be able to see it when and if
he will request it using the `help` command.

After that, initialization of the library is pretty much complete, so you can just call the main command loop:
```
cmdf_commandloop();
```

In any case you may refer to test.c for a working example.

Configuration
---------------
The library can be configured by #defineing any of the following definitions **only once, before including the library**:

|Definition|Description|Default|
|----------|-----------|-------|
|CMDF_MAX_COMMANDS|Maxmium amount of allowed commands.|24|
|CMDF_TAB_TO_SPACES|If a tab is encountered in a command's help string, expand it to N spaces.|8|
|CMDF_READLINE_SUPPORT|Enable/disable GNU readline support (Linux only, requires readline development libraries)|(*Disabled*)|
|CMDF_FGETS|A fgets()-like function, to be used for command-line input.|fgets()|
|CMDF_MALLOC|A malloc()-like function, to be used for memory allocations1.|malloc()|
|CMDF_FREE|A free()-like function, to be used for memory deallocations1.|free()|
|CMDF_MAX_INPUT_BUFFER_LENGTH|The maximum length of the input buffer used to get user input1.|256|
|CMDF_STDOUT|A FILE * to be used as standard output.|stdout|
|CMDF_STDIN|A FILE * to be used as standard input.|stdin|

1 Note: GNU Readline will **not** use any custom memory allocation functions, but rather the standard library's malloc and free. Also, you may have to provide additional linker flags to link against readline.

To configure libcmdf simply define any configuration definitions **once and before LIBCMDF_IMPL**, like so:
```
#define CMDF_READLINE_SUPPORT /* Enable readline support */
#define LIBCMDF_IMPL
#include

...
```

Feedback
---------
I tested the library to the best of my abilities, but there might still be some bugs.

If you do find them, please contact me or open an issue!

FAQ
----
### Is the library thread-safe?
No, but it's just handling user input for CLI, so I honestly don't think it should be.

### Why is cmdf_quit not implemented?
At the moment, the initialization routines don't allocate any memory, or perform any weird
initialization tricks that require deinitalization.

This might change in the future, though, so make sure to call cmdf_quit when you're done with it!

### Any plans to implement a proper C++ API, Linenoise/anything else?
I initially had plans to implement a lot of features.
However, I'm not working with C/C++ professionally anymore so my interest in these languages
and the ecosystem has somewhat dwindled.

This does not affect the development status of this library - it will still be maintained and developed.

-------------------------------------------------------------------------------------------------------

License
--------
This software is dual-licensed to the public domain and under the following license:
you are granted a perpetual, irrevocable license to copy, modify,
publish and distribute this file as you see fit.