cmd.c (5164B)
1 /* 2 * Copyright (c) 2023-2024 lumidify <nobody@lumidify.org> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "cmd.h" 18 19 #include <string.h> 20 21 #include "err.h" 22 #include "ltkd.h" 23 #include "widget.h" 24 25 #include <ltk/ltk.h> 26 #include <ltk/util.h> 27 #include <ltk/color.h> 28 #include <ltk/graphics.h> 29 30 int 31 ltkd_parse_cmd( 32 ltkd_cmd_token *tokens, size_t num_tokens, 33 ltkd_cmdarg_parseinfo *parseinfo, size_t num_arg, ltkd_error *err) { 34 const char *errstr = NULL; 35 ltk_renderdata *renderdata = ltk_get_renderer(); 36 if (num_tokens > num_arg || (num_tokens < num_arg && !parseinfo[num_tokens].optional)) { 37 err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; 38 err->arg = -1; 39 return 1; 40 } 41 size_t i = 0; 42 for (; i < num_tokens; i++) { 43 if (parseinfo[i].type != CMDARG_DATA && tokens[i].contains_nul) { 44 err->type = ERR_INVALID_ARGUMENT; 45 err->arg = i; 46 goto error; 47 } 48 switch (parseinfo[i].type) { 49 case CMDARG_INT: 50 parseinfo[i].val.i = ltk_strtonum(tokens[i].text, parseinfo[i].min, parseinfo[i].max, &errstr); 51 if (errstr) { 52 err->type = ERR_INVALID_ARGUMENT; 53 err->arg = i; 54 goto error; 55 } 56 parseinfo[i].initialized = 1; 57 break; 58 case CMDARG_STICKY: 59 parseinfo[i].val.sticky = LTK_STICKY_NONE; 60 for (const char *c = tokens[i].text; *c != '\0'; c++) { 61 switch (*c) { 62 case 't': 63 parseinfo[i].val.sticky |= LTK_STICKY_TOP; 64 break; 65 case 'b': 66 parseinfo[i].val.sticky |= LTK_STICKY_BOTTOM; 67 break; 68 case 'r': 69 parseinfo[i].val.sticky |= LTK_STICKY_RIGHT; 70 break; 71 case 'l': 72 parseinfo[i].val.sticky |= LTK_STICKY_LEFT; 73 break; 74 case 'w': 75 parseinfo[i].val.sticky |= LTK_STICKY_SHRINK_WIDTH; 76 break; 77 case 'h': 78 parseinfo[i].val.sticky |= LTK_STICKY_SHRINK_HEIGHT; 79 break; 80 case 'p': 81 parseinfo[i].val.sticky |= LTK_STICKY_PRESERVE_ASPECT_RATIO; 82 break; 83 default: 84 err->type = ERR_INVALID_ARGUMENT; 85 err->arg = i; 86 goto error; 87 } 88 } 89 parseinfo[i].initialized = 1; 90 break; 91 case CMDARG_WIDGET: 92 parseinfo[i].val.widget = ltkd_get_widget(tokens[i].text, parseinfo[i].widget_type, err); 93 if (!parseinfo[i].val.widget) { 94 err->arg = i; 95 goto error; 96 } 97 parseinfo[i].initialized = 1; 98 break; 99 case CMDARG_STRING: 100 parseinfo[i].val.str = tokens[i].text; 101 parseinfo[i].initialized = 1; 102 break; 103 case CMDARG_DATA: 104 parseinfo[i].val.data = tokens[i].text; 105 parseinfo[i].initialized = 1; 106 parseinfo[i].len = tokens[i].len; 107 break; 108 case CMDARG_COLOR: 109 if (!(parseinfo[i].val.color = ltk_color_create(renderdata, tokens[i].text))) { 110 /* FIXME: this could fail even if the argument is fine */ 111 err->type = ERR_INVALID_ARGUMENT; 112 err->arg = i; 113 goto error; 114 } 115 parseinfo[i].initialized = 1; 116 break; 117 case CMDARG_BOOL: 118 if (strcmp(tokens[i].text, "true") == 0) { 119 parseinfo[i].val.b = 1; 120 } else if (strcmp(tokens[i].text, "false") == 0) { 121 parseinfo[i].val.b = 0; 122 } else { 123 err->type = ERR_INVALID_ARGUMENT; 124 err->arg = i; 125 goto error; 126 } 127 parseinfo[i].initialized = 1; 128 break; 129 case CMDARG_ORIENTATION: 130 if (strcmp(tokens[i].text, "horizontal") == 0) { 131 parseinfo[i].val.orient = LTK_HORIZONTAL; 132 } else if (strcmp(tokens[i].text, "vertical") == 0) { 133 parseinfo[i].val.orient = LTK_VERTICAL; 134 } else { 135 err->type = ERR_INVALID_ARGUMENT; 136 err->arg = i; 137 goto error; 138 } 139 parseinfo[i].initialized = 1; 140 break; 141 case CMDARG_BORDERSIDES: 142 parseinfo[i].val.border = LTK_BORDER_NONE; 143 for (const char *c = tokens[i].text; *c != '\0'; c++) { 144 switch (*c) { 145 case 't': 146 parseinfo[i].val.border |= LTK_BORDER_TOP; 147 break; 148 case 'b': 149 parseinfo[i].val.border |= LTK_BORDER_BOTTOM; 150 break; 151 case 'l': 152 parseinfo[i].val.border |= LTK_BORDER_LEFT; 153 break; 154 case 'r': 155 parseinfo[i].val.border |= LTK_BORDER_RIGHT; 156 break; 157 default: 158 err->type = ERR_INVALID_ARGUMENT; 159 err->arg = i; 160 goto error; 161 } 162 } 163 parseinfo[i].initialized = 1; 164 break; 165 case CMDARG_IGNORE: 166 parseinfo[i].initialized = 1; 167 break; 168 default: 169 ltkd_fatal("Invalid command argument type. This should not happen.\n"); 170 /* TODO: ltk_assert(0); */ 171 } 172 } 173 for (; i < num_arg; i++) { 174 parseinfo[i].initialized = 0; 175 } 176 return 0; 177 error: 178 for (; i-- > 0;) { 179 if (parseinfo[i].type == CMDARG_COLOR) { 180 ltk_color_destroy(renderdata, parseinfo[i].val.color); 181 } 182 parseinfo[i].initialized = 0; 183 } 184 return 1; 185 }