| /* |
| * tag: dict management |
| * |
| * Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz |
| * |
| * See the file "COPYING" for further information about |
| * the copyright and warranty status of this work. |
| */ |
| |
| #include "config.h" |
| #include "kernel/kernel.h" |
| #include "dict.h" |
| #ifdef BOOTSTRAP |
| #include <string.h> |
| #else |
| #include "libc/string.h" |
| #endif |
| #include "cross.h" |
| |
| |
| unsigned char *dict = NULL; |
| ucell *last; |
| cell dicthead = 0; |
| cell dictlimit = 0; |
| |
| /* lfa2nfa |
| * converts a link field address to a name field address, |
| * i.e find pointer to a given words name |
| */ |
| |
| ucell lfa2nfa(ucell ilfa) |
| { |
| /* get offset from dictionary start */ |
| ilfa = ilfa - (ucell)pointer2cell(dict); |
| ilfa--; /* skip status */ |
| while (dict[--ilfa] == 0); /* skip all pad bytes */ |
| ilfa -= (dict[ilfa] - 128); |
| return ilfa + (ucell)pointer2cell(dict); |
| } |
| |
| /* lfa2cfa |
| * converts a link field address to a code field address. |
| * in this forth implementation this is just a fixed offset |
| */ |
| |
| static xt_t lfa2cfa(ucell ilfa) |
| { |
| return (xt_t)(ilfa + sizeof(cell)); |
| } |
| |
| |
| /* fstrlen - returns length of a forth string. */ |
| |
| ucell fstrlen(ucell fstr) |
| { |
| fstr -= pointer2cell(dict)+1; |
| //fstr -= pointer2cell(dict); FIXME |
| while (dict[++fstr] < 128) |
| ; |
| return dict[fstr] - 128; |
| } |
| |
| /* to_lower - convert a character to lowecase */ |
| |
| static int to_lower(int c) |
| { |
| return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c; |
| } |
| |
| /* fstrcmp - compare null terminated string with forth string. */ |
| |
| static int fstrcmp(const char *s1, ucell fstr) |
| { |
| char *s2 = (char*)cell2pointer(fstr); |
| while (*s1) { |
| if ( to_lower(*(s1++)) != to_lower(*(s2++)) ) |
| return -1; |
| } |
| return 0; |
| } |
| |
| /* fstrncpy - copy a forth string to a destination (with NULL termination) */ |
| |
| void fstrncpy(char *dest, ucell src, unsigned int maxlen) |
| { |
| int len = fstrlen(src); |
| |
| if (fstrlen(src) >= maxlen) len = maxlen - 1; |
| memcpy(dest, cell2pointer(src), len); |
| *(dest + len) = '\0'; |
| } |
| |
| |
| /* findword |
| * looks up a given word in the dictionary. This function |
| * is used by the c based interpreter and to find the "initialize" |
| * word. |
| */ |
| |
| xt_t findword(const char *s1) |
| { |
| ucell tmplfa, len; |
| |
| if (!last) |
| return 0; |
| |
| tmplfa = read_ucell(last); |
| |
| len = strlen(s1); |
| |
| while (tmplfa) { |
| ucell nfa = lfa2nfa(tmplfa); |
| |
| if (len == fstrlen(nfa) && !fstrcmp(s1, nfa)) { |
| return lfa2cfa(tmplfa); |
| } |
| |
| tmplfa = read_ucell(cell2pointer(tmplfa)); |
| } |
| |
| return 0; |
| } |
| |
| |
| /* findsemis_wordlist |
| * Given a DOCOL xt and a wordlist, find the address of the semis |
| * word at the end of the word definition. We do this by finding |
| * the word before this in the dictionary, then counting back one |
| * from the NFA. |
| */ |
| |
| static ucell findsemis_wordlist(ucell xt, ucell wordlist) |
| { |
| ucell tmplfa, nextlfa, nextcfa; |
| |
| if (!wordlist) |
| return 0; |
| |
| tmplfa = read_ucell(cell2pointer(wordlist)); |
| nextcfa = lfa2cfa(tmplfa); |
| |
| /* Catch the special case where the lfa of the word we |
| * want is the last word in the dictionary; in that case |
| * the end of the word is given by "here" - 1 */ |
| if (nextcfa == xt) |
| return pointer2cell(dict) + dicthead - sizeof(cell); |
| |
| while (tmplfa) { |
| |
| /* Peek ahead and see if the next CFA in the list is the |
| * one we are searching for */ |
| nextlfa = read_ucell(cell2pointer(tmplfa)); |
| nextcfa = lfa2cfa(nextlfa); |
| |
| /* If so, count back 1 cell from the current NFA */ |
| if (nextcfa == xt) |
| return lfa2nfa(tmplfa) - sizeof(cell); |
| |
| tmplfa = nextlfa; |
| } |
| |
| return 0; |
| } |
| |
| |
| /* findsemis |
| * Given a DOCOL xt, find the address of the semis word at the end |
| * of the word definition by searching all vocabularies */ |
| |
| ucell findsemis(ucell xt) |
| { |
| ucell usesvocab = findword("vocabularies?") + sizeof(cell); |
| unsigned int i; |
| |
| if (read_ucell(cell2pointer(usesvocab))) { |
| /* Vocabularies are in use, so search each one in turn */ |
| ucell numvocabs = findword("#order") + sizeof(cell); |
| |
| for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) { |
| ucell vocabs = findword("vocabularies") + 2 * sizeof(cell); |
| ucell semis = findsemis_wordlist(xt, read_cell(cell2pointer(vocabs + (i * sizeof(cell))))); |
| |
| /* If we get a non-zero result, we found the xt in this vocab */ |
| if (semis) |
| return semis; |
| } |
| } else { |
| /* Vocabularies not in use */ |
| return findsemis_wordlist(xt, read_ucell(last)); |
| } |
| |
| return 0; |
| } |
| |
| |
| /* findxtfromcell_wordlist |
| * Given a cell and a wordlist, determine the CFA of the word containing |
| * the cell or 0 if we are unable to return a suitable CFA |
| */ |
| |
| ucell findxtfromcell_wordlist(ucell incell, ucell wordlist) |
| { |
| ucell tmplfa; |
| |
| if (!wordlist) |
| return 0; |
| |
| tmplfa = read_ucell(cell2pointer(wordlist)); |
| while (tmplfa) { |
| if (tmplfa < incell) |
| return lfa2cfa(tmplfa); |
| |
| tmplfa = read_ucell(cell2pointer(tmplfa)); |
| } |
| |
| return 0; |
| } |
| |
| |
| /* findxtfromcell |
| * Given a cell, determine the CFA of the word containing |
| * the cell by searching all vocabularies |
| */ |
| |
| ucell findxtfromcell(ucell incell) |
| { |
| ucell usesvocab = findword("vocabularies?") + sizeof(cell); |
| unsigned int i; |
| |
| if (read_ucell(cell2pointer(usesvocab))) { |
| /* Vocabularies are in use, so search each one in turn */ |
| ucell numvocabs = findword("#order") + sizeof(cell); |
| |
| for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) { |
| ucell vocabs = findword("vocabularies") + 2 * sizeof(cell); |
| ucell semis = findxtfromcell_wordlist(incell, read_cell(cell2pointer(vocabs + (i * sizeof(cell))))); |
| |
| /* If we get a non-zero result, we found the xt in this vocab */ |
| if (semis) |
| return semis; |
| } |
| } else { |
| /* Vocabularies not in use */ |
| return findxtfromcell_wordlist(incell, read_ucell(last)); |
| } |
| |
| return 0; |
| } |
| |
| void dump_header(dictionary_header_t *header) |
| { |
| printk("OpenBIOS dictionary:\n"); |
| printk(" version: %d\n", header->version); |
| printk(" cellsize: %d\n", header->cellsize); |
| printk(" endianess: %s\n", header->endianess?"big":"little"); |
| printk(" compression: %s\n", header->compression?"yes":"no"); |
| printk(" relocation: %s\n", header->relocation?"yes":"no"); |
| printk(" checksum: %08x\n", target_long(header->checksum)); |
| printk(" length: %08x\n", target_long(header->length)); |
| printk(" last: %0" FMT_CELL_x "\n", target_cell(header->last)); |
| } |
| |
| ucell load_dictionary(const char *data, ucell len) |
| { |
| u32 checksum=0; |
| const char *checksum_walk; |
| ucell *walk, *reloc_table; |
| dictionary_header_t *header=(dictionary_header_t *)data; |
| |
| /* assertions */ |
| if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8)) |
| return 0; |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| dump_header(header); |
| #endif |
| |
| checksum_walk=data; |
| while (checksum_walk<data+len) { |
| checksum+=read_long(checksum_walk); |
| checksum_walk+=sizeof(u32); |
| } |
| |
| if(checksum) { |
| printk("Checksum invalid (%08x)!\n", checksum); |
| return 0; |
| } |
| |
| data += sizeof(dictionary_header_t); |
| |
| dicthead = target_long(header->length); |
| |
| memcpy(dict, data, dicthead); |
| reloc_table=(ucell *)(data+dicthead); |
| |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk("\nmoving dictionary (%x bytes) to %x\n", |
| (ucell)dicthead, (ucell)dict); |
| printk("\ndynamic relocation..."); |
| #endif |
| |
| for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead); |
| walk++) { |
| int pos, bit, l; |
| l=(walk-(ucell *)dict); |
| pos=l/BITS; |
| bit=l&~(-BITS); |
| if (reloc_table[pos] & target_ucell((ucell)1ULL << bit)) { |
| // printk("%lx, pos %x, bit %d\n",*walk, pos, bit); |
| write_ucell(walk, read_ucell(walk)+pointer2cell(dict)); |
| } |
| } |
| |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk(" done.\n"); |
| #endif |
| |
| last = (ucell *)(dict + target_ucell(header->last)); |
| |
| return -1; |
| } |