aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Crisci <tony@dubstepdish.com>2017-08-24 15:26:51 -0400
committerTony Crisci <tony@dubstepdish.com>2017-08-26 08:32:11 -0400
commit54f87146c3755653bbbe076c86b4b85c23a0989d (patch)
tree973c93c7d9a203986f488be743e24f6d40606614
parent98f4cdfccb7d2ace2929bca45f0479b3472b96ac (diff)
refactor example config and add ini.c
-rw-r--r--examples/config.c146
-rw-r--r--examples/config.h25
-rw-r--r--examples/ini.c195
-rw-r--r--examples/ini.h93
-rw-r--r--examples/meson.build2
-rw-r--r--examples/output-layout.c1
-rw-r--r--examples/pointer.c1
-rw-r--r--examples/rotation.c1
-rw-r--r--examples/shared.c139
-rw-r--r--examples/shared.h18
10 files changed, 463 insertions, 158 deletions
diff --git a/examples/config.c b/examples/config.c
new file mode 100644
index 00000000..4f70faf0
--- /dev/null
+++ b/examples/config.c
@@ -0,0 +1,146 @@
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <string.h>
+#include "shared.h"
+#include "config.h"
+
+static void usage(const char *name, int ret) {
+ fprintf(stderr,
+ "usage: %s [-d <name> [-r <rotation> | -f]]*\n"
+ "\n"
+ " -o <output> The name of the DRM display. e.g. DVI-I-1.\n"
+ " -r <rotation> The rotation counter clockwise. Valid values are 90, 180, 270.\n"
+ " -x <position> The X-axis coordinate position of this output in the layout.\n"
+ " -y <position> The Y-axis coordinate position of this output in the layout.\n"
+ " -f Flip the output along the vertical axis.\n", name);
+
+ exit(ret);
+}
+
+struct example_config *parse_args(int argc, char *argv[]) {
+ struct example_config *config = calloc(1, sizeof(struct example_config));
+ wl_list_init(&config->outputs);
+ struct output_config *oc = NULL;
+
+ int c;
+ while ((c = getopt(argc, argv, "o:r:x:y:fh")) != -1) {
+ switch (c) {
+ case 'o':
+ oc = calloc(1, sizeof(*oc));
+ oc->name = optarg;
+ oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ wl_list_insert(&config->outputs, &oc->link);
+ break;
+ case 'r':
+ if (!oc) {
+ fprintf(stderr, "You must specify an output first\n");
+ usage(argv[0], 1);
+ }
+
+ if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL
+ && oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) {
+ fprintf(stderr, "Rotation for %s already specified\n", oc->name);
+ usage(argv[0], 1);
+ }
+
+ if (strcmp(optarg, "90") == 0) {
+ oc->transform += WL_OUTPUT_TRANSFORM_90;
+ } else if (strcmp(optarg, "180") == 0) {
+ oc->transform += WL_OUTPUT_TRANSFORM_180;
+ } else if (strcmp(optarg, "270") == 0) {
+ oc->transform += WL_OUTPUT_TRANSFORM_270;
+ } else {
+ fprintf(stderr, "Invalid rotation '%s'\n", optarg);
+ usage(argv[0], 1);
+ }
+ break;
+ case 'x':
+ if (!oc) {
+ fprintf(stderr, "You must specify an output first\n");
+ usage(argv[0], 1);
+ }
+ oc->x = strtol(optarg, NULL, 0);
+ break;
+ case 'y':
+ if (!oc) {
+ fprintf(stderr, "You must specify an output first\n");
+ usage(argv[0], 1);
+ }
+ oc->y = strtol(optarg, NULL, 0);
+ break;
+ case 'f':
+ if (!oc) {
+ fprintf(stderr, "You must specify an output first\n");
+ usage(argv[0], 1);
+ }
+
+ if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) {
+ fprintf(stderr, "Flip for %s already specified\n", oc->name);
+ usage(argv[0], 1);
+ }
+
+ oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED;
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0], c != 'h');
+ }
+ }
+
+ return config;
+}
+
+void example_config_destroy(struct example_config *config) {
+ struct output_config *oc, *tmp = NULL;
+ wl_list_for_each_safe(oc, tmp, &config->outputs, link) {
+ free(oc);
+ }
+ free(config);
+}
+
+struct wlr_output_layout *configure_layout(struct example_config *config, struct wl_list *outputs) {
+ struct wlr_output_layout *layout = wlr_output_layout_init();
+ int max_x = INT_MIN;
+ int max_x_y = INT_MIN; // y value for the max_x output
+
+ // first add all the configured outputs
+ struct output_state *output;
+ wl_list_for_each(output, outputs, link) {
+ struct output_config *conf;
+ wl_list_for_each(conf, &config->outputs, link) {
+ if (strcmp(conf->name, output->output->name) == 0) {
+ wlr_output_layout_add(layout, output->output,
+ conf->x, conf->y);
+ wlr_output_transform(output->output, conf->transform);
+ int width, height;
+ wlr_output_effective_resolution(output->output, &width, &height);
+ if (conf->x + width > max_x) {
+ max_x = conf->x + width;
+ max_x_y = conf->y;
+ }
+ break;
+ }
+ }
+ }
+
+ if (max_x == INT_MIN) {
+ // couldn't find a configured output
+ max_x = 0;
+ max_x_y = 0;
+ }
+
+ // now add all the other configured outputs in a sensible position
+ wl_list_for_each(output, outputs, link) {
+ if (wlr_output_layout_get(layout, output->output)) {
+ continue;
+ }
+ wlr_output_layout_add(layout, output->output, max_x, max_x_y);
+ int width, height;
+ wlr_output_effective_resolution(output->output, &width, &height);
+ max_x += width;
+ }
+
+ return layout;
+}
+
diff --git a/examples/config.h b/examples/config.h
new file mode 100644
index 00000000..1ecadd81
--- /dev/null
+++ b/examples/config.h
@@ -0,0 +1,25 @@
+#ifndef _EXAMPLE_CONFIG_H
+#define _EXAMPLE_CONFIG_H
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200112L
+#endif
+#include <wlr/types/wlr_output_layout.h>
+
+struct output_config {
+ char *name;
+ enum wl_output_transform transform;
+ int x, y;
+ struct wl_list link;
+};
+
+struct example_config {
+ struct wl_list outputs;
+};
+
+struct example_config *parse_args(int argc, char *argv[]);
+
+void example_config_destroy(struct example_config *config);
+
+struct wlr_output_layout *configure_layout(struct example_config *config,
+ struct wl_list *outputs);
+#endif
diff --git a/examples/ini.c b/examples/ini.c
new file mode 100644
index 00000000..6be9c44a
--- /dev/null
+++ b/examples/ini.c
@@ -0,0 +1,195 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+https://github.com/benhoyt/inih
+
+*/
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+ char* p = s + strlen(s);
+ while (p > s && isspace((unsigned char)(*--p)))
+ *p = '\0';
+ return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+ while (*s && isspace((unsigned char)(*s)))
+ s++;
+ return (char*)s;
+}
+
+/* Return pointer to first char (of chars) or inline comment in given string,
+ or pointer to null at end of string if neither found. Inline comment must
+ be prefixed by a whitespace character to register as a comment. */
+static char* find_chars_or_comment(const char* s, const char* chars)
+{
+#if INI_ALLOW_INLINE_COMMENTS
+ int was_space = 0;
+ while (*s && (!chars || !strchr(chars, *s)) &&
+ !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
+ was_space = isspace((unsigned char)(*s));
+ s++;
+ }
+#else
+ while (*s && (!chars || !strchr(chars, *s))) {
+ s++;
+ }
+#endif
+ return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+ strncpy(dest, src, size);
+ dest[size - 1] = '\0';
+ return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
+ void* user)
+{
+ /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+#else
+ char* line;
+#endif
+ char section[MAX_SECTION] = "";
+ char prev_name[MAX_NAME] = "";
+
+ char* start;
+ char* end;
+ char* name;
+ char* value;
+ int lineno = 0;
+ int error = 0;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_MAX_LINE);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+ /* Scan through stream line by line */
+ while (reader(line, INI_MAX_LINE, stream) != NULL) {
+ lineno++;
+
+ start = line;
+#if INI_ALLOW_BOM
+ if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+ (unsigned char)start[1] == 0xBB &&
+ (unsigned char)start[2] == 0xBF) {
+ start += 3;
+ }
+#endif
+ start = lskip(rstrip(start));
+
+ if (*start == ';' || *start == '#') {
+ /* Per Python configparser, allow both ; and # comments at the
+ start of a line */
+ }
+#if INI_ALLOW_MULTILINE
+ else if (*prev_name && *start && start > line) {
+ /* Non-blank line with leading whitespace, treat as continuation
+ of previous name's value (as per Python configparser). */
+ if (!handler(user, section, prev_name, start) && !error)
+ error = lineno;
+ }
+#endif
+ else if (*start == '[') {
+ /* A "[section]" line */
+ end = find_chars_or_comment(start + 1, "]");
+ if (*end == ']') {
+ *end = '\0';
+ strncpy0(section, start + 1, sizeof(section));
+ *prev_name = '\0';
+ }
+ else if (!error) {
+ /* No ']' found on section line */
+ error = lineno;
+ }
+ }
+ else if (*start) {
+ /* Not a comment, must be a name[=:]value pair */
+ end = find_chars_or_comment(start, "=:");
+ if (*end == '=' || *end == ':') {
+ *end = '\0';
+ name = rstrip(start);
+ value = lskip(end + 1);
+#if INI_ALLOW_INLINE_COMMENTS
+ end = find_chars_or_comment(value, NULL);
+ if (*end)
+ *end = '\0';
+#endif
+ rstrip(value);
+
+ /* Valid name[=:]value pair found, call handler */
+ strncpy0(prev_name, name, sizeof(prev_name));
+ if (!handler(user, section, name, value) && !error)
+ error = lineno;
+ memset(value, 0, strlen(value));
+ }
+ else if (!error) {
+ /* No '=' or ':' found on name[=:]value line */
+ error = lineno;
+ }
+ }
+
+#if INI_STOP_ON_FIRST_ERROR
+ if (error)
+ break;
+#endif
+ }
+
+#if !INI_USE_STACK
+ free(line);
+#endif
+
+ return error;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file, ini_handler handler, void* user)
+{
+ return ini_parse_stream((ini_reader)fgets, file, handler, user);
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename, ini_handler handler, void* user)
+{
+ FILE* file;
+ int error;
+
+ file = fopen(filename, "r");
+ if (!file)
+ return -1;
+ error = ini_parse_file(file, handler, user);
+ fclose(file);
+ return error;
+}
diff --git a/examples/ini.h b/examples/ini.h
new file mode 100644
index 00000000..2804255b
--- /dev/null
+++ b/examples/ini.h
@@ -0,0 +1,93 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+https://github.com/benhoyt/inih
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Typedef for prototype of handler function. */
+typedef int (*ini_handler)(void* user, const char* section,
+ const char* name, const char* value);
+
+/* Typedef for prototype of fgets-style reader function. */
+typedef char* (*ini_reader)(char* str, int num, void* stream);
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+ (whitespace stripped), and comments starting with ';' (semicolon). Section
+ is "" if name=value pair parsed before any section heading. name:value
+ pairs are also supported as a concession to Python's configparser.
+
+ For each name=value pair parsed, call handler function with given user
+ pointer as well as section, name, and value (data only valid for duration
+ of handler call). Handler should return nonzero on success, zero on error.
+
+ Returns 0 on success, line number of first error on parse error (doesn't
+ stop on first error), -1 on file open error, or -2 on memory allocation
+ error (only when INI_USE_STACK is zero).
+*/
+int ini_parse(const char* filename, ini_handler handler, void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+ close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file, ini_handler handler, void* user);
+
+/* Same as ini_parse(), but takes an ini_reader function pointer instead of
+ filename. Used for implementing custom or string-based I/O. */
+int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
+ void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+ configparser. If allowed, ini_parse() will call the handler with the same
+ name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+ the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Nonzero to allow inline comments (with valid inline comment characters
+ specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
+ Python 3.2+ configparser behaviour. */
+#ifndef INI_ALLOW_INLINE_COMMENTS
+#define INI_ALLOW_INLINE_COMMENTS 1
+#endif
+#ifndef INI_INLINE_COMMENT_PREFIXES
+#define INI_INLINE_COMMENT_PREFIXES ";"
+#endif
+
+/* Nonzero to use stack, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Stop parsing on first error (default is to keep parsing). */
+#ifndef INI_STOP_ON_FIRST_ERROR
+#define INI_STOP_ON_FIRST_ERROR 0
+#endif
+
+/* Maximum line length for any line in INI file. */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 2000
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
diff --git a/examples/meson.build b/examples/meson.build
index d4d96984..8fda974f 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -1,5 +1,5 @@
lib_shared = static_library('shared',
- ['shared.c', 'cat.c'],
+ ['shared.c', 'cat.c', 'ini.c', 'config.c'],
dependencies: wlroots)
executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared)
diff --git a/examples/output-layout.c b/examples/output-layout.c
index 041d5788..90ad558f 100644
--- a/examples/output-layout.c
+++ b/examples/output-layout.c
@@ -22,6 +22,7 @@
#include <wlr/types/wlr_keyboard.h>
#include <math.h>
#include "shared.h"
+#include "config.h"
#include "cat.h"
struct sample_state {
diff --git a/examples/pointer.c b/examples/pointer.c
index 95e28bb2..fcf9805f 100644
--- a/examples/pointer.c
+++ b/examples/pointer.c
@@ -22,6 +22,7 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/util/log.h>
#include "shared.h"
+#include "config.h"
#include "cat.h"
struct sample_input_device {
diff --git a/examples/rotation.c b/examples/rotation.c
index 1dcbc80f..2596e492 100644
--- a/examples/rotation.c
+++ b/examples/rotation.c
@@ -19,6 +19,7 @@
#include <wlr/util/log.h>
#include <math.h>
#include "shared.h"
+#include "config.h"
#include "cat.h"
struct sample_state {
diff --git a/examples/shared.c b/examples/shared.c
index 1dad8016..f9d687e3 100644
--- a/examples/shared.c
+++ b/examples/shared.c
@@ -18,145 +18,6 @@
#include <wlr/util/log.h>
#include "shared.h"
-static void usage(const char *name, int ret) {
- fprintf(stderr,
- "usage: %s [-d <name> [-r <rotation> | -f]]*\n"
- "\n"
- " -o <output> The name of the DRM display. e.g. DVI-I-1.\n"
- " -r <rotation> The rotation counter clockwise. Valid values are 90, 180, 270.\n"
- " -x <position> The X-axis coordinate position of this output in the layout.\n"
- " -y <position> The Y-axis coordinate position of this output in the layout.\n"
- " -f Flip the output along the vertical axis.\n", name);
-
- exit(ret);
-}
-
-struct example_config *parse_args(int argc, char *argv[]) {
- struct example_config *config = calloc(1, sizeof(struct example_config));
- wl_list_init(&config->outputs);
- struct output_config *oc = NULL;
-
- int c;
- while ((c = getopt(argc, argv, "o:r:x:y:fh")) != -1) {
- switch (c) {
- case 'o':
- oc = calloc(1, sizeof(*oc));
- oc->name = optarg;
- oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
- wl_list_insert(&config->outputs, &oc->link);
- break;
- case 'r':
- if (!oc) {
- fprintf(stderr, "You must specify an output first\n");
- usage(argv[0], 1);
- }
-
- if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL
- && oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) {
- fprintf(stderr, "Rotation for %s already specified\n", oc->name);
- usage(argv[0], 1);
- }
-
- if (strcmp(optarg, "90") == 0) {
- oc->transform += WL_OUTPUT_TRANSFORM_90;
- } else if (strcmp(optarg, "180") == 0) {
- oc->transform += WL_OUTPUT_TRANSFORM_180;
- } else if (strcmp(optarg, "270") == 0) {
- oc->transform += WL_OUTPUT_TRANSFORM_270;
- } else {
- fprintf(stderr, "Invalid rotation '%s'\n", optarg);
- usage(argv[0], 1);
- }
- break;
- case 'x':
- if (!oc) {
- fprintf(stderr, "You must specify an output first\n");
- usage(argv[0], 1);
- }
- oc->x = strtol(optarg, NULL, 0);
- break;
- case 'y':
- if (!oc) {
- fprintf(stderr, "You must specify an output first\n");
- usage(argv[0], 1);
- }
- oc->y = strtol(optarg, NULL, 0);
- break;
- case 'f':
- if (!oc) {
- fprintf(stderr, "You must specify an output first\n");
- usage(argv[0], 1);
- }
-
- if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) {
- fprintf(stderr, "Flip for %s already specified\n", oc->name);
- usage(argv[0], 1);
- }
-
- oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED;
- break;
- case 'h':
- case '?':
- usage(argv[0], c != 'h');
- }
- }
-
- return config;
-}
-
-void example_config_destroy(struct example_config *config) {
- struct output_config *oc, *tmp = NULL;
- wl_list_for_each_safe(oc, tmp, &config->outputs, link) {
- free(oc);
- }
- free(config);
-}
-
-struct wlr_output_layout *configure_layout(struct example_config *config, struct wl_list *outputs) {
- struct wlr_output_layout *layout = wlr_output_layout_init();
- int max_x = INT_MIN;
- int max_x_y = INT_MIN; // y value for the max_x output
-
- // first add all the configured outputs
- struct output_state *output;
- wl_list_for_each(output, outputs, link) {
- struct output_config *conf;
- wl_list_for_each(conf, &config->outputs, link) {
- if (strcmp(conf->name, output->output->name) == 0) {
- wlr_output_layout_add(layout, output->output,
- conf->x, conf->y);
- wlr_output_transform(output->output, conf->transform);
- int width, height;
- wlr_output_effective_resolution(output->output, &width, &height);
- if (conf->x + width > max_x) {
- max_x = conf->x + width;
- max_x_y = conf->y;
- }
- break;
- }
- }
- }
-
- if (max_x == INT_MIN) {
- // couldn't find a configured output
- max_x = 0;
- max_x_y = 0;
- }
-
- // now add all the other configured outputs in a sensible position
- wl_list_for_each(output, outputs, link) {
- if (wlr_output_layout_get(layout, output->output)) {
- continue;
- }
- wlr_output_layout_add(layout, output->output, max_x, max_x_y);
- int width, height;
- wlr_output_effective_resolution(output->output, &width, &height);
- max_x += width;
- }
-
- return layout;
-}
-
static void keyboard_led_update(struct keyboard_state *kbstate) {
uint32_t leds = 0;
diff --git a/examples/shared.h b/examples/shared.h
index d9972ffd..06108494 100644
--- a/examples/shared.h
+++ b/examples/shared.h
@@ -12,24 +12,6 @@
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_input_device.h>
-struct output_config {
- char *name;
- enum wl_output_transform transform;
- int x, y;
- struct wl_list link;
-};
-
-struct example_config {
- struct wl_list outputs;
-};
-
-struct example_config *parse_args(int argc, char *argv[]);
-
-void example_config_destroy(struct example_config *config);
-
-struct wlr_output_layout *configure_layout(struct example_config *config,
- struct wl_list *outputs);
-
struct output_state {
struct compositor_state *compositor;
struct wlr_output *output;