Skip to content

Commit 9e4ec2e

Browse files
Improved implementation of --actions command, with less stack memory use, and with localization of action names
1 parent 97dcb4d commit 9e4ec2e

1 file changed

Lines changed: 172 additions & 84 deletions

File tree

src/actionhelp.c

Lines changed: 172 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -41,70 +41,73 @@ char *
4141
build_actions_string(void) {
4242
DB_plugin_t **plugins = plug_get_list();
4343

44-
const int MAX_DEPTH = 32;
4544
const int NAME_COLUMN = 40;
4645
const int INITIAL_BUF = 4096;
4746

48-
/* ---------- dynamic buffer ---------- */
49-
size_t buf_capacity = INITIAL_BUF;
50-
size_t buf_len = 0;
51-
char *buf = malloc(buf_capacity);
47+
size_t capacity = INITIAL_BUF;
48+
size_t length = 0;
49+
50+
char *buf = malloc(capacity);
5251
if (!buf) {
5352
return NULL;
5453
}
54+
5555
buf[0] = 0;
5656

57-
/* ---------- helper to append to buffer ---------- */
5857
#define APPEND(...) do { \
5958
int needed = snprintf(NULL, 0, __VA_ARGS__); \
60-
if (buf_len + needed + 1 > buf_capacity) { \
61-
buf_capacity = (buf_len + needed + 1) * 2; \
62-
buf = realloc(buf, buf_capacity); \
59+
if (length + needed + 1 > capacity) { \
60+
capacity = (length + needed + 1) * 2; \
61+
buf = realloc(buf, capacity); \
6362
} \
64-
buf_len += snprintf(buf + buf_len, buf_capacity - buf_len, __VA_ARGS__); \
65-
} while(0)
63+
length += snprintf(buf + length, capacity - length, __VA_ARGS__); \
64+
} while (0)
6665

67-
/* ---------- header ---------- */
68-
APPEND("\n");
69-
APPEND(_("List of all actions.\n"));
70-
APPEND(_("Perform actions using \"--action=NAME\" command line argument.\n\n"));
7166
APPEND(_("Title"));
72-
int header_pos = 5;
73-
for (int i = header_pos; i < NAME_COLUMN; i++) {
67+
68+
for (int i = 5; i < NAME_COLUMN; i++) {
7469
APPEND(" ");
7570
}
76-
APPEND("| ");
77-
APPEND(_("Name"));
78-
APPEND("\n");
7971

80-
/* ---------- full-width divider ---------- */
81-
int total_width = NAME_COLUMN + 40; // approximate total width
72+
APPEND("| %s\n", _("Name"));
73+
74+
int total_width = NAME_COLUMN + 40;
75+
8276
for (int i = 0; i < total_width; i++) {
83-
APPEND(i == NAME_COLUMN ? "|" : "-");
77+
if (i == NAME_COLUMN) {
78+
APPEND("|");
79+
} else {
80+
APPEND("-");
81+
}
8482
}
83+
8584
APPEND("\n");
8685

87-
/* ---------- collect actions ---------- */
88-
int capacity = 64, count = 0;
89-
DB_plugin_action_t **list = malloc(sizeof(DB_plugin_action_t *) * capacity);
86+
// Build an alphabetically-sorted list of actions from all plugins
87+
88+
int cap_list = 64, count = 0;
89+
DB_plugin_action_t **list = malloc(sizeof(*list) * cap_list);
90+
9091
if (!list) {
9192
free(buf);
9293
return NULL;
9394
}
9495

95-
for (int pi = 0; plugins[pi] != NULL; pi++) {
96-
DB_plugin_t *plugin = plugins[pi];
97-
if (!plugin->get_actions) {
96+
for (int i = 0; plugins[i]; i++) {
97+
if (!plugins[i]->get_actions) {
9898
continue;
9999
}
100-
DB_plugin_action_t *action = plugin->get_actions(NULL);
101-
while (action) {
102-
if (count == capacity) {
103-
capacity *= 2;
104-
list = realloc(list, sizeof(DB_plugin_action_t*) * capacity);
100+
101+
DB_plugin_action_t *a = plugins[i]->get_actions(NULL);
102+
103+
while (a) {
104+
if (count == cap_list) {
105+
cap_list *= 2;
106+
list = realloc(list, sizeof(*list) * cap_list);
105107
}
106-
list[count++] = action;
107-
action = action->next;
108+
109+
list[count++] = a;
110+
a = a->next;
108111
}
109112
}
110113

@@ -113,75 +116,160 @@ buf_len += snprintf(buf + buf_len, buf_capacity - buf_len, __VA_ARGS__); \
113116
return buf;
114117
}
115118

116-
/* ---------- sort ---------- */
117-
qsort(list, count, sizeof(DB_plugin_action_t *), action_alphasort);
119+
qsort(list, count, sizeof(*list), action_alphasort);
118120

119-
/* ---------- tree printing ---------- */
120-
char prev_parts[MAX_DEPTH][256];
121-
int prev_depth = 0;
121+
// Build action tree based on '/' separators
122122

123-
for (int ai = 0; ai < count; ai++) {
124-
const char *src = list[ai]->title;
125-
char parts[MAX_DEPTH][256];
123+
const char *prev = "";
124+
125+
for (int i = 0; i < count; i++) {
126+
const char *cur = list[i]->title;
127+
const char *p_prev = prev;
128+
const char *p_cur = cur;
126129
int depth = 0;
127130

128-
/* split path handling escaped \/ */
129-
while (*src && depth < MAX_DEPTH) {
130-
int idx = 0;
131-
while (*src) {
132-
if (src[0] == '\\' && src[1] == '/') {
133-
parts[depth][idx++] = '/';
134-
src += 2;
131+
while (*p_cur) {
132+
const char *c_start = p_cur;
133+
int c_len = 0;
134+
135+
while (*p_cur) {
136+
if (p_cur[0] == '\\' && p_cur[1] == '/') {
137+
p_cur += 2;
138+
c_len++;
135139
continue;
136140
}
137-
if (*src == '/') {
141+
142+
if (*p_cur == '/') {
138143
break;
139144
}
140-
parts[depth][idx++] = *src++;
141-
}
142-
parts[depth][idx] = 0;
143-
depth++;
144-
if (*src == '/') {
145-
src++;
146-
}
147-
else {
148-
break;
145+
146+
p_cur++;
147+
c_len++;
149148
}
150-
}
151149

152-
int shared = 0;
153-
while (shared < depth
154-
&& shared < prev_depth
155-
&& strcmp(parts[shared], prev_parts[shared]) == 0) {
156-
shared++;
157-
}
150+
int match = 0;
158151

159-
for (int level = shared; level < depth; level++) {
160-
int indent = level * 4;
161-
for (int i = 0; i < indent; i++) {
162-
APPEND(" ");
152+
if (*p_prev) {
153+
const char *p_start = p_prev;
154+
int p_len = 0;
155+
156+
while (*p_prev) {
157+
if (p_prev[0] == '\\' && p_prev[1] == '/') {
158+
p_prev += 2;
159+
p_len++;
160+
continue;
161+
}
162+
163+
if (*p_prev == '/') {
164+
break;
165+
}
166+
167+
p_prev++;
168+
p_len++;
169+
}
170+
171+
if (c_len == p_len && strncmp(c_start, p_start, c_len) == 0) {
172+
match = 1;
173+
}
174+
175+
if (*p_prev == '/') {
176+
p_prev++;
177+
}
163178
}
164-
APPEND("%s", parts[level]);
165-
int current_pos = indent + (int)strlen(parts[level]);
166-
if (level == depth - 1) {
167-
if (current_pos < NAME_COLUMN) {
168-
for (int i = current_pos; i < NAME_COLUMN; i++) {
179+
180+
if (!match) {
181+
const char *s = c_start;
182+
int level = depth;
183+
184+
while (1) {
185+
int indent = level * 4;
186+
187+
for (int k = 0; k < indent; k++) {
169188
APPEND(" ");
170189
}
171-
} else {
172-
APPEND(" ");
190+
191+
const char *tmp = s;
192+
int seg_len = 0;
193+
194+
while (*tmp) {
195+
if (tmp[0] == '\\' && tmp[1] == '/') {
196+
tmp += 2;
197+
seg_len++;
198+
continue;
199+
}
200+
201+
if (*tmp == '/') {
202+
break;
203+
}
204+
205+
tmp++;
206+
seg_len++;
207+
}
208+
209+
const char *p = s;
210+
int remaining = seg_len;
211+
212+
213+
char *name = calloc(remaining + 1, 1);
214+
char *namep = name;
215+
216+
while (remaining > 0) {
217+
if (p[0] == '\\' && p[1] == '/') {
218+
*namep++ = '/';
219+
p += 2;
220+
remaining--;
221+
} else {
222+
*namep++ = *p++;
223+
remaining--;
224+
}
225+
}
226+
*namep = 0;
227+
APPEND("%s", name);
228+
free(name);
229+
name = NULL;
230+
namep = NULL;
231+
232+
if (*tmp == 0) {
233+
int pos = indent + seg_len;
234+
235+
if (pos < NAME_COLUMN) {
236+
for (int k = pos; k < NAME_COLUMN; k++) {
237+
APPEND(" ");
238+
}
239+
} else {
240+
APPEND(" ");
241+
}
242+
243+
APPEND("| %s", list[i]->name);
244+
}
245+
246+
APPEND("\n");
247+
248+
if (*tmp == '/') {
249+
s = tmp + 1;
250+
level++;
251+
} else {
252+
break;
253+
}
173254
}
174-
APPEND("| %s", list[ai]->name);
255+
256+
break;
257+
}
258+
259+
depth++;
260+
261+
if (*p_cur == '/') {
262+
p_cur++;
263+
} else {
264+
break;
175265
}
176-
APPEND("\n");
177-
strcpy(prev_parts[level], parts[level]);
178266
}
179-
prev_depth = depth;
267+
268+
prev = cur;
180269
}
181270

182271
free(list);
183272
return buf;
184273

185274
#undef APPEND
186275
}
187-

0 commit comments

Comments
 (0)