1 | #include <stdio.h> |
---|
2 | #include <string.h> |
---|
3 | #include <sys/stat.h> |
---|
4 | #include <locale.h> |
---|
5 | |
---|
6 | #ifdef HAVE_CONFIG_H |
---|
7 | # include "config.h" |
---|
8 | #endif |
---|
9 | |
---|
10 | #include <gst/gst.h> |
---|
11 | |
---|
12 | |
---|
13 | typedef struct |
---|
14 | { |
---|
15 | gchar *name; |
---|
16 | GSList *srcpads; |
---|
17 | GSList *sinkpads; |
---|
18 | GSList *srcpadtemplates; |
---|
19 | GSList *sinkpadtemplates; |
---|
20 | GSList *arguments; |
---|
21 | } comp_element; |
---|
22 | |
---|
23 | enum |
---|
24 | { |
---|
25 | ARG_INT, |
---|
26 | ARG_FILENAME, |
---|
27 | ARG_ENUM |
---|
28 | }; |
---|
29 | |
---|
30 | typedef struct |
---|
31 | { |
---|
32 | gchar *name; |
---|
33 | int type; |
---|
34 | GSList *enums; |
---|
35 | } comp_argument; |
---|
36 | |
---|
37 | typedef struct |
---|
38 | { |
---|
39 | gint value; |
---|
40 | gchar *nick; |
---|
41 | } enum_value; |
---|
42 | |
---|
43 | |
---|
44 | void |
---|
45 | print_match_list (gchar * prefix, int len, GSList * wordlist) |
---|
46 | { |
---|
47 | GSList *words = wordlist; |
---|
48 | |
---|
49 | while (words) { |
---|
50 | if (!len || !strncmp ((gchar *) (words->data), prefix, len)) |
---|
51 | printf ("%s\n", (gchar *) (words->data)); |
---|
52 | words = g_slist_next (words); |
---|
53 | } |
---|
54 | } |
---|
55 | |
---|
56 | int |
---|
57 | match_element (comp_element * element, gchar * name) |
---|
58 | { |
---|
59 | return strcmp (element->name, name); |
---|
60 | } |
---|
61 | |
---|
62 | int |
---|
63 | main (int argc, char *argv[]) |
---|
64 | { |
---|
65 | xmlDocPtr doc; |
---|
66 | xmlNodePtr rootnode, elementnode, propnode, argnode; |
---|
67 | GList *element_list = NULL; |
---|
68 | comp_element *element; |
---|
69 | GSList *element_names = NULL; |
---|
70 | comp_argument *argument; |
---|
71 | enum_value *option; |
---|
72 | |
---|
73 | gchar *prev_word; |
---|
74 | gchar *partial_word; |
---|
75 | int partial_len; |
---|
76 | GList *elements; |
---|
77 | GSList *pads; |
---|
78 | int num_pads; |
---|
79 | GSList *args; |
---|
80 | gchar *word; |
---|
81 | GSList *words = NULL; |
---|
82 | |
---|
83 | struct stat stat_buf; |
---|
84 | |
---|
85 | setlocale (LC_ALL, ""); |
---|
86 | |
---|
87 | if (argc < 4) { |
---|
88 | fprintf (stderr, "gst-complete called with invalid arguments\n"); |
---|
89 | exit (1); |
---|
90 | } |
---|
91 | |
---|
92 | prev_word = argv[3]; |
---|
93 | partial_word = argv[2]; |
---|
94 | |
---|
95 | partial_len = strlen (partial_word); |
---|
96 | |
---|
97 | /***** Loading the completion information from the registry *****/ |
---|
98 | |
---|
99 | if (stat (GST_CACHE_DIR "/compreg.xml", &stat_buf) == 0) { |
---|
100 | doc = xmlParseFile (GST_CACHE_DIR "/compreg.xml"); |
---|
101 | } else { |
---|
102 | exit (1); |
---|
103 | } |
---|
104 | rootnode = doc->xmlRootNode; |
---|
105 | |
---|
106 | elementnode = rootnode->xmlChildrenNode; |
---|
107 | while (elementnode) { |
---|
108 | if (!strcmp (elementnode->name, "element")) { |
---|
109 | element = g_new0 (comp_element, 1); |
---|
110 | propnode = elementnode->xmlChildrenNode; |
---|
111 | while (propnode) { |
---|
112 | |
---|
113 | if (!strcmp (propnode->name, "name")) { |
---|
114 | element->name = xmlNodeGetContent (propnode); |
---|
115 | /* fprintf(stderr,element->name); */ |
---|
116 | } else if (!strcmp (propnode->name, "srcpad")) { |
---|
117 | element->srcpads = |
---|
118 | g_slist_prepend (element->srcpads, xmlNodeGetContent (propnode)); |
---|
119 | /* fprintf(stderr,"."); */ |
---|
120 | } else if (!strcmp (propnode->name, "sinkpad")) { |
---|
121 | element->sinkpads = |
---|
122 | g_slist_prepend (element->sinkpads, xmlNodeGetContent (propnode)); |
---|
123 | } else if (!strcmp (propnode->name, "srcpadtemplate")) { |
---|
124 | element->srcpadtemplates = |
---|
125 | g_slist_prepend (element->srcpadtemplates, |
---|
126 | xmlNodeGetContent (propnode)); |
---|
127 | /* fprintf(stderr,"."); */ |
---|
128 | } else if (!strcmp (propnode->name, "sinkpad")) { |
---|
129 | element->sinkpadtemplates = |
---|
130 | g_slist_prepend (element->sinkpadtemplates, |
---|
131 | xmlNodeGetContent (propnode)); |
---|
132 | } else if (!strcmp (propnode->name, "argument")) { |
---|
133 | argument = g_new0 (comp_argument, 1); |
---|
134 | argument->name = xmlNodeGetContent (propnode); |
---|
135 | argument->type = ARG_INT; |
---|
136 | |
---|
137 | /* walk through the values data */ |
---|
138 | argnode = propnode->xmlChildrenNode; |
---|
139 | while (argnode) { |
---|
140 | if (!strcmp (argnode->name, "filename")) { |
---|
141 | argument->type = ARG_FILENAME; |
---|
142 | } else if (!strcmp (argnode->name, "option")) { |
---|
143 | argument->type = ARG_ENUM; |
---|
144 | option = g_new0 (enum_value, 1); |
---|
145 | sscanf (xmlNodeGetContent (argnode), "%d", &option->value); |
---|
146 | argument->enums = g_slist_prepend (argument->enums, option); |
---|
147 | } |
---|
148 | argnode = argnode->next; |
---|
149 | } |
---|
150 | |
---|
151 | element->arguments = g_slist_prepend (element->arguments, argument); |
---|
152 | } |
---|
153 | |
---|
154 | propnode = propnode->next; |
---|
155 | } |
---|
156 | element_list = g_list_prepend (element_list, element); |
---|
157 | element_names = g_slist_prepend (element_names, element->name); |
---|
158 | } |
---|
159 | elementnode = elementnode->next; |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | |
---|
164 | /***** Completion *****/ |
---|
165 | |
---|
166 | /* The bulk of the work is in deciding exactly which words are an option. */ |
---|
167 | |
---|
168 | /* if we're right at the beginning, with -launch in the first word */ |
---|
169 | if (strstr (prev_word, "-launch")) { |
---|
170 | /* print out only elements with no sink pad or padtemplate */ |
---|
171 | elements = element_list; |
---|
172 | while (elements) { |
---|
173 | element = (comp_element *) (elements->data); |
---|
174 | if (!element->sinkpads && !element->sinkpadtemplates) |
---|
175 | words = g_slist_prepend (words, element->name); |
---|
176 | elements = g_list_next (elements); |
---|
177 | } |
---|
178 | } |
---|
179 | |
---|
180 | /* if the previous word is a connection */ |
---|
181 | if (strchr (prev_word, '!')) { |
---|
182 | /* print out oly elements with a sink pad or template */ |
---|
183 | elements = element_list; |
---|
184 | while (elements) { |
---|
185 | element = (comp_element *) (elements->data); |
---|
186 | if (element->sinkpads || element->sinkpadtemplates) |
---|
187 | words = g_slist_prepend (words, element->name); |
---|
188 | elements = g_list_next (elements); |
---|
189 | } |
---|
190 | } |
---|
191 | |
---|
192 | /* if the partial word is an argument, and it's an enum */ |
---|
193 | if (strchr (prev_word, '=')) { |
---|
194 | fprintf (stderr, "it's an arg, but dunno what element yet\n"); |
---|
195 | } |
---|
196 | |
---|
197 | /* if the previous word is an element, we need to list both pads and arguments */ |
---|
198 | if ((elements = |
---|
199 | g_list_find_custom (element_list, prev_word, |
---|
200 | (GCompareFunc) match_element))) { |
---|
201 | element = elements->data; |
---|
202 | /* zero the numpads list so we can count them */ |
---|
203 | num_pads = 0; |
---|
204 | |
---|
205 | /* pads */ |
---|
206 | pads = element->srcpads; |
---|
207 | while (pads) { |
---|
208 | num_pads++; |
---|
209 | words = |
---|
210 | g_slist_prepend (words, g_strdup_printf ("%s!", |
---|
211 | (gchar *) (pads->data))); |
---|
212 | pads = g_slist_next (pads); |
---|
213 | } |
---|
214 | |
---|
215 | /* padtemplates */ |
---|
216 | pads = element->srcpadtemplates; |
---|
217 | while (pads) { |
---|
218 | num_pads++; |
---|
219 | word = g_strdup_printf ("%s!", (gchar *) (pads->data)); |
---|
220 | if (!g_slist_find_custom (words, word, (GCompareFunc) strcmp)) |
---|
221 | words = g_slist_prepend (words, word); |
---|
222 | pads = g_slist_next (pads); |
---|
223 | } |
---|
224 | |
---|
225 | /* if there is only one pad, add '!' to the list of completions */ |
---|
226 | if (num_pads == 1) { |
---|
227 | words = g_slist_prepend (words, "!"); |
---|
228 | } |
---|
229 | |
---|
230 | /* arguments */ |
---|
231 | args = element->arguments; |
---|
232 | while (args) { |
---|
233 | argument = (comp_argument *) (args->data); |
---|
234 | word = strstr (argument->name, "::") + 2; |
---|
235 | words = g_slist_prepend (words, g_strdup_printf ("%s=", word)); |
---|
236 | words = g_slist_prepend (words, g_strdup_printf ("%s=...", word)); |
---|
237 | args = g_slist_next (args); |
---|
238 | } |
---|
239 | } |
---|
240 | |
---|
241 | |
---|
242 | /* The easy part is ouptuting the correct list of possibilities. */ |
---|
243 | print_match_list (partial_word, partial_len, words); |
---|
244 | |
---|
245 | return 0; |
---|
246 | } |
---|