• Stars
    star
    326
  • Rank 129,064 (Top 3 %)
  • Language
    C
  • License
    The Unlicense
  • Created about 10 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Portable, reentrant, getopt-like option parser

Optparse

Optparse is a public domain, portable, reentrant, embeddable, getopt-like option parser. As a single header file, it's trivially dropped into any project. It supports POSIX getopt option strings, GNU-style long options, argument permutation, and subcommand processing.

To get the implementation, define OPTPARSE_IMPLEMENTATION before including optparse.h.

#define OPTPARSE_IMPLEMENTATION
#include "optparse.h"

Optionally define OPTPARSE_API to control the API's visibility and/or linkage (static, __attribute__, __declspec).

#define OPTPARSE_API static
#include "optparse.h"

Why not getopt()?

The POSIX getopt option parser has three fatal flaws. These flaws are solved by Optparse.

  1. The getopt parser state is stored entirely in global variables, some of which are static and inaccessible. This means only one thread can use getopt. It also means it's not possible to recursively parse nested sub-arguments while in the middle of argument parsing. Optparse fixes this by storing all state on a local struct.

  2. The POSIX standard provides no way to properly reset the parser. For portable code this means getopt is only good for one run, over one argv with one option string. It also means subcommand options cannot be reliably processed with getopt. Most implementations provide an implementation-specific method to reset the parser, but this is not portable. Optparse provides an optparse_arg() function for stepping through non-option arguments, and parsing of options can continue again at any time with a different option string. The Optparse struct itself could be passed around to subcommand handlers for additional subcommand option parsing. If a full parser reset is needed, optparse_init() can be called again.

  3. In getopt, error messages are printed to stderr. This can be disabled with opterr, but the messages themselves are still inaccessible. Optparse solves this by writing the error message to its errmsg field, which can be printed to anywhere. The downside to Optparse is that this error message will always be in English rather than the current locale.

Permutation

By default, argv is permuted as it is parsed, moving non-option arguments to the end of the array. This can be disabled by setting the permute field to 0 after initialization.

struct optparse options;
optparse_init(&options, argv);
options.permute = 0;

Drop-in Replacement

Optparse's interface should be familiar with anyone accustomed to getopt. It's nearly a drop-in replacement. The option string has the same format and the parser struct fields have the same names as the getopt global variables (optarg, optind, optopt).

The long option parser optparse_long() API is very similar to GNU's getopt_long() and can serve as a portable, embedded replacement.

Optparse does not allocate memory. Furthermore, Optparse has no dependencies, including libc itself, so it can be used in situations where the standard C library cannot.

See optparse.h for full API documentation.

Example Usage

Here's a traditional getopt setup.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getopt.h>

int main(int argc, char **argv)
{
    bool amend = false;
    bool brief = false;
    const char *color = "white";
    int delay = 0;

    int option;
    while ((option = getopt(argc, argv, "abc:d::")) != -1) {
        switch (option) {
        case 'a':
            amend = true;
            break;
        case 'b':
            brief = true;
            break;
        case 'c':
            color = optarg;
            break;
        case 'd':
            delay = optarg ? atoi(optarg) : 1;
            break;
        case '?':
            exit(EXIT_FAILURE);
        }
    }

    /* Print remaining arguments. */
    for (; optind < argc; optind++)
        printf("%s\n", argv[optind]);
    return 0;
}

Here's the same thing translated to Optparse.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define OPTPARSE_IMPLEMENTATION
#define OPTPARSE_API static
#include "optparse.h"

int main(int argc, char **argv)
{
    bool amend = false;
    bool brief = false;
    const char *color = "white";
    int delay = 0;

    char *arg;
    int option;
    struct optparse options;

    optparse_init(&options, argv);
    while ((option = optparse(&options, "abc:d::")) != -1) {
        switch (option) {
        case 'a':
            amend = true;
            break;
        case 'b':
            brief = true;
            break;
        case 'c':
            color = options.optarg;
            break;
        case 'd':
            delay = options.optarg ? atoi(options.optarg) : 1;
            break;
        case '?':
            fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
            exit(EXIT_FAILURE);
        }
    }

    /* Print remaining arguments. */
    while ((arg = optparse_arg(&options)))
        printf("%s\n", arg);
    return 0;
}

And here's a conversion to long options.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define OPTPARSE_IMPLEMENTATION
#define OPTPARSE_API static
#include "optparse.h"

int main(int argc, char **argv)
{
    struct optparse_long longopts[] = {
        {"amend", 'a', OPTPARSE_NONE},
        {"brief", 'b', OPTPARSE_NONE},
        {"color", 'c', OPTPARSE_REQUIRED},
        {"delay", 'd', OPTPARSE_OPTIONAL},
        {0}
    };

    bool amend = false;
    bool brief = false;
    const char *color = "white";
    int delay = 0;

    char *arg;
    int option;
    struct optparse options;

    optparse_init(&options, argv);
    while ((option = optparse_long(&options, longopts, NULL)) != -1) {
        switch (option) {
        case 'a':
            amend = true;
            break;
        case 'b':
            brief = true;
            break;
        case 'c':
            color = options.optarg;
            break;
        case 'd':
            delay = options.optarg ? atoi(options.optarg) : 1;
            break;
        case '?':
            fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
            exit(EXIT_FAILURE);
        }
    }

    /* Print remaining arguments. */
    while ((arg = optparse_arg(&options)))
        printf("%s\n", arg);

    return 0;
}

Subcommand Parsing

To parse subcommands, first parse options with permutation disabled. These are the "global" options that come before the subcommand. Then parse the remainder, optionally permuting, as a new option array.

See examples/subcommands.c for a complete, working example.

More Repositories

1

endlessh

SSH tarpit that slowly sends an endless banner
C
7,113
star
2

w64devkit

Portable C and C++ Development Kit for x64 (and x86) Windows
C
2,871
star
3

elfeed

An Emacs web feeds client
Emacs Lisp
1,371
star
4

skewer-mode

Live web development in Emacs
Emacs Lisp
1,066
star
5

hash-prospector

Automated integer hash function discovery
C
672
star
6

enchive

Encrypted personal archives
C
630
star
7

branchless-utf8

Branchless UTF-8 decoder
C
589
star
8

scratch

Personal scratch code
C
366
star
9

pixelcity

Shamus Young's procedural city project
C++
359
star
10

pdjson

C JSON parser library that doesn't suck
C
279
star
11

interactive-c-demo

Demonstration of interactive C programming
C
249
star
12

emacs-aio

async/await for Emacs Lisp
Emacs Lisp
215
star
13

webgl-particles

WebGL particle system demo
JavaScript
203
star
14

fantasyname

Fantasy name generator
C
180
star
15

lstack

C11 Lock-free Stack
C
172
star
16

resurrect-js

JavaScript serialization that preserves behavior and reference circularity.
JavaScript
169
star
17

passphrase2pgp

Generate a PGP key from a passphrase
Go
168
star
18

pure-linux-threads-demo

Pthreads-free Linux threading demo
Assembly
147
star
19

ptrace-examples

Examples for Linux ptrace(2)
C
134
star
20

memdig

Memory cheat tool for Windows and Linux games
C
131
star
21

dosdefender-ld31

DOS Defender (Ludum Dare #31)
C
130
star
22

dotfiles

My personal dotfiles
Shell
124
star
23

Prelude-of-the-Chambered

Notch's Prelude of the Chambered 48-hour game
Java
124
star
24

sort-circle

Colorful sorting animations
C
124
star
25

.emacs.d

My personal .emacs.d
Emacs Lisp
119
star
26

growable-buf

Growable Memory Buffer for C99
C
116
star
27

youtube-dl-emacs

Emacs youtube-dl download manager
Emacs Lisp
104
star
28

getopt

POSIX getopt() as a portable header library
C
102
star
29

trie

C99 trie library
C
98
star
30

opengl-demo

Minimal OpenGL 3.3 core profile demo
C
97
star
31

Minicraft

Notch's Ludum Dare 22 entry.
Java
95
star
32

igloojs

Low-level, fluent, OOP WebGL wrapper
JavaScript
89
star
33

hastyhex

A blazing fast hex dumper
C
88
star
34

webgl-game-of-life

WebGL Game of Life
JavaScript
88
star
35

u-config

a smaller, simpler, portable pkg-config clone
C
84
star
36

bmp

24-bit BMP (Bitmap) ANSI C header library
C
84
star
37

elisp-ffi

Emacs Lisp Foreign Function Interface
C++
83
star
38

rng-js

JavaScript seedable random number generation tools.
JavaScript
82
star
39

mandel-simd

Mandelbrot set in SIMD (SSE, AVX)
C
81
star
40

sample-java-project

Example Ant-based Java project
Java
78
star
41

nasm-mode

Major mode for editing NASM assembly programs
Emacs Lisp
78
star
42

vulkan-test

Test if your system supports Vulkan
C
77
star
43

gap-buffer-animator

Gap buffer animation creator
C
72
star
44

at-el

Prototype-based Emacs Lisp object system
Emacs Lisp
71
star
45

skeeto.github.com

Personal website/blog
HTML
64
star
46

ulid-c

ULID Library for C
C
62
star
47

xf8

8-bit Xor Filter in C99
C
61
star
48

race64

World's fastest Base64 encoder / decoder
C
58
star
49

devdocs-lookup

Quick Emacs API lookup on devdocs.io
Emacs Lisp
58
star
50

webgl-path-solver

WebGL shortest path solver
JavaScript
57
star
51

x86-lookup

Quickly jump to x86 documentation from Emacs
Emacs Lisp
57
star
52

javadoc-lookup

Quickly lookup Javadoc pages from Emacs
Emacs Lisp
55
star
53

am-i-shadowbanned

Online reddit shadowban test
JavaScript
53
star
54

fun-liquid

Physics engine liquid in Java.
Java
53
star
55

minimail

Embeddable POP3 + SMTP server.
C
50
star
56

emacs-memoize

Elisp memoization functions
Emacs Lisp
48
star
57

webgl-fire

WebGL fire effect
JavaScript
47
star
58

simplegpg

Simplified, signify-like interface to GnuPG signatures
Shell
47
star
59

autotetris-mode

Automatically play Emacs Tetris
Emacs Lisp
45
star
60

fiber-await

Win32 Fiber async/await demo
C
45
star
61

lorenz-webgl

Lorenz System WebGL
JavaScript
42
star
62

asteroids-demo

Asteroids Clone for Windows
C
40
star
63

elisp-json-rpc

JSON-RPC library for Emacs Lisp
Emacs Lisp
39
star
64

hashtab

Simple C hash table
C
37
star
65

pgp-poisoner

PGP key poisoner
Go
36
star
66

bf-x86

x86_64 brainfuck compiler
C
36
star
67

wisp

Wisp, a lisp programming language
C
33
star
68

binitools

Bini file translator for the game Freelancer
C
32
star
69

double-pendulum

JavaScript double pendulum simulation with RK4 integration
JavaScript
30
star
70

predd

Multimethods for Emacs Lisp
Emacs Lisp
29
star
71

atomkv

In-memory, JSON, key-value service with compare-and-swap updates and event streams
Go
29
star
72

purgeable

Purgeable memory allocations for Linux
C
28
star
73

lqueue

C11 + Pthreads Atomic Bounded Work Queue
C
28
star
74

uuid

UUID generator for Go
Go
27
star
75

goblin-com

Goblin-COM roguelike game for 7DRL 2015
C
27
star
76

jekyll-deck

Template for Jekyll / deck.js presentations
27
star
77

rlhk

Roguelike Header Kit
C
26
star
78

voronoi-toy

WebGL interactive Voronoi diagram
JavaScript
26
star
79

transcription-mode

Emacs mode for editing transcripts.
Emacs Lisp
25
star
80

october-chess-engine

Java Chess Engine
Java
25
star
81

boids-js

HTML5 boids (skewer-mode demo)
JavaScript
25
star
82

optparse-go

GNU style long options for Go
Go
24
star
83

geohash

Fast, lean, efficient geohash C library
C
24
star
84

bitpack

Emacs Lisp structure packing
Emacs Lisp
23
star
85

lean-static-gpg

Lean, static GnuPG build for Linux
Shell
23
star
86

connect4

Connect Four AI and Engine
C
22
star
87

blowpipe

Authenticated Blowfish-encrypted pipe
C
22
star
88

markov-text

Markov chain text generation in Emacs Lisp
Emacs Lisp
22
star
89

joymacs

Joystick support for Emacs
C
21
star
90

emacs-rsa

RSA cryptography in Emacs Lisp
Emacs Lisp
21
star
91

live-dev-env

A live CD of my personal development environment
Shell
20
star
92

dynamic-function-benchmark

Benchmark for three different kinds of dynamic function calls
C
20
star
93

utf-7

UTF-7 encoder and decoder in ANSI C
C
19
star
94

elisp-fakespace

Emacs Lisp namespaces (defpackage)
Emacs Lisp
18
star
95

siphash

Incremental SipHash in C
C
18
star
96

bencode-c

Bencode decoder in ANSI C
C
17
star
97

british-square

British Square Engine (Analysis and Perfect AI Player)
C
17
star
98

pokerware

Pokerware Secure Passphrase Generation
Makefile
17
star
99

xxtea

100% XXTEA authenticated, chunked file encryption
C
17
star
100

gnupg-windows-build

Cross-compile GnuPG for Windows using Docker
Dockerfile
17
star