Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
303 lines (237 sloc) 6.11 KB
#ifndef com_sleepless_taglist_h
#define com_sleepless_taglist_h
// Copyright 1998-2004 Sleepless Software Inc. All Rights Reserved
/*
Similar to TagArray, except:
This object always takes strings for both tags and vals so you
won't have to do any casting.
This object also lets you read and write tags/vals to/from files.
There is no support for accessing items by index.
This was mainly intended for storing game preferences persistantly,
such as "sound-fx: on/off", etc.
TagList()
TagList(const char *f)
~TagList()
void clear()
void readBuf(const char *inbuf)
const char *get(const char *tag)
int getInt(const char *tag)
bool rem(const char *tag)
void set(const char *tag, const char *val)
void set(const char *tag, int val)
int readFile(const char *path)
int writeFile(const char *path)
*/
#include <stdio.h>
#include "tagarray.cpp"
#include "file.cpp"
#include "assert.cpp"
struct TagList
{
TagArray ta;
TagList()
{
}
TagList(const char *f)
{
readFile(f);
}
~TagList()
{
clear();
}
/* Clears all items from the list */
void clear()
{
while(ta.length() > 0)
rem(ta.getTag(0));
}
/* Reads data from a text buffer.
Input must be one big, null terminated string consisting of one
or more '\n' delimited lines. Each line must be terminated by
'\n', even if there is only one. Each line must contain at least
one space, which separates the initial "tag" at the beginning of
the line, with the value which is everything
after the space, not including the '\n'.
Example:
action add\n
name Bob Jones\n
phone (801) 555 1212\n
blah\n
age 81\n
On return, a call such as get("action") will return "add".
A call such as get("name") will return "Bob Jones".
A call such as getInt("age") will return 81.
A call such as getInt("name") will return 0.
A call such as get("foo") will return "" (empty string, not NULL).
A call such as get("") will return "blah".
Etc.
Note: This method ADDS to the items already on the list. Clear it
first if you don't want the existing items.
*/
void readBuf(const char *inbuf)
{
char *buf = strdup(inbuf);
DASSERT(buf);
char *c = buf;
while(true)
{
char *nl = strchr(c, '\n');
char *sp = strchr(c, ' ');
if(!nl || !sp || (sp > nl))
break;
char *tag = c;
*sp = 0;
char *val = sp + 1;
*nl = 0;
c = nl + 1;
Str::trim(val);
set(tag,val);
}
free(buf);
}
/* Returns val for a tag or null if not found */
const char *get(const char *tag)
{
return (const char *)ta.get(tag);
}
/* Returns val for a tag or "" if not found.
This function always returns a valid char ptr,
however you lose the ability to distinguish between
a non-existant item and an item with a value of "".
*/
const char *getNoNull(const char *tag)
{
const char *v = (const char *)get(tag);
if(!v)
v = "";
return v;
}
/* Returns val as an integer or 0 if tag not found or tag is not
a number */
int getInt(const char *tag)
{
const char *val = get(tag);
if(val)
return atoi(get(tag));
return 0;
}
/* Remove a tag and it's associated val from the list. Returns false
if the tag wasn't found, or true if it was and was removed. */
bool rem(const char *tag)
{
char *t, *v;
int l = ta.length();
for(int i = 0; i < l; i++)
{
t = (char *)ta.getTag(i);
if(strcmp(t, tag) == 0)
{
v = (char *)ta.rem(i);
DASSERT(v);
free(v);
return true;
}
}
return false;
}
/* Assign a value to a tag. Returns true if the value was set. */
void set(const char *tag, const char *val)
{
rem(tag);
char *v;
v = strdup(val);
DASSERT(v);
ta.put(tag, v);
}
/* Sets a pref to an integer value */
void set(const char *tag, int val)
{
char num[20];
sprintf(num, "%d", val);
set(tag, num);
}
/* Reads data from file. Returns 0 on success. Contents of the file
must adhere to the same format readBuf() expects. */
int readFile(const char *path)
{
File file(path);
const char *bytes = (const char *)file.getBytes();
if(bytes)
{
readBuf(bytes);
return 0;
}
return 1;
}
/* Write to file. Returns 0 on success. */
int writeFile(const char *path)
{
FILE *fp = fopen(path, "wb");
if(!fp)
return 1;
int len = ta.length();
for(int i = 0; i < len; i++)
{
const char *tag = ta.getTag(i);
const char *val = (const char *)ta.get(i);
fprintf(fp, "%s %s\n", tag, val);
}
fclose(fp);
return 0;
}
};
#ifdef TAGLIST_TEST
TagList tl;
void dump()
{
int l = tl.ta.length();
printf(" TA -- length() returns %d\n", l);
for(int i = 0; i < l; i++)
{
printf(" %d: tag = '%s' - val = '%s'\n", i, tl.ta.getTag(i), tl.ta.get(i));
}
printf("\n");
}
int main(int argc, char **argv)
{
const char *s1 = "I have\na lovely\nbunch of\ncoco nuts\n";
printf("on start :\n");
dump();
printf("initing to '%s'\n", s1);
tl.readBuf(s1);
dump();
printf("val for tag I is '%s'\n", tl.get("I"));
printf("val for tag A is '%s'\n", tl.get("A"));
printf("val for tag a is '%s'\n", tl.get("a"));
printf("val for tag bunch is '%s'\n", tl.get("bunch"));
printf("val for tag foo is '%s'\n", tl.get("foo"));
printf("int val for tag foo is %d\n", tl.getInt("foo"));
printf("int val for tag bunch is %d\n", tl.getInt("bunch"));
printf("calling set('i', 'fly')\n");
tl.set("i", "fly");
printf("get('i') returns '%s'\n", tl.get("i"));
dump();
printf("calling setInt('i', 777)\n");
tl.set("i", 777);
printf("getInt('i') returns %d\n", tl.getInt("i"));
dump();
printf("get('coco') returns '%s'\n", tl.get("coco"));
printf("calling rem('coco')\n");
tl.rem("coco");
dump();
printf("get('coco') returns '%s'\n", tl.get("coco"));
printf("writing to bar.txt returns %d\n", tl.writeFile("bar.txt"));
printf("clearing\n");
tl.clear();
dump();
printf("get('i') returns '%s'\n", tl.get("i"));
printf("reading back from bar.txt ... returns %d\n", tl.readFile("bar.txt"));
dump();
printf("get('i') returns '%s'\n", tl.get("i"));
printf("val for tag I is '%s'\n", tl.get("I"));
printf("val for tag a is '%s'\n", tl.get("a"));
printf("val for tag bunch is '%s'\n", tl.get("bunch"));
}
#endif
#endif // com_sleepless_taglist_h