[18713] | 1 | #include <stdio.h> |
---|
| 2 | #include <string.h> |
---|
| 3 | #include <sys/stat.h> |
---|
[21004] | 4 | #include <locale.h> |
---|
[18713] | 5 | |
---|
[21004] | 6 | #ifdef HAVE_CONFIG_H |
---|
| 7 | # include "config.h" |
---|
| 8 | #endif |
---|
[18713] | 9 | |
---|
[21004] | 10 | #include <gst/gst.h> |
---|
[18713] | 11 | |
---|
| 12 | |
---|
[21004] | 13 | typedef struct |
---|
| 14 | { |
---|
[18713] | 15 | gchar *name; |
---|
| 16 | GSList *srcpads; |
---|
| 17 | GSList *sinkpads; |
---|
| 18 | GSList *srcpadtemplates; |
---|
| 19 | GSList *sinkpadtemplates; |
---|
| 20 | GSList *arguments; |
---|
| 21 | } comp_element; |
---|
| 22 | |
---|
[21004] | 23 | enum |
---|
| 24 | { |
---|
[18713] | 25 | ARG_INT, |
---|
| 26 | ARG_FILENAME, |
---|
| 27 | ARG_ENUM |
---|
| 28 | }; |
---|
| 29 | |
---|
[21004] | 30 | typedef struct |
---|
| 31 | { |
---|
[18713] | 32 | gchar *name; |
---|
| 33 | int type; |
---|
| 34 | GSList *enums; |
---|
| 35 | } comp_argument; |
---|
| 36 | |
---|
[21004] | 37 | typedef struct |
---|
| 38 | { |
---|
[18713] | 39 | gint value; |
---|
| 40 | gchar *nick; |
---|
| 41 | } enum_value; |
---|
| 42 | |
---|
| 43 | |
---|
[21004] | 44 | void |
---|
| 45 | print_match_list (gchar * prefix, int len, GSList * wordlist) |
---|
| 46 | { |
---|
[18713] | 47 | GSList *words = wordlist; |
---|
| 48 | |
---|
| 49 | while (words) { |
---|
[21004] | 50 | if (!len || !strncmp ((gchar *) (words->data), prefix, len)) |
---|
| 51 | printf ("%s\n", (gchar *) (words->data)); |
---|
[18713] | 52 | words = g_slist_next (words); |
---|
| 53 | } |
---|
| 54 | } |
---|
| 55 | |
---|
[21004] | 56 | int |
---|
| 57 | match_element (comp_element * element, gchar * name) |
---|
| 58 | { |
---|
| 59 | return strcmp (element->name, name); |
---|
[18713] | 60 | } |
---|
| 61 | |
---|
[21004] | 62 | int |
---|
| 63 | main (int argc, char *argv[]) |
---|
| 64 | { |
---|
[18713] | 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; |
---|
[21004] | 84 | |
---|
| 85 | setlocale (LC_ALL, ""); |
---|
| 86 | |
---|
| 87 | if (argc < 4) { |
---|
| 88 | fprintf (stderr, "gst-complete called with invalid arguments\n"); |
---|
| 89 | exit (1); |
---|
[18713] | 90 | } |
---|
| 91 | |
---|
| 92 | prev_word = argv[3]; |
---|
| 93 | partial_word = argv[2]; |
---|
| 94 | |
---|
[21004] | 95 | partial_len = strlen (partial_word); |
---|
[18713] | 96 | |
---|
| 97 | /***** Loading the completion information from the registry *****/ |
---|
| 98 | |
---|
[21004] | 99 | if (stat (GST_CACHE_DIR "/compreg.xml", &stat_buf) == 0) { |
---|
| 100 | doc = xmlParseFile (GST_CACHE_DIR "/compreg.xml"); |
---|
[18713] | 101 | } else { |
---|
| 102 | exit (1); |
---|
| 103 | } |
---|
| 104 | rootnode = doc->xmlRootNode; |
---|
| 105 | |
---|
| 106 | elementnode = rootnode->xmlChildrenNode; |
---|
| 107 | while (elementnode) { |
---|
[21004] | 108 | if (!strcmp (elementnode->name, "element")) { |
---|
| 109 | element = g_new0 (comp_element, 1); |
---|
[18713] | 110 | propnode = elementnode->xmlChildrenNode; |
---|
| 111 | while (propnode) { |
---|
| 112 | |
---|
[21004] | 113 | if (!strcmp (propnode->name, "name")) { |
---|
| 114 | element->name = xmlNodeGetContent (propnode); |
---|
[18713] | 115 | /* fprintf(stderr,element->name); */ |
---|
[21004] | 116 | } else if (!strcmp (propnode->name, "srcpad")) { |
---|
| 117 | element->srcpads = |
---|
| 118 | g_slist_prepend (element->srcpads, xmlNodeGetContent (propnode)); |
---|
[18713] | 119 | /* fprintf(stderr,"."); */ |
---|
[21004] | 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)); |
---|
[18713] | 127 | /* fprintf(stderr,"."); */ |
---|
[21004] | 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); |
---|
[18713] | 135 | argument->type = ARG_INT; |
---|
| 136 | |
---|
| 137 | /* walk through the values data */ |
---|
| 138 | argnode = propnode->xmlChildrenNode; |
---|
| 139 | while (argnode) { |
---|
[21004] | 140 | if (!strcmp (argnode->name, "filename")) { |
---|
[18713] | 141 | argument->type = ARG_FILENAME; |
---|
[21004] | 142 | } else if (!strcmp (argnode->name, "option")) { |
---|
[18713] | 143 | argument->type = ARG_ENUM; |
---|
[21004] | 144 | option = g_new0 (enum_value, 1); |
---|
| 145 | sscanf (xmlNodeGetContent (argnode), "%d", &option->value); |
---|
[18713] | 146 | argument->enums = g_slist_prepend (argument->enums, option); |
---|
| 147 | } |
---|
| 148 | argnode = argnode->next; |
---|
| 149 | } |
---|
| 150 | |
---|
[21004] | 151 | element->arguments = g_slist_prepend (element->arguments, argument); |
---|
[18713] | 152 | } |
---|
| 153 | |
---|
| 154 | propnode = propnode->next; |
---|
| 155 | } |
---|
[21004] | 156 | element_list = g_list_prepend (element_list, element); |
---|
| 157 | element_names = g_slist_prepend (element_names, element->name); |
---|
[18713] | 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 */ |
---|
[21004] | 169 | if (strstr (prev_word, "-launch")) { |
---|
[18713] | 170 | /* print out only elements with no sink pad or padtemplate */ |
---|
| 171 | elements = element_list; |
---|
| 172 | while (elements) { |
---|
[21004] | 173 | element = (comp_element *) (elements->data); |
---|
[18713] | 174 | if (!element->sinkpads && !element->sinkpadtemplates) |
---|
| 175 | words = g_slist_prepend (words, element->name); |
---|
[21004] | 176 | elements = g_list_next (elements); |
---|
[18713] | 177 | } |
---|
| 178 | } |
---|
| 179 | |
---|
| 180 | /* if the previous word is a connection */ |
---|
[21004] | 181 | if (strchr (prev_word, '!')) { |
---|
[18713] | 182 | /* print out oly elements with a sink pad or template */ |
---|
| 183 | elements = element_list; |
---|
| 184 | while (elements) { |
---|
[21004] | 185 | element = (comp_element *) (elements->data); |
---|
[18713] | 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 */ |
---|
[21004] | 193 | if (strchr (prev_word, '=')) { |
---|
| 194 | fprintf (stderr, "it's an arg, but dunno what element yet\n"); |
---|
[18713] | 195 | } |
---|
| 196 | |
---|
[21004] | 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))) { |
---|
[18713] | 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++; |
---|
[21004] | 209 | words = |
---|
| 210 | g_slist_prepend (words, g_strdup_printf ("%s!", |
---|
| 211 | (gchar *) (pads->data))); |
---|
[18713] | 212 | pads = g_slist_next (pads); |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | /* padtemplates */ |
---|
| 216 | pads = element->srcpadtemplates; |
---|
| 217 | while (pads) { |
---|
| 218 | num_pads++; |
---|
[21004] | 219 | word = g_strdup_printf ("%s!", (gchar *) (pads->data)); |
---|
| 220 | if (!g_slist_find_custom (words, word, (GCompareFunc) strcmp)) |
---|
[18713] | 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) { |
---|
[21004] | 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)); |
---|
[18713] | 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 | } |
---|