#ifdef RCS
static char rcsid[]="$Id: explain.c,v 1.1.1.1 2000/11/13 02:42:41 holsta Exp $";
#endif
/******************************************************************************
* Internetting Cooperating Programmers
* ----------------------------------------------------------------------------
*
* ____ PROJECT
* | _ \ __ _ _ __ ___ ___ _ __
* | | | |/ _` | '_ \ / __/ _ \ '__|
* | |_| | (_| | | | | (_| __/ |
* |____/ \__,_|_| |_|\___\___|_| the IRC bot
*
* All files in this archive are subject to the GNU General Public License.
*
* $Source: /cvsroot/dancer/dancer/src/explain.c,v $
* $Revision: 1.1.1.1 $
* $Date: 2000/11/13 02:42:41 $
* $Author: holsta $
* $State: Exp $
* $Locker: $
*
* ---------------------------------------------------------------------------
*****************************************************************************/
#include "dancer.h"
#include "trio.h"
#include "strio.h"
#include "explain.h"
#include "list.h"
#include "function.h"
#include <stddef.h> /* offsetof */
#ifndef offsetof
# define offsetof(type, member) ((int)(&((type *)0L)->member))
#endif
extern char expfile[];
extern char *errfrom;
typedef struct Explainstruct {
struct Header h;
char *word;
char *explain;
} itemexplain;
itemexplain *explainHead = NULL;
int numExplains = 0;
/* --- ExplainFind ------------------------------------------------ */
itemexplain *ExplainFind(char *word)
{
itemexplain *e;
snapshot;
for (e = First(explainHead); e; e = Next(e)) {
if (StrEqual(e->word, word))
return e;
}
return NULL;
}
/* --- ExplainAddReal --------------------------------------------- */
itemexplain *ExplainAddReal(char *word, char *explain)
{
itemexplain *e;
snapshot;
e = NewEntry(itemexplain);
if (e) {
e->word = StrDuplicate(word);
if (e->word) {
e->explain = StrDuplicate(explain);
if (e->explain) {
InsertLast(explainHead, e);
numExplains++;
return e;
}
StrFree(e->word);
}
free(e);
}
return NULL;
}
/* --- ExplainAddItem --------------------------------------------- */
void ExplainAddItem(char *line)
{
char words[MIDBUFFER], explain[BIGBUFFER];
char *word;
snapshot;
if (2 == StrScan(line, "%"MIDBUFFERTXT"[^ =]=%"BIGBUFFERTXT"[^\n]",
words, explain)) {
for (word = StrTokenize(words, ","); word; word = StrTokenize(NULL, ",")) {
if (NULL == ExplainFind(word))
if (NULL == ExplainAddReal(word, explain))
return; /* Not enough memory */
}
}
}
/* --- ExplainSort ------------------------------------------------ */
void ExplainSort(void)
{
snapshot;
SortList(explainHead, offsetof(itemexplain, word));
}
/* --- ExplainLoad ------------------------------------------------ */
bool ExplainLoad(char *filename)
{
char line[MAXLINE];
FILE *f;
snapshot;
if ((NULL == explainHead) || (NULL == filename) || (NIL == filename[0]))
return FALSE;
f = fopen(filename, "r");
if (f) {
while (fgets(line, sizeof(line), f)) {
switch (line[0]) {
case '#':
case '\n':
break;
case ' ':
ExplainAddItem(line + 1);
break;
default:
break;
}
}
fclose(f);
ExplainSort();
return TRUE;
}
return FALSE;
}
/* --- FreeExplain ------------------------------------------------ */
void FreeExplain(void *v)
{
itemexplain *e;
snapshot;
e = (itemexplain *)v;
if (e) {
if (e->word)
StrFree(e->word);
if (e->explain)
StrFree(e->explain);
numExplains--;
}
}
/* --- ExplainInit ------------------------------------------------ */
void ExplainInit(void)
{
snapshot;
explainHead = NewList(itemexplain);
ExplainLoad(expfile);
}
/* --- ExplainCleanup --------------------------------------------- */
void ExplainCleanup(void)
{
snapshot;
DeleteList(explainHead, FreeExplain);
}
/* --- ExplainReload ---------------------------------------------- */
void ExplainReload(char *filename)
{
snapshot;
FlushList(explainHead, FreeExplain);
ExplainLoad(filename);
}
/* --- ExplainSave ------------------------------------------------ */
bool ExplainSave(char *filename)
{
char tempfile[MIDBUFFER];
bool ok = TRUE;
itemexplain *e;
FILE *f;
snapshot;
if ((NULL == filename) || (NIL == filename[0]))
return FALSE;
StrFormatMax(tempfile, sizeof(tempfile), "%s~", filename);
f = fopen(tempfile, "w");
if (f) {
if (0 > fprintf(f, "# Dancer explain list version: " VERSIONMSG "\n")) {
ok = FALSE;
}
else {
for (e = First(explainHead); e; e = Next(e)) {
if (0 > fprintf(f, " %s=%s\n", e->word, e->explain)) {
ok = FALSE;
break;
}
}
}
fclose(f);
if (ok)
rename(tempfile, filename);
}
return ok;
}
/* --- ExplainAdd ------------------------------------------------- */
void ExplainAdd(char *from, char *line)
{
char words[BIGBUFFER], explain[BIGBUFFER];
char *word;
char *exists = NULL;
bool changed = FALSE;
snapshot;
if (2 == StrScan(line, "%"BIGBUFFERTXT"[^ =]%*[ =]%"BIGBUFFERTXT"[^\n]",
words, explain)) {
for (word = StrTokenize(words, ","); word; word = StrTokenize(NULL, ",")) {
if (NULL == ExplainFind(word)) {
if (ExplainAddReal(word, explain))
changed = TRUE;
}
else {
if (NULL == exists)
exists = word;
}
}
if (changed) {
ExplainSort();
ExplainSave(expfile);
}
if (exists)
Sendf(from, GetText(msg_already_explained), exists);
else if (changed)
Send(from, GetText(msg_added_explaination));
}
else
CmdSyntax(errfrom, "EXPADD");
}
/* --- ExplainDel ------------------------------------------------- */
void ExplainDel(char *from, char *line)
{
char words[BIGBUFFER];
char *word;
char *first = NULL, *not_exists = NULL;
bool changed = FALSE;
itemexplain *e;
snapshot;
if (1 == StrScan(line, "%"BIGBUFFERTXT"s", words)) {
for (word = StrTokenize(words, ","); word; word = StrTokenize(NULL, ",")) {
e = ExplainFind(word);
if (e) {
if (NULL == first)
first = word;
DeleteEntry(explainHead, e, FreeExplain);
changed = TRUE;
}
else {
if (NULL == not_exists)
not_exists = word;
}
}
if (changed)
ExplainSave(expfile);
if (not_exists)
Sendf(errfrom, GetText(msg_explaination_was_not_found), not_exists);
else if (first)
Sendf(from, GetText(msg_removed_explaination), first);
}
else
CmdSyntax(errfrom, "EXPDEL");
}
/* --- Explain ---------------------------------------------------- */
void Explain(char *from, char *line)
{
extern bool public;
extern itemopt option;
char buffer[MIDBUFFER], match[MIDBUFFER];
bool search;
int matches = 0;
itemexplain *e;
itemexplain *firsthit = NULL;
snapshot;
search = (GetOption(line) && ('S' == toupper(option.copt)));
line = option.newpos;
if (1 == StrScan(line, "%"MIDBUFFERTXT"s", buffer)) {
if (search)
StrFormatMax(match, sizeof(match), "*%s*", buffer);
else
StrCopyMax(match, sizeof(match), buffer);
if (public && StrIndex(match, '*')) {
Send(errfrom, GetText(msg_no_public_wildcards));
}
else {
buffer[0] = (char)0;
for (e = First(explainHead); e; e = Next(e)) {
if (StrMatch(search ? e->explain : e->word, match)) {
if (1 == ++matches)
firsthit = e;
if ((StrLength(buffer) + StrLength(e->word)) >= sizeof(buffer)) {
Send(from, buffer);
buffer[0] = (char)0;
}
StrFormatAppendMax(buffer, sizeof(buffer), "%s ", e->word);
}
}
if (0 == matches)
Send(errfrom, GetText(msg_no_explaination));
else if (1 == matches)
Sendf(from, "'%s' %s", firsthit->word, firsthit->explain);
else if (buffer[0])
Send(from, buffer);
}
}
else
CmdSyntax(errfrom, "EXPLAIN");
}
/* ---------------------------------------------------------------- */
/*
* Explaination keywords. Works a bit like 'man -k'
* Certain explainations can be logically grouped.
*
* Example:
*
* 'ircII' and 'mIRC' may both belong to the group 'client', and
* 'ircII' may also belong to the group 'unix'.
*
* "EXPLAIN -k client" will result in "ircII, mIRC"
* "EXPLAIN -k unix" in "ircII, linux, solaris, sunos"
*
* FindExplainKey() first searches for keywords, if none were found
* it searches the usual words.
*
* Represented as 'word key1 key2=description'. Internal representation
* is word = 'word key key'. Extract 'word' with sscanf("[^= \n]) on
* normal searches.
*/
syntax highlighted by Code2HTML, v. 0.9.1