mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-24 05:11:42 +00:00
317d3bddb8
a GNUstep port of the original Quake editor for NeXTstep, QuakeEd.app.
579 lines
8.2 KiB
Objective-C
579 lines
8.2 KiB
Objective-C
|
|
#import "qedefs.h"
|
|
|
|
@implementation Dict
|
|
|
|
- init
|
|
{
|
|
[super initCount: 0
|
|
elementSize: sizeof (dict_t)
|
|
description: NULL];
|
|
return self;
|
|
}
|
|
|
|
- print
|
|
{
|
|
int i;
|
|
dict_t *d;
|
|
|
|
for (i=0 ; i<numElements ; i++)
|
|
{
|
|
d = [self elementAt: i];
|
|
printf ("%s : %s\n",d->key, d->value);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
/*
|
|
===========
|
|
copyFromZone
|
|
|
|
JDC
|
|
===========
|
|
*/
|
|
- copyFromZone:(NXZone *)zone
|
|
{
|
|
id new;
|
|
int i;
|
|
dict_t *d;
|
|
char *old;
|
|
|
|
new = [super copyFromZone: zone];
|
|
for (i=0 ; i<numElements ; i++)
|
|
{
|
|
d = [self elementAt: i];
|
|
old = d->key;
|
|
d->key = malloc(strlen(old)+1);
|
|
strcpy (d->key, old);
|
|
|
|
old = d->value;
|
|
d->value = malloc(strlen(old)+1);
|
|
strcpy (d->value, old);
|
|
}
|
|
|
|
return new;
|
|
}
|
|
|
|
- initFromFile:(FILE *)fp
|
|
{
|
|
[self init];
|
|
return [self parseBraceBlock:fp];
|
|
}
|
|
|
|
//===============================================
|
|
//
|
|
// Dictionary pair functions
|
|
//
|
|
//===============================================
|
|
|
|
//
|
|
// Write a { } block out to a FILE*
|
|
//
|
|
- writeBlockTo:(FILE *)fp
|
|
{
|
|
int max;
|
|
int i;
|
|
dict_t *d;
|
|
|
|
fprintf (fp, "{\n");
|
|
max = [super count];
|
|
for (i = 0; i < max; i++) {
|
|
d = [super elementAt: i];
|
|
fprintf (fp, "\t{\"%s\"\t\"%s\"}\n", d->key, d->value);
|
|
}
|
|
fprintf(fp,"}\n");
|
|
|
|
return self;
|
|
}
|
|
|
|
//
|
|
// Write a single { } block out
|
|
//
|
|
- writeFile: (char *) path
|
|
{
|
|
FILE *fp;
|
|
|
|
if (!(fp = fopen(path,"w+t"))) {
|
|
printf ("Error writing %s!\n", path);
|
|
return nil;
|
|
}
|
|
|
|
printf ("Writing dictionary file %s.\n", path);
|
|
fprintf (fp, "// QE_Project file %s\n", path);
|
|
|
|
[self writeBlockTo: fp];
|
|
fclose (fp);
|
|
|
|
return self;
|
|
}
|
|
|
|
//===============================================
|
|
//
|
|
// Utility methods
|
|
//
|
|
//===============================================
|
|
|
|
//
|
|
// Find a keyword in storage
|
|
// Returns * to dict_t, otherwise NULL
|
|
//
|
|
- (dict_t *) findKeyword:(char *)key
|
|
{
|
|
int max;
|
|
int i;
|
|
dict_t *d;
|
|
|
|
max = [super count];
|
|
for (i = 0;i < max;i++)
|
|
{
|
|
d = [super elementAt:i];
|
|
if (!strcmp(d->key,key))
|
|
return d;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Change a keyword's string
|
|
//
|
|
- changeStringFor:(char *)key to:(char *)value
|
|
{
|
|
dict_t *d;
|
|
dict_t newd;
|
|
|
|
d = [self findKeyword:key];
|
|
if (d != NULL)
|
|
{
|
|
free(d->value);
|
|
d->value = malloc(strlen(value)+1);
|
|
strcpy(d->value,value);
|
|
}
|
|
else
|
|
{
|
|
newd.key = malloc(strlen(key)+1);
|
|
strcpy(newd.key,key);
|
|
newd.value = malloc(strlen(value)+1);
|
|
strcpy(newd.value,value);
|
|
[self addElement:&newd];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
//
|
|
// Search for keyword, return the string *
|
|
//
|
|
- (char *)getStringFor:(char *)name
|
|
{
|
|
dict_t *d;
|
|
|
|
d = [self findKeyword:name];
|
|
if (d != NULL)
|
|
return d->value;
|
|
|
|
return "";
|
|
}
|
|
|
|
//
|
|
// Search for keyword, return the value
|
|
//
|
|
- (unsigned int)getValueFor:(char *)name
|
|
{
|
|
dict_t *d;
|
|
|
|
d = [self findKeyword:name];
|
|
if (d != NULL)
|
|
return atol(d->value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Return # of units in keyword's value
|
|
//
|
|
- (int) getValueUnits:(char *)key
|
|
{
|
|
id temp;
|
|
int count;
|
|
|
|
temp = [self parseMultipleFrom:key];
|
|
count = [temp count];
|
|
[temp free];
|
|
|
|
return count;
|
|
}
|
|
|
|
//
|
|
// Convert List to string
|
|
//
|
|
- (char *)convertListToString:(id)list
|
|
{
|
|
int i;
|
|
int max;
|
|
char tempstr[4096];
|
|
char *s;
|
|
char *newstr;
|
|
|
|
max = [list count];
|
|
tempstr[0] = 0;
|
|
for (i = 0;i < max;i++)
|
|
{
|
|
s = [list elementAt:i];
|
|
strcat(tempstr,s);
|
|
strcat(tempstr," ");
|
|
}
|
|
newstr = malloc(strlen(tempstr)+1);
|
|
strcpy(newstr,tempstr);
|
|
|
|
return newstr;
|
|
}
|
|
|
|
//
|
|
// JDC: I wrote this to simplify removing vectors
|
|
//
|
|
- removeKeyword:(char *)key
|
|
{
|
|
dict_t *d;
|
|
|
|
d = [self findKeyword:key];
|
|
if (d == NULL)
|
|
return self;
|
|
[self removeElementAt:d - (dict_t*)dataPtr];
|
|
return self;
|
|
}
|
|
|
|
//
|
|
// Delete string from keyword's value
|
|
//
|
|
- delString:(char *)string fromValue:(char *)key
|
|
{
|
|
id temp;
|
|
int count;
|
|
int i;
|
|
char *s;
|
|
dict_t *d;
|
|
|
|
d = [self findKeyword:key];
|
|
if (d == NULL)
|
|
return NULL;
|
|
temp = [self parseMultipleFrom:key];
|
|
count = [temp count];
|
|
for (i = 0;i < count;i++)
|
|
{
|
|
s = [temp elementAt:i];
|
|
if (!strcmp(s,string))
|
|
{
|
|
[temp removeElementAt:i];
|
|
free(d->value);
|
|
d->value = [self convertListToString:temp];
|
|
[temp free];
|
|
|
|
break;
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
//
|
|
// Add string to keyword's value
|
|
//
|
|
- addString:(char *)string toValue:(char *)key
|
|
{
|
|
char *newstr;
|
|
char spacing[] = "\t";
|
|
dict_t *d;
|
|
|
|
d = [self findKeyword:key];
|
|
if (d == NULL)
|
|
return NULL;
|
|
newstr = malloc(strlen(string) + strlen(d->value) + strlen(spacing) + 1);
|
|
strcpy(newstr,d->value);
|
|
strcat(newstr,spacing);
|
|
strcat(newstr,string);
|
|
free(d->value);
|
|
d->value = newstr;
|
|
|
|
return self;
|
|
}
|
|
|
|
//===============================================
|
|
//
|
|
// Use these for multiple parameters in a keyword value
|
|
//
|
|
//===============================================
|
|
char *searchStr;
|
|
char item[4096];
|
|
|
|
- setupMultiple:(char *)value
|
|
{
|
|
searchStr = value;
|
|
return self;
|
|
}
|
|
|
|
- (char *)getNextParameter
|
|
{
|
|
char *s;
|
|
|
|
if (!searchStr)
|
|
return NULL;
|
|
strcpy(item,searchStr);
|
|
s = FindWhitespcInBuffer(item);
|
|
if (!*s)
|
|
searchStr = NULL;
|
|
else
|
|
{
|
|
*s = 0;
|
|
searchStr = FindNonwhitespcInBuffer(s+1);
|
|
}
|
|
return item;
|
|
}
|
|
|
|
//
|
|
// Parses a keyvalue string & returns a Storage full of those items
|
|
//
|
|
- (id) parseMultipleFrom:(char *)key
|
|
{
|
|
#define ITEMSIZE 128
|
|
id stuff;
|
|
char string[ITEMSIZE];
|
|
char *s;
|
|
|
|
s = [self getStringFor:key];
|
|
if (s == NULL)
|
|
return NULL;
|
|
|
|
stuff = [[Storage alloc]
|
|
initCount:0
|
|
elementSize:ITEMSIZE
|
|
description:NULL];
|
|
|
|
[self setupMultiple:s];
|
|
while((s = [self getNextParameter]))
|
|
{
|
|
bzero(string,ITEMSIZE);
|
|
strcpy(string,s);
|
|
[stuff addElement:string];
|
|
}
|
|
|
|
return stuff;
|
|
}
|
|
|
|
//===============================================
|
|
//
|
|
// Dictionary pair parsing
|
|
//
|
|
//===============================================
|
|
|
|
//
|
|
// parse all keyword/value pairs within { } 's
|
|
//
|
|
- (id) parseBraceBlock:(FILE *)fp
|
|
{
|
|
int c;
|
|
dict_t pair;
|
|
char string[1024];
|
|
|
|
c = FindBrace(fp);
|
|
if (c == -1)
|
|
return NULL;
|
|
|
|
while((c = FindBrace(fp)) != '}')
|
|
{
|
|
if (c == -1)
|
|
return NULL;
|
|
// c = FindNonwhitespc(fp);
|
|
// if (c == -1)
|
|
// return NULL;
|
|
// CopyUntilWhitespc(fp,string);
|
|
|
|
// JDC: fixed to allow quoted keys
|
|
c = FindNonwhitespc(fp);
|
|
if (c == -1)
|
|
return NULL;
|
|
c = fgetc(fp);
|
|
if ( c == '\"')
|
|
CopyUntilQuote(fp,string);
|
|
else
|
|
{
|
|
ungetc (c,fp);
|
|
CopyUntilWhitespc(fp,string);
|
|
}
|
|
|
|
pair.key = malloc(strlen(string)+1);
|
|
strcpy(pair.key,string);
|
|
|
|
c = FindQuote(fp);
|
|
CopyUntilQuote(fp,string);
|
|
pair.value = malloc(strlen(string)+1);
|
|
strcpy(pair.value,string);
|
|
|
|
[super addElement:&pair];
|
|
c = FindBrace(fp);
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
//===============================================
|
|
//
|
|
// C routines for string parsing
|
|
//
|
|
//===============================================
|
|
int GetNextChar(FILE *fp)
|
|
{
|
|
int c;
|
|
int c2;
|
|
|
|
c = getc(fp);
|
|
if (c == EOF)
|
|
return -1;
|
|
if (c == '/') // parse comments
|
|
{
|
|
c2 = getc(fp);
|
|
if (c2 == '/')
|
|
{
|
|
while((c2 = getc(fp)) != '\n');
|
|
c = getc(fp);
|
|
}
|
|
else
|
|
ungetc(c2,fp);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
void CopyUntilWhitespc(FILE *fp,char *buffer)
|
|
{
|
|
int count = 800;
|
|
int c;
|
|
|
|
while(count--)
|
|
{
|
|
c = GetNextChar(fp);
|
|
if (c == EOF)
|
|
return;
|
|
if (c <= ' ')
|
|
{
|
|
*buffer = 0;
|
|
return;
|
|
}
|
|
*buffer++ = c;
|
|
}
|
|
}
|
|
|
|
void CopyUntilQuote(FILE *fp,char *buffer)
|
|
{
|
|
int count = 800;
|
|
int c;
|
|
|
|
while(count--)
|
|
{
|
|
c = GetNextChar(fp);
|
|
if (c == EOF)
|
|
return;
|
|
if (c == '\"')
|
|
{
|
|
*buffer = 0;
|
|
return;
|
|
}
|
|
*buffer++ = c;
|
|
}
|
|
}
|
|
|
|
int FindBrace(FILE *fp)
|
|
{
|
|
int count = 800;
|
|
int c;
|
|
|
|
while(count--)
|
|
{
|
|
c = GetNextChar(fp);
|
|
if (c == EOF)
|
|
return -1;
|
|
if (c == '{' ||
|
|
c == '}')
|
|
return c;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int FindQuote(FILE *fp)
|
|
{
|
|
int count = 800;
|
|
int c;
|
|
|
|
while(count--)
|
|
{
|
|
c = GetNextChar(fp);
|
|
if (c == EOF)
|
|
return -1;
|
|
if (c == '\"')
|
|
return c;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int FindWhitespc(FILE *fp)
|
|
{
|
|
int count = 800;
|
|
int c;
|
|
|
|
while(count--)
|
|
{
|
|
c = GetNextChar(fp);
|
|
if (c == EOF)
|
|
return -1;
|
|
if (c <= ' ')
|
|
{
|
|
ungetc(c,fp);
|
|
return c;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int FindNonwhitespc(FILE *fp)
|
|
{
|
|
int count = 800;
|
|
int c;
|
|
|
|
while(count--)
|
|
{
|
|
c = GetNextChar(fp);
|
|
if (c == EOF)
|
|
return -1;
|
|
if (c > ' ')
|
|
{
|
|
ungetc(c,fp);
|
|
return c;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
char *FindWhitespcInBuffer(char *buffer)
|
|
{
|
|
int count = 1000;
|
|
char *b = buffer;
|
|
|
|
while(count--)
|
|
if (*b <= ' ')
|
|
return b;
|
|
else
|
|
b++;
|
|
return NULL;
|
|
}
|
|
|
|
char *FindNonwhitespcInBuffer(char *buffer)
|
|
{
|
|
int count = 1000;
|
|
char *b = buffer;
|
|
|
|
while(count--)
|
|
if (*b > ' ')
|
|
return b;
|
|
else
|
|
b++;
|
|
return NULL;
|
|
}
|