#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// The runtime environment assumes ISO8859/1 (European including Spain)
// CH, LL, and RR are not supported glyphs so we handle them here using 2 letters
// Note that when compiled as a stand-alone .exe under DOS/Windows,
// the default DOS character set is *not* ISO8859/1 and therefore the
// accented characters will not be displayed correctly.
// Cristian wants the first word to automatically link to DRAE (if 'si' checked)
// but that cannot be done with this structure, unless we generate the top-level
// enclosing framework as well, which will be quite a major rewrite. On hold...
// Customise here:
#define TITLE "Juez Lingüístico FISE"
#define Version "2.0"
#define ENTER_WORD "Introduzca la palabra por la que desea consultar"
#define SUBMIT "Consultar"
#define GOOD_WORD "PALABRA ACEPTADA"
#define BAD_WORD "PALABRA NO ACEPTADA"
#define INVALID_ENTRY "Caracteres no válidos"
#define NO_WORD "Debe introducir una palabra."
#define WRONG_SIZE "La palabra consultada debe tener entre dos y quince fichas"
#define NO_ARG_GIVEN ""
//#define NO_ARG_GIVEN "(vacio)"
#define WORD "palabra"
// CHANGE IT BACK TO juez.cgi ONCE TESTING IS COMPLETE
#define PROGNAME "juez.cgi"
static int showroot = (0==0);
static char linkhack[1024] = { '\0' };
#include "FISE/FISE-ROOT.h" // directory is protected. File is not available for download
#define LATIN_CAPITAL_LETTER_N_WITH_TILDE 0xD1
#define LATIN_SMALL_LETTER_N_WITH_TILDE 0xF1
#define LATIN_SMALL_LETTER_A_WITH_ACUTE 0xE1
#define LATIN_SMALL_LETTER_E_WITH_ACUTE 0xE9
#define LATIN_SMALL_LETTER_I_WITH_ACUTE 0xED
#define LATIN_SMALL_LETTER_O_WITH_ACUTE 0xF3
#define LATIN_SMALL_LETTER_U_WITH_ACUTE 0xFA
#define LATIN_SMALL_LETTER_U_WITH_DIAERESIS 0xFC
#define LATIN_SMALL_LETTER_E_WITH_GRAVE 0xE8
#define LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX 0xEE
#define LATIN_CAPITAL_LETTER_A_WITH_ACUTE 0xC1
#define LATIN_CAPITAL_LETTER_E_WITH_ACUTE 0xC9
#define LATIN_CAPITAL_LETTER_I_WITH_ACUTE 0xCD
#define LATIN_CAPITAL_LETTER_O_WITH_ACUTE 0xD3
#define LATIN_CAPITAL_LETTER_U_WITH_ACUTE 0xDA
#define LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS 0xDC
#define LATIN_CAPITAL_LETTER_E_WITH_GRAVE 0xC8
#define LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX 0xCE
/***************************************************************************
* Web param stuff derived directly from code by Harry H. Cheng, 11/24/1995 *
****************************************************************************/
int unescapechar(char *url) {
char *from = url, *to = from;
char hex[3], *hexp=hex; /* contains xx of %xx */
for (;;) {
int c = *from++;
if (c == '+') c = ' ';
if (c == '%') {
*hexp++ = *from++; *hexp++ = *from++; *hexp = '\0';
c = strtol(hex, NULL, 16); hexp = hex;
}
*to++ = c;
if (c == '\0') return;
}
}
int getpairs(char ***name, char ***value)
{
int cl; /* content length */
int i, l1, l2, num=1;
char *qs, *clientinput, *token;
char **nam, **val;
if (!strcmp("POST", getenv("REQUEST_METHOD"))) {
/* POST */
if ((cl = atoi(getenv("CONTENT_LENGTH"))) == 0) return 0;
if ((clientinput = (char *) malloc(sizeof(char) * (cl+1))) == NULL) return -2;
fgets(clientinput, cl+1, stdin); /* get the client input */
} else {
/* GET */
if ((qs = getenv("QUERY_STRING")) == NULL) return 0; else {
cl = strlen(qs);
if ((clientinput = (char *) malloc(sizeof(char) * (cl+1))) == NULL) return -2;
strcpy(clientinput, qs);
}
}
token = strchr(clientinput, '&'); /* & is the name/value pair separator */
while (token != NULL) {token = strchr(++token, '&'); num++;} /* obtain the total number of pairs */
nam = (char **) malloc(sizeof(char*)*num);
val = (char **) malloc(sizeof(char*)*num);
if (nam == NULL || val == NULL) return -2;
for (i = 0, token = strtok(clientinput, "&"); token != NULL; i++) {
l1 = strlen(token); l2 = strcspn(token,"=");
nam[i] = (char *) malloc(sizeof(char) * (l2+1));
if (nam[i] == NULL) return -2;
strncpy(nam[i], token, l2);
nam[i][l2] = '\0';
unescapechar(nam[i]);
if (l1 != l2+1) { /* name=value& */
val[i] = (char *)malloc(sizeof(char) * (l1-l2));
if (val[i] == NULL) return -2;
strcpy(val[i], token+l2+1);
unescapechar(val[i]);
} else val[i] = NULL; /* special case of name=& */
token = strtok(NULL, "&");
}
free(clientinput);
*name = nam; *value = val;
return num; /* return the number of entries */
}
/*********************************************************************
* Dictionary lookup code. See also 'token.c' *
*********************************************************************/
typedef long long NODE;
#define ROOT_NODE 1 /* Root of dag */
#define V_END_OF_WORD 33 /* Bit number of W */
#define M_END_OF_WORD (1LL << V_END_OF_WORD)
#define V_END_OF_NODE 32 /* Bit number of N */
#define M_END_OF_NODE (1LL << V_END_OF_NODE)
#define V_LETTER 24
#define M_LETTER 0xFF
#define M_NODE_POINTER 0xFFFFFFL /* Bit mask for node pointer */
typedef int INDEX;
#define MAX_WORD_LEN 128
INDEX dawg_locate_prefix(NODE *dawg, char *word, INDEX edge)
{
/* Finds the sub-trie in the dictionary whose prefix is word */
for (;;) {
if (*word == (((dawg[edge] >> V_LETTER) & M_LETTER))) {
if (*++word == '\0') {
return(dawg[edge]&M_NODE_POINTER);
} else {
if ((edge = (dawg[edge] & M_NODE_POINTER)) == ROOT_NODE) break;
continue;
}
}
if (((dawg[edge++]) & M_END_OF_NODE) != 0) break;
}
/* What to do when none found? -- fail-safe, or some error code...? */
return(ROOT_NODE);
}
static char *sup(char *s)
{
static char *p, q[128], fancy[128];
sprintf(q, "%s", s);
p = strchr(q, ' ');
if (p == NULL) return(s);
*p++ = '\0';
sprintf(fancy, "%s<sup>%s</sup>", q, p);
return fancy;
}
static char *anchor(char *s, char *alt)
{
static char fancy[128];
if ((alt == NULL) || (strcmp(alt, "1") == 0)) return("");
sprintf(fancy, "#%s_1", alt);
return fancy;
}
static void dawg_pr2(NODE *dawg, INDEX node, int len)
{
static char word[MAX_WORD_LEN];
static int printed1 = 0;
NODE *edge;
for (edge = (NODE *)&dawg[node]; ; edge++) {
long c;
c = *edge; /* Don't rewrite this - its avoiding a MSC bug */
c = c >> V_LETTER;
c = c & M_LETTER;
word[len] = (char)c;
if ((*edge & M_END_OF_WORD) != 0) {
char ws2[MAX_WORD_LEN], *ws, *s, *s2;
word[len+1] = '\0';
s = word;
for (;;) {
if ((s == NULL) || (*s == '\0')) break;
ws = s;
s = strchr(ws, ';');
if (s != NULL) *s++ = '\0';
strcpy(ws2, ws);
s2 = strchr(ws2, ' ');
if (s2 != NULL) *s2++ = '\0';
if (printed1) {
fprintf(stdout, "/ ", sup(ws));
} else {
printed1 = 1;
}
fprintf(stdout, "%s ", sup(ws));
// fprintf(stdout, "<FONT color=green><A HREF=\"http://buscon.rae.es/draeI/SrvltGUIBusUsual?LEMA=%s&origen=RAE&TIPO_BUS=3%s\" target=\"dynamic\">%s</A></FONT> \n", ws2, anchor(ws2, s2), sup(ws));
}
}
c = *edge & M_NODE_POINTER;
if ((*edge & M_NODE_POINTER) != 0)
dawg_pr2 (dawg, c, len + 1);
if ((*edge & M_END_OF_NODE) != 0) break; /* End of node */
}
}
static void dawg_pr(NODE *dawg, INDEX node, int len)
{
static char word[MAX_WORD_LEN];
NODE *edge;
for (edge = (NODE *)&dawg[node]; ; edge++) {
long c;
c = *edge; /* Don't rewrite this - its avoiding a MSC bug */
c = c >> V_LETTER;
c = c & M_LETTER;
word[len] = (char)c;
if ((*edge & M_END_OF_WORD) != 0) {
char ws2[MAX_WORD_LEN], *ws, *s, *s2, *bugfix1, *bugfix2;
word[len+1] = '\0';
s = word;
for (;;) {
if ((s == NULL) || (*s == '\0')) break;
ws = s;
bugfix1 = s = strchr(ws, ';');
if (s != NULL) *s++ = '\0';
strcpy(ws2, ws);
bugfix2 = s2 = strchr(ws2, ' ');
if (s2 != NULL) *s2++ = '\0';
fprintf(stdout, "<FONT color=blue><A HREF=\"http://buscon.rae.es/draeI/SrvltGUIBusUsual?LEMA=%s&origen=RAE&TIPO_BUS=3%s\" target=\"dynamic\">%s</A></FONT> \n", ws2, anchor(ws2, s2), sup(ws));
if (*linkhack != '\0') sprintf(linkhack, "<FONT color=blue><A HREF=\"http://buscon.rae.es/draeI/SrvltGUIBusUsual?LEMA=%s&origen=RAE&TIPO_BUS=3%s\" target=\"dynamic\">%s</A></FONT> \n", ws2, anchor(ws2, s2), sup(ws));
if (bugfix1) {*bugfix1 = ';'; bugfix1 = NULL;}
if (bugfix2) {*bugfix2 = ' '; bugfix2 = NULL;}
}
fprintf(stdout, "<BR>");
}
c = *edge & M_NODE_POINTER;
if ((*edge & M_NODE_POINTER) != 0)
dawg_pr (dawg, c, len + 1);
if ((*edge & M_END_OF_NODE) != 0) break; /* End of node */
}
}
static char *reformat(char *tiles)
{
static char word[32];
char *wordp = word;
for (;;) {
int c = *tiles++;
if (c == '4') c = LATIN_SMALL_LETTER_N_WITH_TILDE;
*wordp = c; if (c == '\0') return word;
if (c == '1') {*wordp++ = 'c'; *wordp = 'h';}
else if (c == '2') {*wordp++ = 'l'; *wordp = 'l';}
else if (c == '3') {*wordp++ = 'r'; *wordp = 'r';}
wordp++;
}
}
static char *global_word_hack = "";
void dawg_print(NODE *dawg, INDEX node)
{
static int printed = 0;
if (printed == 0) {
printed = 1;
if (showroot) {
static char debugging_hack[1024];
INDEX expanded;
// if showroot, use dawg_pr ~word to convert word to list / of / words
fprintf(stdout, "<font color=\"green\">%s: ", GOOD_WORD);
sprintf(debugging_hack, "~%s=", global_word_hack);
expanded = dawg_locate_prefix(_token, debugging_hack, ROOT_NODE);
dawg_pr2(dawg, expanded, 0);
fprintf(stdout, "</font><BR><BR>\nLa palabra proviene de:<BR>");
dawg_pr(dawg, node, 0);
fprintf(stdout, "<BR>");
fprintf(stdout, "Haga clic en la palabra origen si desea ver la definición.<BR>");
} else {
fprintf(stdout, "<font color=\"green\">%s: %s</font><BR><BR>\n", GOOD_WORD, reformat(global_word_hack));
}
}
}
int dawg_checkeq(NODE *dict, unsigned char *word)
{
int ch;
NODE *edge = dict+ROOT_NODE;
if (edge == dict) return(0!=0);
for (;;) {
ch = (int)(((*edge >> V_LETTER) & M_LETTER));
ch = ch&255;
if (ch == '=') {
if (*word == '\0') {
dawg_print(dict, (*edge & M_NODE_POINTER));
return(0==0);
}
}
if (ch == *word) {
word += 1;
if ((edge = dict+(*edge & M_NODE_POINTER)) == dict) break; /* End of dict */
continue; /* edge moved down a level */
}
if (((*edge++) & M_END_OF_NODE) != 0) break; /* End of options */
}
return(0!=0);
}
/* Support for typographical conventions used (see document entitled 'COMMENT') */
static char convert[256]; // canonicalize ISO Latin1
#define GOOD (0==0)
#define BAD (0!=0)
static int standardize(char *inword, char *outword)
{
unsigned int c;
for (;;) {
c = (unsigned int) (*inword++) & 255U;
if (c == '\0') break;
c = convert[c]; // remove accents, convert to lower, leave
// tilde on n.
if (c == '?') return (BAD);
if ((c == 'c') && (convert[(unsigned int) (*inword) & 255U] == 'h')) { // ch
c = '1'; inword++;
} else if ((c == 'l') && (convert[(unsigned int) (*inword) & 255U] == 'l')) { // ll
c = '2'; inword++;
} else if ((c == 'r') && (convert[(unsigned int) (*inword) & 255U] == 'r')) { // rr
c = '3'; inword++;
}
*outword++ = (char) c;
}
*outword = '\0';
return (GOOD);
}
/* Main program works as both command-line (parameterised or interactive) and
web-based (standard cgi mechanism). Portable between unix (linux) and windows (dos) */
int main(int argc, char **argv)
{
static char word[32] = { '\0' };
int i;
for (i = 0; i < 256; i++) convert[i] = '?'; // rejected unless explicitly specified
for (i = 'a'; i <= 'z'; i++) convert[i] = i;
for (i = 'A'; i <= 'Z'; i++) convert[i] = tolower (i);
// K and W not present in Spanish Scrabble
convert['k'] = '?'; convert['w'] = '?';
convert['K'] = '?'; convert['W'] = '?';
// capital tilde N => lower tilde n, encoded here in 7-bit ascii as '4'
// because the dawg code may not be 8-bit clean (signed char problem? - debug later...)
convert[LATIN_CAPITAL_LETTER_N_WITH_TILDE] = '4';
convert[LATIN_SMALL_LETTER_N_WITH_TILDE] = '4';
// remove all accents and convert to lowercase
convert[LATIN_SMALL_LETTER_A_WITH_ACUTE] = 'a';
convert[LATIN_SMALL_LETTER_E_WITH_ACUTE] = 'e';
convert[LATIN_SMALL_LETTER_I_WITH_ACUTE] = 'i';
convert[LATIN_SMALL_LETTER_O_WITH_ACUTE] = 'o';
convert[LATIN_SMALL_LETTER_U_WITH_ACUTE] = 'u';
convert[LATIN_SMALL_LETTER_U_WITH_DIAERESIS] = 'u';
convert[LATIN_SMALL_LETTER_E_WITH_GRAVE] = 'e';
convert[LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX] = 'i';
convert[LATIN_CAPITAL_LETTER_A_WITH_ACUTE] = 'a';
convert[LATIN_CAPITAL_LETTER_E_WITH_ACUTE] = 'e';
convert[LATIN_CAPITAL_LETTER_I_WITH_ACUTE] = 'i';
convert[LATIN_CAPITAL_LETTER_O_WITH_ACUTE] = 'o';
convert[LATIN_CAPITAL_LETTER_U_WITH_ACUTE] = 'u';
convert[LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS] = 'u';
convert[LATIN_CAPITAL_LETTER_E_WITH_GRAVE] = 'e';
convert[LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX] = 'i';
if (argc > 1) {
//fprintf(stdout, "%s %s\n\n", TITLE, Version);
fprintf(stdout, "%s\n\n", TITLE);
if (strcmp(argv[1], "-h") == 0) {
fprintf(stdout, "%s -h\n", PROGNAME);
fprintf(stdout, "%s\n", PROGNAME);
fprintf(stdout, "%s %s\n", PROGNAME, WORD);
fprintf(stdout, "%s %s1 %s2 ...\n", PROGNAME, WORD, WORD);
exit(0);
}
}
if (argc == 1) { // WEB or interactive command line
static char *s, line[32];
char **name, **value;
int c = 0;
if (getenv ("REQUEST_METHOD") != NULL) { /* Invoked from CGI */
int i, pairs = 0;
/* WEB */
*linkhack = '\0';
fprintf(stdout, "Content-type: text/html\r\n");
fprintf(stdout, "\r\n");
fprintf(stdout, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\r\n");
fprintf(stdout, " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n");
fprintf(stdout, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
fprintf(stdout, "<head>\r\n");
fprintf(stdout, "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=iso-8859-1\" />\r\n");
fprintf(stdout, "<title>\r\n");
//fprintf(stdout, "%s %s\r\n", TITLE, Version);
fprintf(stdout, "%s\r\n", TITLE);
fprintf(stdout, "</title>\r\n");
fprintf(stdout, "</head>\r\n");
fprintf(stdout, "<body>\r\n");
//fprintf(stdout, "<h1>%s %s</h1>\r\n", TITLE, Version);
fprintf(stdout, "<h1>%s</h1>\r\n", TITLE);
// display form for user to enter word
fprintf(stdout, "<form action=\"/cgi-bin/%s\" method=\"post\">\r\n", PROGNAME);
fprintf(stdout, "%s: \r\n", ENTER_WORD);
fprintf(stdout, "<input type=\"text\" name=\"%s\" />\r\n", WORD);
fprintf(stdout, "<input type=\"submit\" value=\"%s\" />\r\n", SUBMIT);
fprintf(stdout, "<BR>\r\n");
fprintf(stdout, "<BR>¿Mostrar el origen de la palabra? ");
if (strcmp(getenv("REQUEST_METHOD"), "POST") == 0) pairs = getpairs(&name, &value);
if (pairs > 0) {
for (i = 0; i < pairs; i++) if (strcmp(name[i], "showroot") == 0) {showroot = (*value[i] == 'Y'); break;}
}
fprintf(stdout, "<input type=\"radio\" name=\"showroot\" value=\"Y\"%s> SÍ", showroot ? " checked" : "");
fprintf(stdout, "<input type=\"radio\" name=\"showroot\" value=\"N\"%s> NO<BR>\r\n", showroot ? "" : " checked");
fprintf(stdout, "</form>\r\n");
if (strcmp(getenv("REQUEST_METHOD"), "POST") == 0) {
char *GIVEN_ARG = NULL;
// word supplied, check it
if (pairs > 0) {
// TO DO: conversions into and out of quoted web format; hex entity refs for accented chars
for (i = 0; i < pairs; i++) if (strcmp(name[i], WORD) == 0) {GIVEN_ARG = value[i]; break;}
for (i = 0; i < pairs; i++) if (strcmp(name[i], "showroot") == 0) {showroot = *value[i] == 'Y'; break;}
if ((GIVEN_ARG != NULL) && (!standardize (GIVEN_ARG, word))) {
fprintf(stdout, "<font color=\"red\">%s: %s</font>\n\n", INVALID_ENTRY, GIVEN_ARG);
} else if ((GIVEN_ARG == NULL) || (strlen (word) == 0)) {
fprintf(stdout, "<font color=\"red\">%s</font>\n", NO_WORD);
} else if ((strlen (GIVEN_ARG) > 30) || (strlen (word) < 2) || (strlen (word) > 15)) {
fprintf(stdout, "<font color=\"red\">%s: %s</font>\n", WRONG_SIZE,
(GIVEN_ARG == NULL ? NO_ARG_GIVEN : GIVEN_ARG));
} else {
if (dawg_checkeq(_token, global_word_hack = word)) {
// already printed: fprintf(stdout, "<font color=\"green\">%s: %s</font>\n", GOOD_WORD, reformat(word));
} else {
fprintf(stdout, "<font color=\"red\">%s: %s</font>\n", BAD_WORD, reformat(word));
}
}
for (i = 0; i < pairs; i++) {
if (name[i] != NULL) free(name[i]);
if (value[i] != NULL) free(value[i]);
}
if (name != NULL) free(name);
if (value != NULL) free(value);
} else {
fprintf(stdout, "Form does not seem to include the required field '%s'.\r\n", WORD);
}
}
fprintf(stdout, "</body>\r\n");
fprintf(stdout, "</html>\r\n");
} else {
/* Console/Interactive */
//fprintf(stdout, "%s %s\n\n", TITLE, Version);
fprintf(stdout, "%s\n\n", TITLE);
for (;;) {
fprintf(stderr, "%s: ", ENTER_WORD); fflush(stderr);
s = line; i = 0; *linkhack = '\0';
for (;;) {
int c = fgetc(stdin);
if ((c == ('Z' & 31)) || (c == ('D' & 31)) || ferror(stdin)) c = EOF;
if (c == EOF) {
fprintf(stdout, "\n\n");
exit(0);
}
if (c == '\n') break;
if ((c == '\r') || ((c == ' ') || (c == '\t'))) continue;
// allow 31 so we catch 'words' > 15 like chllrrchllrrchllrrchllrrchllrrx
if (i++ < 31) *s++ = c;
}
*s = '\0'; if (*line == '\0') continue;
fprintf(stdout, "\n");
if (!standardize (line, word)) {
fprintf(stdout, "%s: %s\n\n", INVALID_ENTRY, line);
} else if ((strlen(word) < 2) || (strlen(word) > 15)) {
fprintf(stdout, "%s: %s\n\n", WRONG_SIZE, reformat(word));
} else {
if (dawg_checkeq(_token, global_word_hack = word)) {
// already printed
} else {
fprintf(stdout, "%s: %s\n\n", BAD_WORD, reformat(word));
}
}
fflush(stdout);
if (c == EOF) exit (1);
}
fprintf(stdout, "\n");
}
} else {
/* Console/command-line */
for (i = 1; i < argc; i++) {
if ((strlen (argv[i]) <= 30) && (!standardize (argv[i], word))) {
// bad input (length test is so assignment to 'word' is not exceeded)
fprintf (stdout, "%s: %s\n", INVALID_ENTRY, argv[i]);
} else if ((strlen(argv[i]) > 30) || (strlen(word) < 2) || (strlen(word) > 15)) {
fprintf(stdout, "%s: %s\n", WRONG_SIZE, argv[i]);
} else {
if (dawg_checkeq(_token, global_word_hack = word)) {
// printed already: fprintf(stdout, "%s: %s\n", GOOD_WORD, reformat(word));
// now print root.
} else {
fprintf(stdout, "%s: %s\n", BAD_WORD, reformat(word));
}
}
}
}
exit (0);
}