/*
* FISG - User- and nick-related datastructure handling
* Programmed and designed by Matti 'ccr' Hamalainen
* (C) Copyright 2003-2004 Tecnic Software productions (TNSP)
*
* Please read file 'COPYING' for information on license and distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "fisg.h"
#include "th_util.h"
#include "th_string.h"
/*
* Userlist handling
*/
/* Allocate new t_user_data structure
*/
t_user_data *user_data_new(void)
{
t_user_data *pData;
/* Allocate the structure */
pData = (t_user_data *) calloc(1, sizeof(t_user_data));
if (!pData) return NULL;
return pData;
}
/* Free t_user_data structure
*/
void user_data_free(t_user_data *pData)
{
t_user_entry *pCurr, *pNext;
if (pData)
{
/* Free linked list */
pCurr = pData->pList;
while (pCurr)
{
pNext = pCurr->pNext;
user_free(pCurr);
pCurr = pNext;
}
/* Free index */
free(pData->ppIndex);
/* Clear structure */
pData->pList = NULL;
pData->ppIndex = NULL;
pData->dirtyN =
pData->dirtyIndex = FALSE;
/* Free structure */
free(pData);
}
}
/* Allocate a new user node
*/
t_user_entry *user_new(char *userHandle)
{
t_user_entry *pResult;
/* Allocate memory for new node */
pResult = (t_user_entry *) calloc(1, sizeof(t_user_entry));
if (!pResult) return NULL;
/* Set fields */
th_strcpy(&pResult->userHandle, userHandle);
return pResult;
}
/* Free user node and data
*/
void user_free(t_user_entry *pUser)
{
assert(pUser);
if (pUser->userHandle) free(pUser->userHandle);
if (pUser->picPath) free(pUser->picPath);
if (pUser->linkURL) free(pUser->linkURL);
if (pUser->sComment) free(pUser->sComment);
free(pUser);
}
/* Insert given node to linked list
*/
void user_insert(t_user_data *pData, t_user_entry *pNode)
{
assert(pData);
assert(pNode);
/* Make dirty */
pData->dirtyN = pData->dirtyIndex = TRUE;
/* Insert node */
if (pData->pList)
{
/* The first node's pPrev points to last node */
LPREV = pData->pList->pPrev; /* New node's prev = Previous last node */
pData->pList->pPrev->pNext = pNode; /* Previous last node's next = New node */
pData->pList->pPrev = pNode; /* New last node = New node */
LNEXT = NULL; /* But next is NULL! */
} else {
pData->pList = pNode; /* First node ... */
LPREV = pNode; /* ... it's also last */
LNEXT = NULL; /* But next is NULL! */
}
}
/* Delete given user node from linked list
*/
void user_delete(t_user_data *pData, t_user_entry *pNode)
{
assert(pData);
assert(pData->pList);
assert(pNode);
/* Make dirty */
pData->dirtyN = pData->dirtyIndex = TRUE;
/* Delete node */
if (LPREV) LPREV->pNext = LNEXT;
if (LNEXT)
LNEXT->pPrev = LPREV;
else
pData->pList->pPrev = LPREV;
LPREV = LNEXT = NULL;
}
/*
* User data structures handling
*/
/* Compare function for qsort() that compares 2 nodes for fTotalScore
*/
int user_data_index_cmp(const void *pNode1, const void *pNode2)
{
t_user_entry *pUser1, *pUser2;
pUser1 = * (t_user_entry **) pNode1;
pUser2 = * (t_user_entry **) pNode2;
if (pUser1->fTotalScore > pUser2->fTotalScore)
return -1;
else
if (pUser1->fTotalScore < pUser2->fTotalScore)
return 1;
else
return 0;
}
/* Create a user index for given t_user_data structure
* from nodes in the linked list.
*/
int user_data_makeindex(t_user_data *pData)
{
t_user_entry *pCurr;
t_ulint i;
assert(pData);
/* Free old index, if it exists */
free(pData->ppIndex);
pData->ppIndex = NULL;
/* Computer number of nodes */
for (pData->n = 0, pCurr = pData->pList; pCurr; pCurr = pCurr->pNext)
pData->n++;
pData->dirtyN = FALSE;
/* Check number of nodes */
if (pData->n == 0) return 0;
/* Allocate memory for index */
pData->ppIndex = (t_user_entry **) malloc(sizeof(t_user_entry *) * pData->n);
if (pData->ppIndex == NULL)
return -1;
/* Copy node-pointers to the index-table */
i = 0;
pCurr = pData->pList;
while (pCurr && (i < pData->n))
{
pData->ppIndex[i++] = pCurr;
pCurr = pCurr->pNext;
}
if (i != pData->n) return -2;
pData->dirtyIndex = FALSE;
return 0;
}
/*
* Nicklist/hash handling
*/
/* Insert given node into the nicklist/hashtable
*/
int nickhash_insert(t_str_hash nickList, t_str_node *pNode)
{
int i;
char *tmpNick;
assert(nickList);
assert(pNode);
assert(pNode->pcStr);
/* Find first non-token character from nick */
tmpNick = pNode->pcStr;
while ((*tmpNick == '*') || (*tmpNick == '?')) tmpNick++;
i = th_tolower(*tmpNick);
/* Check the hash index */
if ((i < 0) && (i >= SET_HASH_MAXINDEX))
return -1;
/* Insert node in the linked list */
if (nickList[i])
{
/* The first node's pPrev points to last node */
pNode->pPrev = nickList[i]->pPrev; /* New node's prev = Previous last node */
nickList[i]->pPrev->pNext = pNode; /* Previous last node's next = New node */
nickList[i]->pPrev = pNode; /* New last node = New node */
pNode->pNext = NULL; /* But next is NULL! */
} else {
nickList[i] = pNode; /* First node */
pNode->pPrev = pNode; /* But also last */
pNode->pNext = NULL; /* But next is NULL! */
}
return 0;
}
/* Check if given nick is in the nicklist
*/
t_str_node *nickhash_search(t_str_hash nickList, char *findNick)
{
t_str_node *pCurr;
int i, j;
BOOL isFound;
assert(nickList);
isFound = FALSE;
pCurr = NULL;
j = 0;
/* Check hash */
while ((!isFound) && (findNick[j]))
{
i = th_tolower(findNick[j]);
if ((i >= 0) && (i < SET_HASH_MAXINDEX))
{
/* Find from linked list */
pCurr = nickList[i];
while (pCurr && (!isFound))
{
if (th_strcasematch(findNick, pCurr->pcStr))
isFound = TRUE;
else
pCurr = pCurr->pNext;
}
}
j++;
}
/* Return result */
if (isFound)
return pCurr;
else
return NULL;
}
/*
* Userfile parser
*/
/* Get a field ending to line-end or colon ':'
*/
void parse_pfield1(char *inLine, char *tmpBuf, size_t bufSize, size_t *linePos)
{
size_t i = 0;
while (inLine[*linePos] && (inLine[*linePos] != ':') && (i < bufSize))
tmpBuf[i++] = inLine[(*linePos)++];
tmpBuf[i++] = 0;
}
/* Get a field ending to line-end, whitespace or colon ':'
*/
void parse_pfield2(char *inLine, char *tmpBuf, size_t bufSize, size_t *linePos)
{
size_t i = 0;
while (inLine[*linePos] && !th_isspace(inLine[*linePos]) && (inLine[*linePos] != ':') && (i < bufSize))
tmpBuf[i++] = inLine[(*linePos)++];
tmpBuf[i++] = 0;
}
/* Get a field ending to line-end or whitespace
*/
void parse_pfield3(char *inLine, char *tmpBuf, size_t bufSize, size_t *linePos)
{
size_t i = 0;
while (inLine[*linePos] && !th_isspace(inLine[*linePos]) && (i < bufSize))
tmpBuf[i++] = inLine[(*linePos)++];
tmpBuf[i++] = 0;
}
/* Parse a given userfile to nick and user information
*/
int parse_userfile(char *userFilename, t_stats *pStats, t_fisgconfig *pCfg)
{
char inLine[SET_MAX_BUF + 1], tmpStr[SET_MAX_BUF + 1];
FILE *inFile;
size_t lineNum, linePos;
t_user_entry *tmpUser = NULL;
t_str_node *tmpNick = NULL;
BOOL isIgnored;
assert(pStats);
/* Get configuration options */
/* Try to open the file */
if ((inFile = fopen(userFilename, "ra")) == NULL)
return -1;
/* Read and parse the data */
lineNum = 0;
while (fgets(inLine, SET_MAX_BUF, inFile) != NULL)
{
linePos = 0;
while (inLine[linePos] && !th_iscrlf(inLine[linePos])) linePos++;
inLine[linePos] = 0;
lineNum++;
linePos = 0;
/* Check if the line is OK and what type it is */
if (inLine[0] && (inLine[linePos] != '#'))
{
/* Check if it's ignored user */
if (inLine[linePos] == '!')
{
linePos++;
isIgnored = TRUE;
} else
isIgnored = FALSE;
/* Get the user handle */
parse_pfield1(inLine, tmpStr, SET_MAX_BUF, &linePos);
/* Check if next field exists */
if (inLine[linePos] != ':')
{
THERR("Error in userfile '%s', line %i - missing fields.\n",
userFilename, lineNum);
} else {
/* Allocate a new user and nick records */
tmpUser = user_new(tmpStr);
tmpUser->isIgnored = isIgnored;
tmpUser->isManaged = TRUE;
user_insert(pStats->usersList, tmpUser);
/* Get alias nicks */
linePos++;
while (inLine[linePos] && (inLine[linePos] != ':'))
{
/* Get one nick */
th_findnext(inLine, &linePos);
parse_pfield2(inLine, tmpStr, SET_MAX_BUF, &linePos);
th_findnext(inLine, &linePos);
/* Add to user */
tmpNick = th_strnode_new(tmpStr, 0, tmpUser);
if (nickhash_insert(pStats->nickList, tmpNick) != 0)
THERR("nickhash_insert() failed, hash: '%s'\n", tmpStr);
}
/* Check if image path is given */
if (inLine[linePos] == ':')
{
/* Get image path */
linePos++;
if (inLine[linePos] != ':')
{
parse_pfield1(inLine, tmpStr, SET_MAX_BUF, &linePos);
if (tmpStr[0])
th_strcpy(&tmpUser->picPath, tmpStr);
}
if (inLine[linePos] == ':')
{
/* Get user URL */
linePos++;
th_findnext(inLine, &linePos);
parse_pfield3(inLine, tmpStr, SET_MAX_BUF, &linePos);
if (tmpStr[0])
th_strcpy(&tmpUser->linkURL, tmpStr);
}
}
}
}
} /* if (fgets()) */
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1