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