File: formatter.c

package info (click to toggle)
libscfg 0.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 108 kB
  • sloc: ansic: 653; makefile: 3
file content (129 lines) | stat: -rw-r--r-- 2,451 bytes parent folder | download
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <errno.h>
#include <scfg.h>
#include <stdbool.h>
#include <string.h>

static bool contains_special_char(const char *str) {
	for (size_t i = 0; str[i] != '\0'; i++) {
		switch (str[i]) {
		case '"':
		case '\\':
		case '\r':
		case '\n':
		case '\'':
		case '{':
		case '}':
		case ' ':
		case '\t':
			return true;
		}
	}
	return false;
}

static bool write_str(const char *str, FILE *f) {
	size_t n = strlen(str);
	return fwrite(str, 1, n, f) == n;
}

static bool write_ch(char ch, FILE *f) {
	return fwrite(&ch, 1, 1, f) == 1;
}

static bool write_indent(int level, FILE *f) {
	for (int i = 0; i < level; i++) {
		if (!write_ch('\t', f)) {
			return false;
		}
	}
	return true;
}

static bool format_word(const char *str, FILE *f) {
	if (str[0] != '\0' && !contains_special_char(str)) {
		return write_str(str, f);
	}

	if (!write_ch('"', f)) {
		return false;
	}

	for (size_t i = 0; str[i] != '\0'; i++) {
		char ch = str[i];
		switch (ch) {
		case '"':
		case '\\':
			if (!write_ch('\\', f)) {
				return false;
			}
			break;
		}
		if (!write_ch(ch, f)) {
			return false;
		}
	}

	return write_ch('"', f);
}

static int format_block(const struct scfg_block *block, FILE *f, int indent);

static int format_directive(const struct scfg_directive *dir, FILE *f, int indent) {
	if (dir->name[0] == '\0') {
		return -EINVAL;
	}

	if (!write_indent(indent, f) || !format_word(dir->name, f)) {
		return -errno;
	}

	for (size_t i = 0; i < dir->params_len; i++) {
		if (!write_ch(' ', f) || !format_word(dir->params[i], f)) {
			return -errno;
		}
	}

	if (dir->children.directives_len > 0) {
		if (!write_str(" {\n", f)) {
			return -errno;
		}
		int ret = format_block(&dir->children, f, indent + 1);
		if (ret < 0) {
			return ret;
		}
		if (!write_indent(indent, f) || !write_str("}", f)) {
			return -errno;
		}
	}

	if (!write_ch('\n', f)) {
		return -errno;
	}

	return 0;
}

static int format_block(const struct scfg_block *block, FILE *f, int indent) {
	for (size_t i = 0; i < block->directives_len; i++) {
		int ret = format_directive(&block->directives[i], f, indent);
		if (ret != 0) {
			return ret;
		}
	}
	return 0;
}

int scfg_format_file(const struct scfg_block *block, FILE *f) {
	return format_block(block, f, 0);
}

int scfg_store_file(const struct scfg_block *block, const char *path) {
	FILE *f = fopen(path, "w");
	if (f == NULL) {
		return -errno;
	}

	int res = scfg_format_file(block, f);
	fclose(f);
	return res;
}