| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | #include "cli.h" |
| 16 | #include <stdio.h> |
| 17 | #include <stdlib.h> |
| 18 | #include <string.h> |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | const char *value_to_string (const s4_val_t *val) |
| 25 | { |
| 26 | static char buf[12]; |
| 27 | const char *ret; |
| 28 | int32_t i; |
| 29 | |
| 30 | if (!s4_val_get_str (val, &ret)) { |
| 31 | s4_val_get_int (val, &i); |
| 32 | sprintf (buf, "%i", i); |
| 33 | ret = buf; |
| 34 | } |
| 35 | |
| 36 | return ret; |
| 37 | } |
| 38 | |
| 39 | void print_list (list_t *l) |
| 40 | { |
| 41 | list_data_t *data; |
| 42 | GList *list = l->list; |
| 43 | int first = 1; |
| 44 | const char *sep; |
| 45 | const char *print_mode = get_var ("print_mode"); |
| 46 | |
| 47 | if (strcmp (print_mode, "compact") == 0) { |
| 48 | sep = ", "; |
| 49 | } else { |
| 50 | sep = ",\n"; |
| 51 | } |
| 52 | |
| 53 | printf ("["); |
| 54 | for (; list != NULL((void*)0); list = g_list_next (list)((list) ? (((GList *)(list))->next) : ((void*)0))) { |
| 55 | if (first) { |
| 56 | first = 0; |
| 57 | } else { |
| 58 | printf ("%s", sep); |
| 59 | } |
| 60 | data = list->data; |
| 61 | printf ("%s=%s (%s)", data->key, |
| 62 | value_to_string (data->val), |
| 63 | data->src); |
| 64 | } |
| 65 | printf ("]\n"); |
| 66 | } |
| 67 | |
| 68 | |
| 69 | static int columns_has_data (int count, const s4_result_t **cols) |
| 70 | { |
| 71 | int i; |
| 72 | for (i = 0; i < count; i++) { |
| 73 | if (cols[i] != NULL((void*)0)) |
| 74 | return 1; |
| 75 | } |
| 76 | |
| 77 | return 0; |
| 78 | } |
| 79 | |
| 80 | |
| 81 | static void print_row (int row, int column_width, int column_count, |
| 82 | const s4_result_t **columns, const char *print_format) |
| 83 | { |
| 84 | int i; |
| 85 | const s4_result_t *res; |
| 86 | char col_str[column_width]; |
| 87 | int compact = strcmp (print_format, "compact") == 0; |
| 88 | |
| 89 | printf ("\r|%5i ", row); |
| 90 | |
| 91 | do { |
| 92 | for (i = 0; i < column_count; i++) { |
| 19 | | Assuming 'i' is < 'column_count' | |
|
| 20 | | Loop condition is true. Entering loop body | |
|
| 93 | res = columns[i]; |
| 21 | | Assigned value is garbage or undefined |
|
| 94 | if (res != NULL((void*)0)) { |
| 95 | columns[i] = s4_result_next (res); |
| 96 | if (compact) { |
| 97 | snprintf (col_str, column_width + 1, "| %-*s", column_width, |
| 98 | value_to_string (s4_result_get_val (res))); |
| 99 | } else { |
| 100 | snprintf (col_str, column_width + 1, "| %s (%s) %*s", |
| 101 | value_to_string (s4_result_get_val (res)), |
| 102 | s4_result_get_src (res), |
| 103 | column_width, ""); |
| 104 | } |
| 105 | printf ("%s", col_str); |
| 106 | } else { |
| 107 | printf ("| %*s", column_width - 2, ""); |
| 108 | } |
| 109 | } |
| 110 | printf ("|\n| "); |
| 111 | } while (columns_has_data (column_count, columns)); |
| 112 | } |
| 113 | |
| 114 | |
| 115 | |
| 116 | |
| 117 | static const char *column_key (int col, const s4_resultset_t *set) |
| 118 | { |
| 119 | int row; |
| 120 | const char *ret = NULL((void*)0); |
| 121 | const s4_result_t *res; |
| 122 | |
| 123 | for (row = 0; row < s4_resultset_get_rowcount (set); row++) { |
| 124 | res = s4_resultset_get_result (set, row, col); |
| 125 | while (res != NULL((void*)0)) { |
| 126 | const char *key = s4_result_get_key (res); |
| 127 | if (ret != NULL((void*)0) && strcmp (ret, key)) { |
| 128 | return "_"; |
| 129 | } else if (ret == NULL((void*)0)) { |
| 130 | ret = key; |
| 131 | } |
| 132 | res = s4_result_next (res); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | return ret; |
| 137 | } |
| 138 | |
| 139 | |
| 140 | int find_column (const char *key, const s4_resultset_t *set) |
| 141 | { |
| 142 | int col; |
| 143 | |
| 144 | for (col = 0; col < s4_resultset_get_colcount (set); col++) { |
| 145 | const char *col_key = column_key (col, set); |
| 146 | if (col_key != NULL((void*)0) && strcmp (col_key, key) == 0) { |
| 147 | return col; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | return -1; |
| 152 | } |
| 153 | |
| 154 | |
| 155 | |
| 156 | |
| 157 | static int terminal_width (void) |
| 158 | { |
| 159 | const char *width = getenv ("COLUMNS"); |
| 160 | int ret; |
| 161 | |
| 162 | if (width == NULL((void*)0) || (ret = atoi (width)) == 0) { |
| 163 | return 80; |
| 164 | } |
| 165 | |
| 166 | return ret; |
| 167 | } |
| 168 | |
| 169 | |
| 170 | void print_result (const s4_resultset_t *set) |
| 171 | { |
| 172 | int col, row, total_width, col_width; |
| 173 | const s4_result_t **columns, *res; |
| 174 | const char *print_format = get_var ("print_mode"); |
| 175 | char *col_str; |
| 176 | |
| 177 | if (s4_resultset_get_rowcount (set) == 0) { |
| 8 | | Assuming the condition is false | |
|
| |
| 178 | printf ("No results\n"); |
| 179 | return; |
| 180 | } |
| 181 | |
| 182 | columns = malloc (sizeof (s4_result_t*) * s4_resultset_get_colcount (set)); |
| 183 | total_width = terminal_width () - 8; |
| 184 | col_width = total_width / s4_resultset_get_colcount (set); |
| 185 | col_str = malloc (col_width + 1); |
| 186 | |
| 187 | if (strcmp (print_format, "pretty") == 0 |
| 188 | || strcmp (print_format, "compact") == 0) { |
| 189 | |
| 190 | printf ("| row "); |
| 191 | for (col = 0; col < s4_resultset_get_colcount (set); col++) { |
| 10 | | Assuming the condition is false | |
|
| 11 | | Loop condition is false. Execution continues on line 196 | |
|
| 192 | snprintf (col_str, col_width + 1, "| %-*s", |
| 193 | col_width - 2, column_key (col, set)); |
| 194 | printf ("%s", col_str); |
| 195 | } |
| 196 | printf ("|\n|------|"); |
| 197 | for (col = 0; col < s4_resultset_get_colcount (set); col++) { |
| 12 | | Assuming the condition is false | |
|
| 13 | | Loop condition is false. Execution continues on line 203 | |
|
| 198 | for (row = 1; row < col_width; row++) { |
| 199 | putchar ('-'); |
| 200 | } |
| 201 | putchar ('|'); |
| 202 | } |
| 203 | putchar ('\n'); |
| 204 | |
| 205 | |
| 206 | for (row = 0; row < s4_resultset_get_rowcount (set); row++) { |
| 14 | | Assuming the condition is true | |
|
| 15 | | Loop condition is true. Entering loop body | |
|
| 207 | for (col = 0; col < s4_resultset_get_colcount (set); col++) { |
| 16 | | Assuming the condition is false | |
|
| 17 | | Loop condition is false. Execution continues on line 210 | |
|
| 208 | columns[col] = s4_resultset_get_result (set, row, col); |
| 209 | } |
| 210 | print_row (row, col_width, s4_resultset_get_colcount (set), |
| |
| 211 | columns, print_format); |
| 212 | } |
| 213 | } else { |
| 214 | |
| 215 | printf (" row | col | data\n"); |
| 216 | |
| 217 | |
| 218 | for (row = 0; row < s4_resultset_get_rowcount (set); row++) { |
| 219 | printf ("\r%5i ", row); |
| 220 | for (col = 0; col < s4_resultset_get_colcount (set); col++) { |
| 221 | printf ("| %5i ", col); |
| 222 | for (res = s4_resultset_get_result (set, row, col); |
| 223 | res != NULL((void*)0); |
| 224 | res = s4_result_next (res)) { |
| 225 | printf ("| %s=%s (%s)\n | ", s4_result_get_key (res), |
| 226 | value_to_string (s4_result_get_val (res)), |
| 227 | s4_result_get_src (res)); |
| 228 | } |
| 229 | printf ("\r "); |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | printf (" \r"); |
| 234 | |
| 235 | free (col_str); |
| 236 | free (columns); |
| 237 | } |
| 238 | |
| 239 | void print_cond (s4_condition_t *cond) |
| 240 | { |
| 241 | int i; |
| 242 | const char *operation; |
| 243 | s4_condition_t *operand; |
| 244 | |
| 245 | if (s4_cond_is_filter (cond)) { |
| 246 | switch (s4_cond_get_filter_type (cond)) { |
| 247 | case S4_FILTER_EQUAL: operation = "="; break; |
| 248 | case S4_FILTER_NOTEQUAL: operation = "!="; break; |
| 249 | case S4_FILTER_SMALLER: operation = "<"; break; |
| 250 | case S4_FILTER_GREATER: operation = ">"; break; |
| 251 | case S4_FILTER_SMALLEREQ: operation = "<="; break; |
| 252 | case S4_FILTER_GREATEREQ: operation = ">="; break; |
| 253 | case S4_FILTER_MATCH: operation = "~"; break; |
| 254 | case S4_FILTER_EXISTS: operation = "+"; break; |
| 255 | case S4_FILTER_TOKEN: operation = "^"; break; |
| 256 | default: operation = "unknown filter"; break; |
| 257 | } |
| 258 | if (s4_cond_get_key (cond) != NULL((void*)0)) { |
| 259 | printf ("%s %s", s4_cond_get_key (cond), operation); |
| 260 | } else { |
| 261 | printf ("%s", operation); |
| 262 | } |
| 263 | if (s4_cond_get_filter_type (cond) == S4_FILTER_MATCH) { |
| 264 | printf (" pattern"); |
| 265 | } else if (s4_cond_get_filter_type (cond) == S4_FILTER_TOKEN) { |
| 266 | printf (" %s", (const char *)s4_cond_get_funcdata (cond)); |
| 267 | } else if (s4_cond_get_filter_type (cond) != S4_FILTER_EXISTS) { |
| 268 | printf (" %s", value_to_string (s4_cond_get_funcdata (cond))); |
| 269 | } |
| 270 | } else { |
| 271 | switch (s4_cond_get_combiner_type (cond)) { |
| 272 | case S4_COMBINE_AND: operation = "&"; break; |
| 273 | case S4_COMBINE_NOT: operation = "!"; break; |
| 274 | case S4_COMBINE_OR: operation = "|"; break; |
| 275 | default: operation = "unknown combiner"; break; |
| 276 | } |
| 277 | |
| 278 | if (s4_cond_get_combiner_type (cond) == S4_COMBINE_NOT) { |
| 279 | printf ("!("); |
| 280 | } else { |
| 281 | printf ("("); |
| 282 | } |
| 283 | for (i = 0; (operand = s4_cond_get_operand (cond, i)) != NULL((void*)0); i++) { |
| 284 | if (i != 0) |
| 285 | printf (") %s (", operation); |
| 286 | print_cond (operand); |
| 287 | } |
| 288 | printf (")"); |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | void print_fetch (s4_fetchspec_t *fetch) |
| 293 | { |
| 294 | int i; |
| 295 | const char *sep; |
| 296 | const char *print_mode = get_var ("print_mode"); |
| 297 | |
| 298 | if (strcmp (print_mode, "compact") == 0) { |
| 299 | sep = ", "; |
| 300 | } else { |
| 301 | sep = ",\n"; |
| 302 | } |
| 303 | printf ("("); |
| 304 | for (i = 0; i < s4_fetchspec_size (fetch); i++) { |
| 305 | if (i != 0) { |
| 306 | printf ("%s", sep); |
| 307 | } |
| 308 | printf ("%s", s4_fetchspec_get_key (fetch, i)); |
| 309 | } |
| 310 | printf (")\n"); |
| 311 | } |
| 312 | |
| 313 | void print_vars () |
| 314 | { |
| 315 | GHashTableIter iter; |
| 316 | char *str; |
| 317 | void *val; |
| 318 | |
| 319 | g_hash_table_iter_init (&iter, cond_table); |
| 320 | printf ("Cond table\n"); |
| 321 | while (g_hash_table_iter_next (&iter, (void**)&str, &val)) { |
| 1 | Loop condition is false. Execution continues on line 327 | |
|
| 322 | printf ("%s: ", str); |
| 323 | print_cond (val); |
| 324 | printf ("\n"); |
| 325 | } |
| 326 | |
| 327 | g_hash_table_iter_init (&iter, fetch_table); |
| 328 | printf ("Fetch table\n"); |
| 329 | while (g_hash_table_iter_next (&iter, (void**)&str, &val)) { |
| 2 | | Loop condition is false. Execution continues on line 333 | |
|
| 330 | printf ("%s: ", str); |
| 331 | print_fetch (val); |
| 332 | } |
| 333 | g_hash_table_iter_init (&iter, res_table); |
| 334 | printf ("Result table\n"); |
| 335 | while (g_hash_table_iter_next (&iter, (void**)&str, &val)) { |
| 3 | | Loop condition is true. Entering loop body | |
|
| 4 | | Loop condition is true. Entering loop body | |
|
| 5 | | Loop condition is true. Entering loop body | |
|
| 6 | | Loop condition is true. Entering loop body | |
|
| 336 | printf ("%s: ", str); |
| 337 | print_result (val); |
| |
| 338 | } |
| 339 | g_hash_table_iter_init (&iter, list_table); |
| 340 | printf ("List table\n"); |
| 341 | while (g_hash_table_iter_next (&iter, (void**)&str, &val)) { |
| 342 | printf ("%s: ", str); |
| 343 | print_list (val); |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | void print_help (void) |
| 348 | { |
| 349 | printf("All statements must end with a semicolon\n\n" |
| 350 | "Statements with no value:\n" |
| 351 | ".add <list>, <list> - For every (key, val) from the first list it adds\n" |
| 352 | " the attributes (key, val, src) from the second list\n" |
| 353 | ".del <list>, <list> - For every (key, val) from the first list it deletes\n" |
| 354 | " the attributes (key, val, src) from the second list\n" |
| 355 | ".exit - Exit the program\n" |
| 356 | ".help - Prints this help\n" |
| 357 | ".set key value - Sets the option key to val\n" |
| 358 | ".set key - Shows the value of the key\n" |
| 359 | ".set - Shows the value of all keys\n" |
| 360 | ".vars - Prints all bound variables\n\n" |
| 361 | "?var = <cond> - Assigns cond to the condition variable var\n" |
| 362 | "%%var = <fetch> - Assigns fetch to the fetch variable var\n" |
| 363 | "@var = <result> - Assigns var to something returning result\n" |
| 364 | "$var = <list> - Assigns the list to the list variable var\n" |
| 365 | "#var = <pref> - Assigns the pref to the souce preference variable var\n\n" |
| 366 | "Conditions (<cond>):\n" |
| 367 | "?var - Returns the condition bound to var\n" |
| 368 | "!cond - Matches everything cond does not match\n" |
| 369 | "cond1 & cond2 - Matches if both cond1 and cond2 matches\n" |
| 370 | "cond1 | cond2 - Matches if cond1 or cond2 matches\n\n" |
| 371 | "Filter conditions\n" |
| 372 | "key = value - Matches all entries where key equals value\n" |
| 373 | "key ~ value - Matches all entries where key matches value\n" |
| 374 | "key < value - Matches all entries where key is smaller than value\n" |
| 375 | "key > value - Matches all entries where key is greater than value\n" |
| 376 | "key ^ token - Matches all entries where key has a token equal to token\n" |
| 377 | "key != value - Matches all entries where key does not equal value\n" |
| 378 | "key <= value - Matches all entries where key is smaller or equal to value\n" |
| 379 | "key >= value - Matches all entries where key is greater or equal to value\n" |
| 380 | "= value - Matches all entries where one or more keys equals value\n" |
| 381 | "~ value - Matches all entries where one or more keys matches value\n" |
| 382 | "< value - Matches all entries where one or more keys is smaller than value\n" |
| 383 | "> value - Matches all entries where one or more keys is greater than value\n" |
| 384 | "^ token - Matches all entries where one or more keys has token\n" |
| 385 | "!= value - Matches all entries where one or more keys does not equal value\n" |
| 386 | "<= value - Matches all entries where one or more keys is smaller or equal to value\n" |
| 387 | ">= value - Matches all entries where one or more keys is greater or equal to value\n" |
| 388 | "+key - Matches all entries that has key\n" |
| 389 | "+ - Matches everything\n" |
| 390 | "<pref> may be added after all filter conditions to use a source preference to only match\n" |
| 391 | "against the highest priority source in the source preference\n\n" |
| 392 | "Fetch specification (<fetch>):\n" |
| 393 | "%%var - Returns the fetch spec bound to var\n" |
| 394 | "(key1, ..., keyn) - Fetches keys 1 through n from matching entries\n" |
| 395 | "(key1 <pref>,...) - Fetches key1 using the source preference given\n" |
| 396 | "key - Fetches key from matching entries\n" |
| 397 | "key <pref> - Fetches key using the source preference given\n" |
| 398 | "_ - Fetches everything from matching entries\n\n" |
| 399 | "Results (<result>):\n" |
| 400 | ".query <fetch> <cond> - Queries the database, returns a result\n\n" |
| 401 | "@var - Returns the result bound to var\n\n" |
| 402 | "Lists (<list>):\n" |
| 403 | "$var - Returns the list bound to the variable var\n" |
| 404 | "<result>{<rng>,<rng>} - Creates a list of the columns given by {row,col}.\n" |
| 405 | "<result>{<rng>, key} - Creates a list of the column where the column key\n" |
| 406 | " equals key and the rows are in the range\n" |
| 407 | "[key val src, ...] - Creates a list\n" |
| 408 | "[key val, ...] - Creates a list where source is set to default_source\n\n" |
| 409 | "Ranges (<rng>):\n" |
| 410 | "start - stop - Creates a range from start to stop (inclusive)\n" |
| 411 | " - stop - Creates a range from 0 to stop\n" |
| 412 | "start - - Creates a range from start with no stop\n" |
| 413 | " - - Creates a range from 0 with no stop\n\n" |
| 414 | "Source preferences (<pref>):\n" |
| 415 | "#var - Returns the source preference bound to var\n" |
| 416 | ":src1:src2:...:srcn - Creates a new source preference where src1 has the highest priority,\n" |
| 417 | " src2 seconds highest and so on\n\n" |
| 418 | "Shorthand:\n" |
| 419 | ".q = .query\n" |
| 420 | ".a = .add\n" |
| 421 | ".d = .del\n" |
| 422 | ".v = .vars\n" |
| 423 | ".h = .help\n" |
| 424 | ".? = .help\n" |
| 425 | ".s = .set\n" |
| 426 | ".e = .exit\n" |
| 427 | ); |
| 428 | } |