Begin work on X5
[khatus.git] / x5 / khatus.c
1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #define MAX_TOT_WIDTH 1024
8
9 #define debug( args...) {fprintf(stderr, "[debug] " args);}
10 #define error( args...) {fprintf(stderr, "[error] " args); errors++;}
11 #define fatal(n, args...) {fprintf(stderr, "[fatal] " args); exit(n);}
12 #define usage( args...) {print_usage(); fatal(1, "[usage] " args);}
13
14
15 typedef struct file * File;
16
17 struct file {
18 char * name;
19 int width;
20 int ttl;
21 File next;
22 };
23
24 struct options {
25 char * argv0;
26 int interval;
27 File files;
28 } options = {
29 .argv0 = NULL,
30 .interval = 1,
31 .files = NULL
32 };
33
34 typedef struct options * Options;
35
36 Options opts = &options;
37 int errors = 0;
38
39
40 int
41 is_pos_num(char *s)
42 {
43 while (*s != '\0')
44 if (!isdigit(*(s++)))
45 return 0;
46 return 1;
47 }
48
49 void
50 print_usage()
51 {
52 assert(opts->argv0);
53 fprintf(
54 stderr,
55 "\n"
56 "Usage: %s [OPTIONS ...] SPEC [SPEC ...]\n"
57 "\n"
58 "\tSPEC = FILE_PATH DATA_WIDTH DATA_TTL\n"
59 "\tFILE_PATH = string\n"
60 "\tDATA_WIDTH = int (* (positive) number of characters *)\n"
61 "\tDATA_TTL = int (* (positive) number of seconds *)\n"
62 "\tOPTION = -i INTERVAL\n"
63 "\tINTERVAL = int (* (positive) number of seconds *)\n"
64 "\n",
65 opts->argv0
66 );
67 fprintf(
68 stderr,
69 "Example: %s -i 1 /dev/shm/khatus/khatus_sensor_x 4 10\n"
70 "\n",
71 opts->argv0
72 );
73 }
74
75 void parse_opts(int, char *[], int); /* For mutually-recursive calls. */
76
77 void
78 parse_opts_opt_i(int argc, char *argv[], int i)
79 {
80 if (i < argc) {
81 char *param = argv[i++];
82
83 if (is_pos_num(param)) {
84 opts->interval = atoi(param);
85 parse_opts(argc, argv, i);
86 } else {
87 usage("Option -i parameter is invalid: \"%s\"\n", param);
88 }
89 } else {
90 usage("Option -i parameter is missing.\n");
91 }
92 }
93
94 void
95 parse_opts_opt(int argc, char *argv[], int i)
96 {
97 switch (argv[i][1]) {
98 case 'i': parse_opts_opt_i(argc, argv, ++i); break; /* TODO: Generic set_int */
99 default : usage("Option \"%s\" is invalid\n", argv[i]);
100 }
101 }
102
103 void
104 parse_opts_spec(int argc, char *argv[], int i)
105 {
106 if ((i + 3) > argc)
107 usage("[spec] Parameter(s) missing for file \"%s\".\n", argv[i]);
108
109 char *n = argv[i++];
110 char *w = argv[i++];
111 char *t = argv[i++];
112
113 if (!is_pos_num(w))
114 usage("[spec] Invalid width: \"%s\", for file \"%s\"\n", w, n);
115 if (!is_pos_num(t))
116 usage("[spec] Invalid TTL: \"%s\", for file \"%s\"\n", t, n);
117 File f = malloc(sizeof(struct file));
118 if (f) {
119 f->name = n;
120 f->width = atoi(w);
121 f->ttl = atoi(t);
122 f->next = opts->files;
123 opts->files = f;
124 } else {
125 fatal(2, "[memory] Allocation failure.");
126 }
127 parse_opts(argc, argv, i);
128 }
129
130 void
131 parse_opts(int argc, char *argv[], int i)
132 {
133 if (i < argc) {
134 switch (argv[i][0]) {
135 case '-': parse_opts_opt(argc, argv, i); break;
136 default : parse_opts_spec(argc, argv, i);
137 }
138 }
139 }
140
141 int
142 main(int argc, char **argv)
143 {
144 opts->argv0 = argv[0];
145 parse_opts(argc, argv, 1);
146 assert(!errors);
147 debug("[options] argv0 = %s\n", opts->argv0);
148 debug("[options] interval = %d\n", opts->interval);
149 if (opts->files == NULL)
150 usage("No file specs were given!\n");
151 for (File f = opts->files; f; f = f->next) {
152 debug(
153 "[options] file = { name = %s, width = %d, ttl = %d }\n",
154 f->name,
155 f->width,
156 f->ttl
157 );
158 }
159 }
This page took 0.05522 seconds and 4 git commands to generate.