aboutsummaryrefslogtreecommitdiff
path: root/opts.c
blob: ab39f36a36a248691e23a50725868fcb7190fa37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
    Mount option parsing
    Copyright (C) 2004  Miklos Szeredi <miklos@szeredi.hu>

    This program can be distributed under the terms of the GNU GPL.
    See the file COPYING.
*/

#include "opts.h"
#include <string.h>
#include <stdlib.h>

static int process_option(char *arg, struct opt opts[], int case_sensitive)
{
    int i;
    char *eq = strchr(arg, '=');
    if (eq)
        *eq = '\0';

    for (i = 0; opts[i].optname != NULL; i++) {
        if (case_sensitive) {
            if (strcmp(opts[i].optname, arg) == 0)
                break;
        } else if (strcasecmp(opts[i].optname, arg) == 0)
            break;
    }
    if (opts[i].optname == NULL) {
        if (eq)
            *eq = '=';
        return 0;
    }
    opts[i].present = 1;
    if (eq) {
        if (opts[i].value)
            free(opts[i].value);
        opts[i].value = strdup(eq+1);
    }
    return 1;
}

static int process_option_group(char *arg, struct opt opts[],
                                int case_sensitive)
{
    int remove = 1;
    char *prevcomma = NULL;
    while (1) {
        int remove_one;
        char *comma = strchr(arg, ',');
        if (comma)
            *comma = '\0';
        remove_one = process_option(arg, opts, case_sensitive);
        if (remove_one) {
            if (comma)
                memmove(arg, comma + 1, strlen(comma + 1) + 1);
        } else {
            remove = 0;
            if (comma)
                arg = comma + 1;
        }
        if (!remove_one && prevcomma)
            *prevcomma = ',';
        if (!comma)
            break;
        prevcomma = comma;
    }
    return remove;
}

void process_options(int *argcp, char *argv[], struct opt opts[], 
                     int case_sensitive)
{
    int argctr;
    int newargctr;

    for (argctr = 1, newargctr = 1; argctr < *argcp; argctr++) {
        char *arg = argv[argctr];
        int removed = 0;
        if (arg[0] == '-' && arg[1] == 'o') {
            if (arg[2])
                removed = process_option_group(arg+2, opts, case_sensitive);
            else {
                if (argctr + 1 < *argcp) {
                    argctr++;
                    arg = argv[argctr];
                    removed = process_option_group(arg, opts, case_sensitive);
                    if (removed)
                        free(argv[argctr-1]);
                    else if (argctr != newargctr)
                        argv[newargctr++] = argv[argctr-1];
                    
                }
            }
        }
        if (removed)
            free(arg);
        else {
            if(argctr != newargctr)
                argv[newargctr] = arg;
            newargctr++;
        }
    }
    *argcp = newargctr;
}