34ac42fff40aa5bdbbda5db3b561f42999d86117
3 - [ ] Switch from regular files to named pipes
17 #define debug(args...) {fprintf(stderr, "[debug] " args);}
18 #define info( args...) {fprintf(stderr, "[info] " args);}
19 #define error(args...) {fprintf(stderr, "[error] " args);}
20 #define fatal(args...) {fprintf(stderr, "[fatal] " args); exit(EXIT_FAILURE);}
21 #define usage(args...) {print_usage(); fatal("[usage] " args);}
25 typedef struct File File
;
32 int pos
; /* Position on the output buffer. */
36 typedef struct Config Config
;
47 .timefmt
= "%Y-%m-%d %H:%M:%S",
70 "Usage: %s [OPTION ...] SPEC [SPEC ...]\n"
72 " SPEC = FILE_PATH DATA_WIDTH DATA_TTL\n"
73 " FILE_PATH = string\n"
74 " DATA_WIDTH = int (* (positive) number of characters *)\n"
75 " DATA_TTL = int (* (positive) number of seconds *)\n"
76 " OPTION = -i INTERVAL\n"
78 " SEPARATOR = string\n"
79 " INTERVAL = int (* (positive) number of seconds *)\n"
85 "Example: %s -i 1 /dev/shm/khatus/khatus_sensor_x 4 10\n"
91 void opts_parse_any(Config
*, int, char *[], int); /* For mutually-recursive calls. */
94 parse_opts_opt_i(Config
*cfg
, int argc
, char *argv
[], int i
)
97 char *param
= argv
[i
++];
99 if (is_pos_num(param
)) {
100 cfg
->interval
= atoi(param
);
101 opts_parse_any(cfg
, argc
, argv
, i
);
103 usage("Option -i parameter is invalid: \"%s\"\n", param
);
106 usage("Option -i parameter is missing.\n");
111 parse_opts_opt_s(Config
*cfg
, int argc
, char *argv
[], int i
)
114 cfg
->separator
= calloc((strlen(argv
[i
]) + 1), sizeof(char));
115 strcpy(cfg
->separator
, argv
[i
]);
116 opts_parse_any(cfg
, argc
, argv
, ++i
);
118 usage("Option -s parameter is missing.\n");
123 parse_opts_opt_t(Config
*cfg
, int argc
, char *argv
[], int i
)
126 cfg
->timefmt
= calloc((strlen(argv
[i
]) + 1), sizeof(char));
127 strcpy(cfg
->timefmt
, argv
[i
]);
128 opts_parse_any(cfg
, argc
, argv
, ++i
);
130 usage("Option -t parameter is missing.\n");
135 parse_opts_opt(Config
*cfg
, int argc
, char *argv
[], int i
)
137 switch (argv
[i
][1]) {
138 case 'i': parse_opts_opt_i(cfg
, argc
, argv
, ++i
); break; /* TODO: Generic set_int */
139 case 's': parse_opts_opt_s(cfg
, argc
, argv
, ++i
); break; /* TODO: Generic set_str */
140 case 't': parse_opts_opt_t(cfg
, argc
, argv
, ++i
); break; /* TODO: Generic set_str */
141 default : usage("Option \"%s\" is invalid\n", argv
[i
]);
146 parse_opts_spec(Config
*cfg
, int argc
, char *argv
[], int i
)
149 usage("[spec] Parameter(s) missing for file \"%s\".\n", argv
[i
]);
156 usage("[spec] Invalid width: \"%s\", for file \"%s\"\n", w
, n
);
158 usage("[spec] Invalid TTL: \"%s\", for file \"%s\"\n", t
, n
);
159 File
*f
= calloc(1, sizeof(struct File
));
166 f
->pos
= cfg
->total_width
;
167 f
->next
= cfg
->files
;
170 cfg
->total_width
+= f
->width
;
173 fatal("[memory] Allocation failure.");
175 opts_parse_any(cfg
, argc
, argv
, i
);
179 opts_parse_any(Config
*cfg
, int argc
, char *argv
[], int i
)
182 switch (argv
[i
][0]) {
183 case '-': parse_opts_opt(cfg
, argc
, argv
, i
); break;
184 default : parse_opts_spec(cfg
, argc
, argv
, i
);
190 opts_parse(Config
*cfg
, int argc
, char *argv
[], int i
)
192 opts_parse_any(cfg
, argc
, argv
, 1);
194 File
*last
= cfg
->files
;
196 for (File
*f
= last
; f
; ) {
197 File
*next
= f
->next
;
198 f
->next
= cfg
->files
;
205 read_all(Config
*cfg
, char *buf
)
207 /* TODO: stat then check TTL */
208 for (File
*f
= cfg
->files
; f
; f
= f
->next
) {
210 f
->fd
= open(f
->name
, O_RDONLY
);
212 /* TODO: Consider backing off retries for failed files. */
213 fatal("Failed to open \"%s\"\n", f
->name
);
216 ssize_t n
= read(f
->fd
, buf
+ f
->pos
, f
->width
);
217 int lasti
= n
+ f
->pos
- 1;
218 char lastc
= buf
[lasti
];
226 main(int argc
, char *argv
[])
233 Config
*cfg
= &defaults
;
237 opts_parse(cfg
, argc
, argv
, 1);
238 debug("argv0 = %s\n", argv0
);
239 debug("[config] interval = %d\n", cfg
->interval
);
240 debug("[config] separator = %s\n", cfg
->separator
);
241 debug("[config] file_count = %d\n", cfg
->file_count
);
242 debug("[config] total_width = %d\n", cfg
->total_width
);
243 if (cfg
->files
== NULL
)
244 usage("No file specs were given!\n");
245 for (File
*f
= cfg
->files
; f
; f
= f
->next
) {
263 width
= cfg
->total_width
;
264 seplen
= strlen(cfg
->separator
);
266 /* 1st pass to make space for separators */
267 for (File
*f
= cfg
->files
; f
; f
= f
->next
) {
272 width
+= (seplen
* (nfiles
- 1));
273 buf
= calloc(1, width
+ 1);
275 fatal("[memory] Failed to allocate buffer of %d bytes", width
);
276 memset(buf
, ' ', width
);
278 /* 2nd pass to set the separators */
279 for (File
*f
= cfg
->files
; f
; f
= f
->next
) {
280 if (f
->pos
) { /* Skip the first, left-most */
281 strcpy(buf
+ (f
->pos
- seplen
), cfg
->separator
);
285 /* TODO: nanosleep and nano time diff */
289 sleep(cfg
->interval
);
This page took 0.090849 seconds and 4 git commands to generate.