dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// ispell.cpp - intergrated spell checker 
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with all the licenses *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************
 * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer,       *
 *    Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe.   *
 * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael       *
 *    Chastain, Michael Quan, and Mitchell Tse.                            *
 * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to   *
 *    you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com),         *
 *    Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) *
 * >> Oblivion 1.2 is copyright 1996 Wes Wagner                            *
 **************************************************************************/
#include "include.h"

#ifdef unix
/**************************************************************************/
#include <sys/wait.h>

static FILE *ispell_out;
static int ispell_pid = -1;
static int to[2], from[2];

#define ISPELL_BUF_SIZE 1024

/**************************************************************************/
void ispell_init()
{
    char ignore_buf[1024];

    pipe(to);
    pipe(from);

    ispell_pid = fork();
    if (ispell_pid < 0)
    {
        char *errmsg = NULL;
        sprintf(errmsg, "ispell_init: fork: %s", strerror(errno));
        bug(errmsg);
    }
    else if (ispell_pid == 0)   // child
    {
        int i;
        dup2(to[0], 0);         // this is where we read commands from - make
                                // it stdin 
        close(to[0]);
        close(to[1]);

        dup2(from[1], 1);       // this is where we write stuff to 
        close(from[0]);
        close(from[1]);

        // Close all the other files
        for (i = 2; i < 255; i++)
            close(i);

		logf("starting ispell....");
        execlp("ispell", "ispell", "-a", (char *)
               NULL);
		logf("ispell_init(): error starting ispell.");
		logf("ispell startup error\n");
        exit(1);
    }
    else
    {                           // ok ! 
        close(to[0]);
        close(from[1]);
        ispell_out = fdopen(to[1], "w");
        setbuf(ispell_out, NULL);
        read(from[0], ignore_buf, 1024);

		if(strstr(ignore_buf, "ispell startup error")){
			int status;
			logf("Ispell not started, getting child process result to avoid zombie.");
			wait(&status);
			logf("Status result = %d", status);
		}
    }
}

/**************************************************************************/
void ispell_done()
{
    if (ispell_pid != -1)
    {
        fprintf(ispell_out, "#\n");
        fclose(ispell_out);
        close(from[0]);
        waitpid(ispell_pid, NULL, 0);
        ispell_pid = -1;
    }
}

/**************************************************************************/
char *get_ispell_line(char *word)
{
    static char buf[ISPELL_BUF_SIZE];
    char buf2[MSL];
    int len;

    if (ispell_pid == -1)
        return NULL;

    if (word)
    {
        fprintf(ispell_out, "^%s\n", word);
        fflush(ispell_out);
    }

    len = read(from[0], buf2, ISPELL_BUF_SIZE);
    buf2[len] = '\0';

    // Read up to max 1024 characters here 
    if (sscanf(buf2, "%" Stringify(ISPELL_BUF_SIZE) "[^\n]\n\n", buf) != 1)
        return NULL;

    return buf;
}

/**************************************************************************/
void do_ispell(char_data * ch, char *argument)
{
    char *pc;

    if (ispell_pid <= 0)
    {
        ch->println("ispell is not running.");
        return;
    }

    if (!argument[0] || strchr(argument, ' '))
    {
        ch->println("Invalid input.");
        return;
    }

    if (argument[0] == '+')
    {
        for (pc = argument + 1; *pc; pc++)
            if (!is_alpha(*pc))
            {
                ch->printlnf("'%c' is not a letter.", *pc);
                return;
            }
        fprintf(ispell_out, "*%s\n", argument + 1);
        fflush(ispell_out);
        return;                 // we assume everything is OK.. better be so!
    }

    pc = get_ispell_line(argument);
    if (!pc)
    {
        ch->println("ispell: failed.");
        return;
    }

    switch (pc[0])
    {
        case '*':
        case '+':               /* root */
        case '-':               /* compound */
            ch->println("Correct.");
            break;

        case '&':               /* miss */
            ch->printlnf("Not found. Possible words: %s", strchr(pc, ':') + 1);
            break;

        case '?':               /* guess */
			ch->printlnf("Not found. Possible words: %s", strchr(pc, ':') + 1);
            break;

        case '#':               /* none */
            ch->println("Unable to find anything that matches.");
            break;

        default:
            ch->printlnf("Weird output from ispell: %s", pc);
    }
}

/**************************************************************************/
/*
* Function to add ispell support within an editor
* It takes the string the char is currently editing as it's source,
* and passes it a word at a time to ispell.  A check is kept on
* what words have been checked to prevent repetition of the same
* 'error', mainly useful with proper names etc.
*/
void ispell_string(char_data * ch)
{
    char *result;
    char word[MSL];
    char checked_list[MSL];
    char buf[MSL];
    char *str;
    int i = 0;
    bool errors = false;
    BUFFER *buffer;

    buffer = new_buf();
    strcpy(checked_list, "");

    str = *ch->desc->pString;

	// strip the colour from the string before processing
	// this function uses temp_HSL_workspace to do its thing
	if(!IS_NULLSTR(str)){
		convertColour(str, temp_HSL_workspace, CT_NOCOLOUR, false);
		str=temp_HSL_workspace;
	}

    while (*str != '\0')
    {
        while (*str != ' ' && *str != '\0' && *str != '\n' && *str != '\r')
        {
            word[i++] = *str;

            str++;
        }

        word[i++] = '\0';

        if (!is_exact_name(word, checked_list))
        {
            sprintf(checked_list + str_len(checked_list), "%s ", word);

            result = get_ispell_line(word);

            if (!IS_NULLSTR(result))
            {
                if (result[0] == '&')
                {
                    sprintf(buf, "%s failed - Possible words : %s\r\n",
                            word, strchr(result, ':'));
                    errors = true;
                    add_buf(buffer, buf);
                }

                if (result[0] == '#')
                {
                    sprintf(buf, "%s failed - no similar words found.\r\n", word);
                    errors = true;
                    add_buf(buffer, buf);
                }
            }
        }
        str++;
        i = 0;
    }
    ch->println("");
    if (errors){
        ch->sendpage(buf_string(buffer));
    }else{
        ch->println("No errors found.");
	}

    free_buf(buffer);

    return;
}
/**************************************************************************/
#else
/**************************************************************************/
#include "include.h"
void do_ispell(char_data * ch, char *)
{    
    ch->println("Sorry ispell is available in unix only.");
    return;
}
/**************************************************************************/
#endif