mirror of
https://github.com/suloku/savegame-manager.git
synced 2026-04-17 10:36:19 -05:00
439 lines
15 KiB
OpenEdge ABL
439 lines
15 KiB
OpenEdge ABL
/***************************************************************************
|
|
keys.i - Key Manipulation Functions
|
|
|
|
-------------------
|
|
begin : Fri Apr 21 2000
|
|
copyright : (C) 2000 by Simon White
|
|
email : s_a_white@email.com
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "inikeys.h"
|
|
|
|
#define INI_EQUALS_ALIGN 10
|
|
|
|
#if defined(HAVE_STRINGS_H)
|
|
# include <strings.h>
|
|
#endif
|
|
|
|
#ifndef HAVE_STRCASECMP
|
|
# define strcasecmp stricmp
|
|
#endif
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : __ini_addKey
|
|
* Parameters : ini - pointer to ini file database. key - key name
|
|
* Returns : Pointer to key.
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Adds a new key to the ini file database and updates the temporary workfile.
|
|
* : A heading operation must be called before this function.
|
|
********************************************************************************************************************
|
|
* Rev | Date | By | Comment
|
|
* ----------------------------------------------------------------------------------------------------------------
|
|
********************************************************************************************************************/
|
|
struct key_tag *__ini_addKey (ini_t *ini, char *key)
|
|
{
|
|
struct key_tag *_key;
|
|
size_t length;
|
|
long pos;
|
|
|
|
// Format heading for storing
|
|
__ini_strtrim (key);
|
|
if (!*key)
|
|
return NULL;
|
|
|
|
// Add new key to work file and read it in
|
|
// using file add
|
|
fseek (ini->ftmp, 0, SEEK_END);
|
|
pos = ftell (ini->ftmp);
|
|
fputs (key, ini->ftmp);
|
|
length = (size_t) (ftell (ini->ftmp) - pos);
|
|
_key = __ini_faddKey (ini, ini->ftmp, pos, length);
|
|
fseek (ini->ftmp, 0, SEEK_END);
|
|
fputc ('=', ini->ftmp);
|
|
if (_key)
|
|
ini->flags |= INI_MODIFIED;
|
|
return _key;
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : __ini_averageLengthKey
|
|
* Parameters : current_h - pointer to current header.
|
|
* Returns : Returns the average key length
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Finds average key length for aligning equals.
|
|
********************************************************************************************************************/
|
|
size_t __ini_averageLengthKey (struct section_tag *current_h)
|
|
{
|
|
#ifdef INI_EQUALS_ALIGN
|
|
size_t equal_pos, equal_max, keylength;
|
|
size_t average = 0, count = 0;
|
|
struct key_tag *current_k;
|
|
|
|
// Rev 1.1 Added - Line up equals characters for keys
|
|
// Calculate Average
|
|
current_k = current_h->first;
|
|
while (current_k)
|
|
{
|
|
count++;
|
|
average += strlen (current_k->key);
|
|
current_k = current_k->pNext;
|
|
}
|
|
|
|
if (!count)
|
|
return 0;
|
|
|
|
average /= count;
|
|
equal_pos = (equal_max = average);
|
|
|
|
#if INI_EQUALS_ALIGN > 0
|
|
// Work out the longest key in that range
|
|
current_k = current_h->first;
|
|
while (current_k)
|
|
{
|
|
keylength = strlen (current_k->key);
|
|
equal_max = average + INI_EQUALS_ALIGN;
|
|
|
|
if ((equal_max > keylength) && (keylength > equal_pos))
|
|
equal_pos = keylength;
|
|
current_k = current_k->pNext;
|
|
}
|
|
#endif // INI_EQUALS_ALIGN > 0
|
|
return equal_pos;
|
|
#else
|
|
return 0;
|
|
#endif // INI_EQUALS_ALIGN
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : __ini_faddKey
|
|
* Parameters : ini - pointer to ini file database, file - ini file to read key from
|
|
* : pos - key position in file, length - key length
|
|
* Returns : Pointer to key.
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Adds a new key to the ini file database from the input file.
|
|
* : A heading operation must be called before this function.
|
|
********************************************************************************************************************
|
|
* Rev | Date | By | Comment
|
|
* ----------------------------------------------------------------------------------------------------------------
|
|
********************************************************************************************************************/
|
|
struct key_tag *__ini_faddKey (ini_t *ini, FILE *file, long pos, size_t length)
|
|
{
|
|
struct key_tag *_key;
|
|
char *str;
|
|
|
|
length++;
|
|
str = (char *) malloc (sizeof(char) * length);
|
|
assert (str);
|
|
fseek (file, pos, SEEK_SET);
|
|
fgets (str, (int) length, file);
|
|
__ini_strtrim (str);
|
|
|
|
_key = __ini_createKey (ini, str);
|
|
if (!_key)
|
|
{ free (str);
|
|
return NULL;
|
|
}
|
|
|
|
_key->pos = pos + (long) length;
|
|
return _key;
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : __ini_createKey
|
|
* Parameters : ini - pointer to ini file database. key - key name
|
|
* Returns : Pointer to key.
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Adds an entry into the key linked list ready for formating by the addKey commands
|
|
* : A heading operation must be called before this function.
|
|
********************************************************************************************************************
|
|
* Rev | Date | By | Comment
|
|
* ----------------------------------------------------------------------------------------------------------------
|
|
********************************************************************************************************************/
|
|
struct key_tag *__ini_createKey (ini_t *ini, char *key)
|
|
{
|
|
struct section_tag *section;
|
|
struct key_tag *pNew;
|
|
long pos;
|
|
|
|
if (!*key)
|
|
return NULL;
|
|
|
|
section = ini->selected;
|
|
pNew = __ini_locateKey (ini, key);
|
|
if (pNew)
|
|
{ // Reset details of existing key
|
|
free (pNew->key);
|
|
pNew->key = key;
|
|
pos = 0;
|
|
}
|
|
else
|
|
{ // Create a new key and add at end;
|
|
pNew = (struct key_tag *) malloc (sizeof (struct key_tag));
|
|
if (!pNew)
|
|
return NULL;
|
|
memset (pNew, 0, sizeof (struct key_tag));
|
|
pNew->key = key;
|
|
|
|
if (!section->first)
|
|
section->first = pNew;
|
|
else
|
|
section->last->pNext = pNew;
|
|
|
|
pNew->pPrev = section->last;
|
|
section->last = pNew;
|
|
section->selected = pNew;
|
|
|
|
#ifdef INI_USE_HASH_TABLE
|
|
{ // Rev 1.3 - Added
|
|
struct key_tag *pOld;
|
|
unsigned long crc32;
|
|
unsigned char accel;
|
|
|
|
crc32 = __ini_createCrc32 (key, (ini->flags & INI_CASE) != 0);
|
|
pNew->crc = crc32;
|
|
// Rev 1.3 - Add accelerator list
|
|
accel = (unsigned char) crc32 & 0x0FF;
|
|
pNew->pPrev_Acc = NULL;
|
|
pOld = section->keys[accel];
|
|
section->keys[accel] = pNew;
|
|
if (pOld) pOld->pPrev_Acc = pNew;
|
|
pNew->pNext_Acc = pOld;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
section->selected = pNew;
|
|
return pNew;
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : __ini_deleteKey
|
|
* Parameters : ini - pointer to ini file database. key - key name
|
|
* Returns :
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Removes a key from the database only.
|
|
* : This change does not occur in the file until ini_close is called.
|
|
* : A heading operation must be called before this function.
|
|
********************************************************************************************************************
|
|
* Rev | Date | By | Comment
|
|
* ----------------------------------------------------------------------------------------------------------------
|
|
********************************************************************************************************************/
|
|
void __ini_deleteKey (ini_t *ini)
|
|
{
|
|
struct key_tag *current_k;
|
|
struct section_tag *section = ini->selected;
|
|
|
|
current_k = section->selected;
|
|
if (current_k)
|
|
{
|
|
// Tidy up all users of this key
|
|
section->selected = NULL;
|
|
if (section->last == current_k)
|
|
section->last = current_k->pPrev;
|
|
|
|
// Check to see if all keys were removed
|
|
if (!current_k->pPrev)
|
|
section->first = current_k->pNext;
|
|
else
|
|
current_k->pPrev->pNext = current_k->pNext;
|
|
if (current_k->pNext)
|
|
current_k->pNext->pPrev = current_k->pPrev;
|
|
|
|
#ifdef INI_USE_HASH_TABLE
|
|
// Rev 1.3 - Take member out of accelerator list
|
|
if (!current_k->pPrev_Acc)
|
|
section->keys[(unsigned char) current_k->crc & 0x0FF] = current_k->pNext_Acc;
|
|
else
|
|
current_k->pPrev_Acc->pNext_Acc = current_k->pNext_Acc;
|
|
if (current_k->pNext_Acc)
|
|
current_k->pNext_Acc->pPrev_Acc = current_k->pPrev_Acc;
|
|
#endif // INI_USE_HASH_TABLE
|
|
|
|
// Delete Key
|
|
free (current_k->key);
|
|
free (current_k);
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : __ini_locateKey
|
|
* Parameters : ini - pointer to ini file database. key - key name
|
|
* Returns : Pointer to key.
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Locates a key entry in the database.
|
|
* : A heading operation must be called before this function.
|
|
********************************************************************************************************************
|
|
* Rev | Date | By | Comment
|
|
* ----------------------------------------------------------------------------------------------------------------
|
|
********************************************************************************************************************/
|
|
struct key_tag *__ini_locateKey (ini_t *ini, const char *key)
|
|
{
|
|
struct key_tag *current_k;
|
|
struct section_tag *section;
|
|
section = ini->selected;
|
|
|
|
#ifdef INI_USE_HASH_TABLE
|
|
{ // Rev 1.3 - Added
|
|
unsigned long crc32;
|
|
crc32 = __ini_createCrc32 (key, (ini->flags & INI_CASE) != 0);
|
|
|
|
// Search for key
|
|
for (current_k = section->keys[(unsigned char) crc32 & 0x0FF]; current_k; current_k = current_k->pNext_Acc)
|
|
{
|
|
if (current_k->crc == crc32)
|
|
{
|
|
if (ini->flags & INI_CASE)
|
|
{
|
|
if (!strcmp (current_k->key, key))
|
|
break;
|
|
}
|
|
else if (!strcasecmp (current_k->key, key))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
{ // Search for key
|
|
for (current_k = section->first; current_k; current_k = current_k->pNext)
|
|
{
|
|
if (ini->flags & INI_CASE)
|
|
{
|
|
if (!strcmp (current_k->key, key))
|
|
break;
|
|
}
|
|
else if (!strcasecmp (current_k->key, key))
|
|
break;
|
|
}
|
|
}
|
|
#endif // INI_USE_HASH_TABLE
|
|
|
|
section->selected = current_k;
|
|
return current_k;
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : (public) ini_deleteKey
|
|
* Parameters : ini - pointer to ini file database. heading - heading name. key - key name.
|
|
* Returns : -1 for Error and 0 on success
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description : Equivalent Microsoft write string API call where data set to NULL
|
|
********************************************************************************************************************/
|
|
int INI_LINKAGE ini_deleteKey (ini_fd_t fd)
|
|
{
|
|
ini_t *ini = (ini_t *) fd;
|
|
if (!ini->selected || !ini->selected->selected)
|
|
return -1;
|
|
// Can't delete a temporary key
|
|
if (ini->selected->selected == &(ini->tmpKey))
|
|
return -1;
|
|
// Is file read only?
|
|
if (ini->mode == INI_READ)
|
|
return -1;
|
|
__ini_deleteKey (ini);
|
|
ini->flags |= INI_MODIFIED;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : (public) ini_locateKey
|
|
* Parameters : fd - pointer to ini file descriptor
|
|
* Returns : -1 for Error and 0 on success
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description :
|
|
********************************************************************************************************************/
|
|
int INI_LINKAGE ini_locateKey (ini_fd_t fd, const char *key)
|
|
{
|
|
ini_t *ini = (ini_t *) fd;
|
|
struct key_tag *_key = NULL;
|
|
|
|
if (!key)
|
|
return -1;
|
|
if (!ini->selected)
|
|
return -1;
|
|
|
|
// Can't search for a key in a temporary heading
|
|
if (ini->selected != &(ini->tmpSection))
|
|
_key = __ini_locateKey (ini, key);
|
|
|
|
#ifdef INI_ADD_LIST_SUPPORT
|
|
// Rev 1.1 - Remove buffered list
|
|
if (ini->list)
|
|
{
|
|
free (ini->list);
|
|
ini->list = NULL;
|
|
}
|
|
#endif // INI_ADD_LIST_SUPPORT
|
|
|
|
if (_key)
|
|
return 0;
|
|
|
|
// Ok no key was found, but maybe the user is wanting to create a
|
|
// new one so create it temporarily and see what actually happens later
|
|
{ // Remove all key
|
|
_key = &(ini->tmpKey);
|
|
if (_key->key)
|
|
free (_key->key);
|
|
|
|
// Add new key
|
|
_key->key = strdup (key);
|
|
if (!_key)
|
|
return -1;
|
|
ini->selected->selected = _key;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************
|
|
* Function : (public) ini_currentKey
|
|
* Parameters : fd - pointer to ini file descriptor
|
|
* Returns : NULL for Error and on success pointer to key
|
|
* Globals Used :
|
|
* Globals Modified :
|
|
* Description :
|
|
********************************************************************************************************************/
|
|
const char * INI_LINKAGE ini_currentKey (ini_fd_t fd)
|
|
{
|
|
ini_t *ini = (ini_t *) fd;
|
|
struct section_tag *section;
|
|
struct key_tag *key;
|
|
|
|
if (!ini)
|
|
return NULL;
|
|
section = ini->selected;
|
|
if (!section)
|
|
return NULL;
|
|
key = section->selected;
|
|
if (!key)
|
|
return NULL;
|
|
return key->key;
|
|
}
|