#include "lib.h" int psyc_inherits (char* sho, size_t slen, char* lon, size_t llen) { // this allows to pass zero-terminated strings instead of providing // the length.. but we would be faster here if we expected the callee // to always use the PSYC_C2ARG() macro instead. additionally, the // empty string would then be fully supported (in case you want that) // Disabled this, let's use that macro rather. //if (!slen) slen = strlen(sho); //if (!llen) llen = strlen(lon); if (slen == 0 || *sho != '_' || llen == 0 || *lon != '_') { P1(("Please use long format keywords (compact ones would be faster, I know..)\n")) return -2; } if (slen > llen) { P1(("The long string is shorter than the short one.\n")) return -3; } if (!strncmp(sho, lon, slen)) { /* according to PSYC spec we have hereby already proved * inheritance. the following check is optional! */ if (llen > slen && lon[slen] != '_') { /* It is illegal to introduce a keyword family * that starts just like an existing one. Since * _failure exists, you can't use _fail. But * implementations are not required to recognize * that. */ P1(("Illegal choice of keyword names!\n")) return -4; } return 0; } P4(("%.*s does not inherit from %.*s.\n", (int)llen, lon, (int)slen, sho)) return 1; } int psyc_matches (char* sho, size_t slen, char* lon, size_t llen) { char *s, *l, *se, *le; //if (!slen) slen = strlen(sho); //if (!llen) llen = strlen(lon); if (slen == 0 || *sho != '_' || llen == 0 || *lon != '_') { P1(("Please use long format keywords (compact ones would be faster, I know..)\n")) return -2; } if (slen > llen) { P1(("The long string is shorter than the short one.\n")) return -3; } if (slen == llen) { if (!strncmp(sho, lon, slen)) { P1(("Identical arguments.\n")) return 0; } P1(("Same length but different.\nNo match, but they could be related or have a common type.\n")) return -4; } P3(("# psyc_matches short '%.*s' in long '%.*s' ?\n", (int)slen, sho, (int)llen, lon)) se = sho+slen; le = lon+llen; sho++; lon++; slen--; llen--; while(*sho && sho < se) { P3(("# comparing short '%.*s' (%d)\n", (int)slen, sho, (int)slen)) unless (s = memchr(sho, '_', slen)) s = se; P4(("# sho goes '%c' and lon goes '%c'\n", *sho, (int)*lon)) while(*lon && lon < le) { P3(("# against long '%.*s' (%d)\n", (int)llen, lon, (int)llen)) unless (l = memchr(lon, '_', llen)) l = le; P3(("# %ld == %ld && !strncmp '%.*s', '%.*s'\n", s-sho, l-lon, (int)(s-sho), sho, (int)(s-sho), lon)) if (l-lon == s-sho && !strncmp(sho, lon, s-sho)) goto foundone; P4(("# failed\n")) llen -= l-lon + 1; lon = ++l; } goto failed; foundone: P3(("# found %ld of short '%.*s' and long '%.*s'\n", s-sho, (int)(s-sho), sho, (int)(s-sho), lon)) llen -= l-lon; slen -= s-sho; sho = ++s; lon = ++l; } return 0; failed: P4(("No, they don't match.\n")) return 1; } /** * Check if keyword is in array. * * @param array The array to search, should be ordered alphabetically. * @param size Size of array. * @param kw Keyword to look for. * @param kwlen Length of keyword. * @param inherit If true, look for any keyword inheriting from name, otherwise only exact matches are returned. * @param matching A temporary array used for keeping track of results. * Should be the same size as the array we're searching. * * @return The value of the matched variable in the array. */ int psyc_in_array (const psycMatchVar *array, size_t size, const char *kw, size_t kwlen, psycBool inherit, int8_t *matching) { size_t cursor = 1; uint8_t i, m = 0; //memset(&matching, -1, sizeof matching); if (kwlen < 2 || kw[0] != '_') return 0; // first find the keywords with matching length for (i=0; i array[i].key.length && kw[array[i].key.length] == '_')) matching[m++] = i; matching[m] = -1; // mark the end of matching indexes while (cursor < kwlen && matching[0] >= 0) { for (i = m = 0; i < size; i++) { if (matching[i] < 0) break; // reached the end of possible matches if (cursor < array[matching[i]].key.length && array[matching[i]].key.ptr[cursor] == kw[cursor]) matching[m++] = matching[i]; // found a match, update matching indexes else if (cursor == array[matching[i]].key.length && kw[cursor] == '_') return array[matching[0]].value; // _ after the end of a matching prefix else if (array[matching[i]].key.ptr[cursor] > kw[cursor]) break; // passed the possible matches in alphabetical order in the array } if (m < size) matching[m] = -1; // mark the end of matching indexes cursor++; } // return first match if found return matching[0] >= 0 ? array[matching[0]].value : 0; } #ifdef CMDTOOL int main(int argc, char **argv) { if (argc != 3) { printf("Usage: %s \n\nExample: %s _failure_delivery _failure_unsuccessful_delivery_death\n", argv[0], argv[0]); return -1; } if (psyc_matches(argv[1], 0, argv[2], 0) == 0) printf("Yes, %s matches %s!\n", argv[1], argv[2]); if (psyc_inherits(argv[1], 0, argv[2], 0) == 0) printf("Yes, %s inherits from %s!\n", argv[2], argv[1]); } #endif