@@ -41,70 +41,73 @@ char *
4141build_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 { \
5958int 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