2007-10-03 22:00:00 +02:00
|
|
|
|
//=======================================================================
|
|
|
|
|
// Copyright XashXT Group 2007 <20>
|
|
|
|
|
// qcc_utils.c - qcc common tools
|
|
|
|
|
//=======================================================================
|
|
|
|
|
|
2008-06-04 22:00:00 +02:00
|
|
|
|
#include "vprogs.h"
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
2007-10-04 22:00:00 +02:00
|
|
|
|
void Hash_InitTable(hashtable_t *table, int numbucks)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
table->numbuckets = numbucks;
|
2007-10-04 22:00:00 +02:00
|
|
|
|
table->bucket = (bucket_t **)Qalloc(BytesForBuckets(numbucks));
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint Hash_Key(char *name, int modulus)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
//FIXME: optimize.
|
|
|
|
|
uint key;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
for (key = 0; *name; name++)
|
|
|
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
return (key%modulus);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *Hash_Get(hashtable_t *table, char *name)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = Hash_Key(name, table->numbuckets);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
bucket_t *buck;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
while(buck)
|
|
|
|
|
{
|
|
|
|
|
if (!STRCMP(name, buck->keystring))
|
|
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *Hash_GetKey(hashtable_t *table, int key)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = key%table->numbuckets;
|
2008-06-04 22:00:00 +02:00
|
|
|
|
bucket_t *buck;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
while(buck)
|
|
|
|
|
{
|
|
|
|
|
if ((int)buck->keystring == key)
|
|
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *Hash_GetNext(hashtable_t *table, char *name, void *old)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = Hash_Key(name, table->numbuckets);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
bucket_t *buck;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
while(buck)
|
|
|
|
|
{
|
|
|
|
|
if (!STRCMP(name, buck->keystring))
|
|
|
|
|
{
|
|
|
|
|
if (buck->data == old)//found the old one
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
if (!buck) return NULL;
|
|
|
|
|
|
|
|
|
|
buck = buck->next;//don't return old
|
|
|
|
|
while(buck)
|
|
|
|
|
{
|
|
|
|
|
if (!STRCMP(name, buck->keystring))
|
|
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *Hash_Add(hashtable_t *table, char *name, void *data, bucket_t *buck)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = Hash_Key(name, table->numbuckets);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck->data = data;
|
|
|
|
|
buck->keystring = name;
|
|
|
|
|
buck->next = table->bucket[bucknum];
|
|
|
|
|
table->bucket[bucknum] = buck;
|
|
|
|
|
|
|
|
|
|
return buck;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *Hash_AddKey(hashtable_t *table, int key, void *data, bucket_t *buck)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = key%table->numbuckets;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck->data = data;
|
|
|
|
|
buck->keystring = (char*)key;
|
|
|
|
|
buck->next = table->bucket[bucknum];
|
|
|
|
|
table->bucket[bucknum] = buck;
|
|
|
|
|
|
|
|
|
|
return buck;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Hash_Remove(hashtable_t *table, char *name)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = Hash_Key(name, table->numbuckets);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
bucket_t *buck;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
if (!STRCMP(name, buck->keystring))
|
|
|
|
|
{
|
|
|
|
|
table->bucket[bucknum] = buck->next;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while(buck->next)
|
|
|
|
|
{
|
|
|
|
|
if (!STRCMP(name, buck->next->keystring))
|
|
|
|
|
{
|
|
|
|
|
buck->next = buck->next->next;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Hash_RemoveData(hashtable_t *table, char *name, void *data)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = Hash_Key(name, table->numbuckets);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
bucket_t *buck;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
if (buck->data == data)
|
|
|
|
|
{
|
|
|
|
|
if (!STRCMP(name, buck->keystring))
|
|
|
|
|
{
|
|
|
|
|
table->bucket[bucknum] = buck->next;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while(buck->next)
|
|
|
|
|
{
|
|
|
|
|
if (buck->next->data == data)
|
|
|
|
|
{
|
|
|
|
|
if (!STRCMP(name, buck->next->keystring))
|
|
|
|
|
{
|
|
|
|
|
buck->next = buck->next->next;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Hash_RemoveKey(hashtable_t *table, int key)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
uint bucknum = key%table->numbuckets;
|
2008-06-04 22:00:00 +02:00
|
|
|
|
bucket_t *buck;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
if ((int)buck->keystring == key)
|
|
|
|
|
{
|
|
|
|
|
table->bucket[bucknum] = buck->next;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while(buck->next)
|
|
|
|
|
{
|
|
|
|
|
if ((int)buck->next->keystring == key)
|
|
|
|
|
{
|
|
|
|
|
buck->next = buck->next->next;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
buck = buck->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
PR_decode
|
|
|
|
|
================
|
|
|
|
|
*/
|
2007-10-08 22:00:00 +02:00
|
|
|
|
int PR_decode(int complen, int len, int method, char *src, char **dst)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
int i;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
char *buffer = *dst;
|
|
|
|
|
|
|
|
|
|
switch(method)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
case CMPW_COPY:
|
2007-10-03 22:00:00 +02:00
|
|
|
|
if (complen != len)
|
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
MsgDev(D_WARN, "PR_decode: complen[%d] != len[%d]\n", complen, len);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Mem_Copy(buffer, src, len);
|
|
|
|
|
break;
|
|
|
|
|
case CMPW_ENCRYPT:
|
|
|
|
|
if (complen != len)
|
|
|
|
|
{
|
|
|
|
|
MsgDev(D_WARN, "PR_decode: complen[%d] != len[%d]\n", complen, len);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2007-10-08 22:00:00 +02:00
|
|
|
|
for (i = 0; i < len; i++) buffer[i] = src[i] ^ 0xA5;
|
|
|
|
|
break;
|
|
|
|
|
case CMPW_DEFLATE:
|
2007-11-11 22:00:00 +01:00
|
|
|
|
VFS_Unpack( src, complen, dst, len );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
MsgDev(D_WARN, "PR_decode: invalid method\n");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
return false;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
}
|
2007-10-03 22:00:00 +02:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
PR_encode
|
|
|
|
|
================
|
|
|
|
|
*/
|
2007-11-20 22:00:00 +01:00
|
|
|
|
int PR_encode(int len, int method, char *src, file_t *h)
|
2007-10-08 22:00:00 +02:00
|
|
|
|
{
|
2007-11-20 22:00:00 +01:00
|
|
|
|
int i, pos;
|
|
|
|
|
vfile_t *vf;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
switch(method)
|
|
|
|
|
{
|
|
|
|
|
case CMPW_COPY:
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_Write(h, src, len);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
return len;
|
|
|
|
|
case CMPW_ENCRYPT:
|
|
|
|
|
for (i = 0; i < len; i++) src[i] = src[i] ^ 0xA5;
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_Write(h, src, len);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
return len;
|
|
|
|
|
case CMPW_DEFLATE:
|
2007-11-20 22:00:00 +01:00
|
|
|
|
vf = VFS_Open( h, "wz" );
|
|
|
|
|
pos = FS_Tell(h); // member ofs
|
|
|
|
|
VFS_Write( vf, src, len );
|
|
|
|
|
VFS_Close( vf );
|
|
|
|
|
return FS_Tell(h) - pos;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
default:
|
|
|
|
|
MsgDev(D_WARN, "PR_encode: invalid method\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-03 22:00:00 +02:00
|
|
|
|
// CopyString returns an offset from the string heap
|
|
|
|
|
int PR_CopyString (char *str, bool noduplicate )
|
|
|
|
|
{
|
|
|
|
|
int old;
|
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
if (noduplicate)
|
|
|
|
|
{
|
|
|
|
|
if (!str || !*str) return 0;
|
|
|
|
|
for (s = strings; s < strings + strofs; s++)
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if (!com.strcmp(s, str)) return s - strings;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
old = strofs;
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.strcpy (strings + strofs, str);
|
|
|
|
|
strofs += com.strlen(str)+1;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
return old;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
PR_WriteSourceFiles
|
|
|
|
|
|
|
|
|
|
include sources into progs.dat for fake decompile
|
|
|
|
|
if it needs
|
|
|
|
|
================
|
|
|
|
|
*/
|
2007-11-20 22:00:00 +01:00
|
|
|
|
int PR_WriteSourceFiles(file_t *h, dprograms_t *progs, bool sourceaswell)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2008-07-23 22:00:00 +02:00
|
|
|
|
dsource_t *idf;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
cachedsourcefile_t *f;
|
|
|
|
|
int num = 0;
|
|
|
|
|
int ofs;
|
|
|
|
|
|
|
|
|
|
for (f = sourcefile, num = 0; f; f = f->next)
|
|
|
|
|
{
|
|
|
|
|
if (f->type == FT_CODE && !sourceaswell)
|
|
|
|
|
continue;
|
|
|
|
|
num++;
|
|
|
|
|
}
|
|
|
|
|
if (!num) return 0;
|
|
|
|
|
|
2008-07-23 22:00:00 +02:00
|
|
|
|
idf = Qalloc(sizeof(dsource_t) * num);
|
2008-07-18 22:00:00 +02:00
|
|
|
|
for( f = sourcefile, num = 0; f; f = f->next )
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2008-07-18 22:00:00 +02:00
|
|
|
|
if( f->type == FT_CODE && !sourceaswell )
|
2007-10-03 22:00:00 +02:00
|
|
|
|
continue;
|
2008-07-18 22:00:00 +02:00
|
|
|
|
com.strcpy( idf[num].filename, f->filename );
|
2007-10-03 22:00:00 +02:00
|
|
|
|
idf[num].size = f->size;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
idf[num].compmethod = CMPW_DEFLATE;
|
2007-11-20 22:00:00 +01:00
|
|
|
|
idf[num].ofs = FS_Tell(h);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
idf[num].compsize = PR_encode(f->size, idf[num].compmethod, f->file, h);
|
|
|
|
|
num++;
|
|
|
|
|
}
|
2007-11-20 22:00:00 +01:00
|
|
|
|
ofs = FS_Tell(h);
|
2008-07-18 22:00:00 +02:00
|
|
|
|
FS_Write( h, &num, sizeof(int));
|
2008-07-23 22:00:00 +02:00
|
|
|
|
FS_Write( h, idf, sizeof(dsource_t) * num );
|
2007-10-03 22:00:00 +02:00
|
|
|
|
sourcefile = NULL;
|
|
|
|
|
|
|
|
|
|
return ofs;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
int PR_WriteBodylessFuncs (file_t *handle)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
def_t *d;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
for (d = pr.def_head.next; d; d = d->next)
|
|
|
|
|
{
|
|
|
|
|
// function parms are ok
|
|
|
|
|
if (d->type->type == ev_function && !d->scope)
|
|
|
|
|
{
|
|
|
|
|
if (d->initialized != 1 && d->references > 0)
|
|
|
|
|
{
|
2008-06-04 22:00:00 +02:00
|
|
|
|
FS_Write(handle, d->name, com.strlen(d->name)+1);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
ret++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
====================
|
|
|
|
|
AddBuffer
|
|
|
|
|
|
|
|
|
|
copy string into buffer and process crc
|
|
|
|
|
====================
|
|
|
|
|
*/
|
|
|
|
|
#define NEED_CRC 1 // calcaulate crc
|
|
|
|
|
#define NEED_CPY 2 // copy string
|
|
|
|
|
#define NEED_ALL NEED_CRC|NEED_CPY
|
|
|
|
|
|
|
|
|
|
#define ADD1(p) AddBuffer(p, &crc, file, NEED_ALL)
|
|
|
|
|
#define ADD2(p) AddBuffer(p, &crc, file, NEED_CPY)
|
|
|
|
|
#define ADD3(p) AddBuffer(p, &crc, file, NEED_CRC)
|
|
|
|
|
|
|
|
|
|
_inline void AddBuffer(char *p, word *crc, char *file, byte flags )
|
|
|
|
|
{
|
|
|
|
|
char *s;
|
2008-06-04 22:00:00 +02:00
|
|
|
|
int i = com.strlen(file);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if (i + com.strlen(p) + 1 >= PROGDEFS_MAX_SIZE)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for(s = p; *s; s++, i++)
|
|
|
|
|
{
|
|
|
|
|
if(flags & NEED_CRC) CRC_ProcessByte(crc, *s);
|
|
|
|
|
if(flags & NEED_CPY) file[i] = *s;
|
|
|
|
|
}
|
|
|
|
|
if(flags & NEED_CPY) file[i] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
====================
|
|
|
|
|
PR_WriteProgdefs
|
|
|
|
|
|
|
|
|
|
write advanced progdefs.h into disk
|
|
|
|
|
====================
|
|
|
|
|
*/
|
2008-07-19 22:00:00 +02:00
|
|
|
|
word PR_WriteProgdefs( char *filename )
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
char file[PROGDEFS_MAX_SIZE];
|
|
|
|
|
char header_name[MAX_QPATH];
|
|
|
|
|
def_t *d;
|
2007-10-04 22:00:00 +02:00
|
|
|
|
int f = 0, k = 1;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
word crc;
|
|
|
|
|
|
|
|
|
|
CRC_Init (&crc);
|
|
|
|
|
memset(file, 0, PROGDEFS_MAX_SIZE);
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_FileBase( progsoutname, header_name );
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.strupr( header_name, header_name ); // as part of define name
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
ADD2("\n// progdefs.h\n// generated by Xash3D QuakeC compiler\n\n#ifndef PROGDEFS_H\n#define PROGDEFS_H\n");
|
|
|
|
|
ADD3("\n/* file generated by qcc, do not modify */\n"); // this comment as part of crc
|
|
|
|
|
ADD1("\ntypedef struct");
|
|
|
|
|
ADD2(" globalvars_s");
|
|
|
|
|
ADD1(va("\n{"));
|
|
|
|
|
ADD2(va("\n"));
|
|
|
|
|
ADD1(va("\tint\tpad[%i];\n", RESERVED_OFS));
|
|
|
|
|
|
|
|
|
|
// write globalvars_t
|
|
|
|
|
for (d = pr.def_head.next; d; d = d->next)
|
|
|
|
|
{
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if (!com.strcmp (d->name, "end_sys_globals")) break;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
if (d->ofs < RESERVED_OFS) continue;
|
|
|
|
|
|
|
|
|
|
switch (d->type->type)
|
|
|
|
|
{
|
|
|
|
|
case ev_float:
|
|
|
|
|
ADD1(va("\tfloat\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_vector:
|
|
|
|
|
ADD1(va("\tvec3_t\t%s;\n",d->name));
|
|
|
|
|
d = d->next->next->next; // skip the elements
|
|
|
|
|
break;
|
|
|
|
|
case ev_string:
|
|
|
|
|
ADD1(va("\tstring_t\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_function:
|
|
|
|
|
ADD1(va("\tfunc_t\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_entity:
|
|
|
|
|
ADD1(va("\tint\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_integer:
|
|
|
|
|
ADD1(va("\tint\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ADD1(va("\tint\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ADD1("} globalvars_t;\n\n");
|
|
|
|
|
|
|
|
|
|
// write entvars_t
|
|
|
|
|
ADD1("typedef struct");
|
|
|
|
|
ADD2(" entvars_s");
|
|
|
|
|
ADD1("\n{\n");
|
|
|
|
|
|
|
|
|
|
for (d = pr.def_head.next; d; d = d->next)
|
|
|
|
|
{
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if (!com.strcmp (d->name, "end_sys_fields")) break;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
if (d->type->type != ev_field) continue;
|
|
|
|
|
|
|
|
|
|
switch (d->type->aux_type->type)
|
|
|
|
|
{
|
|
|
|
|
case ev_float:
|
|
|
|
|
ADD1(va("\tfloat\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_vector:
|
|
|
|
|
ADD1(va("\tvec3_t\t%s;\n",d->name));
|
|
|
|
|
d = d->next->next->next; // skip the elements
|
|
|
|
|
break;
|
|
|
|
|
case ev_string:
|
|
|
|
|
ADD1(va("\tstring_t\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_function:
|
|
|
|
|
ADD1(va("\tfunc_t\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_entity:
|
|
|
|
|
ADD1(va("\tint\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_integer:
|
|
|
|
|
ADD1(va("\tint\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ADD1(va("\tint\t%s;\n",d->name));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ADD1("} entvars_t;\n\n");
|
|
|
|
|
|
2007-11-23 22:00:00 +01:00
|
|
|
|
// begin custom fields
|
|
|
|
|
ADD2("\n#define REQFIELDS (sizeof(reqfields) / sizeof(fields_t))\n");
|
|
|
|
|
ADD2("\nstatic fields_t reqfields[] = \n{\n");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// write fields
|
|
|
|
|
for (d = pr.def_head.next; d; d = d->next)
|
|
|
|
|
{
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if (!com.strcmp (d->name, "end_sys_fields")) k = 0;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
if (d->type->type != ev_field) continue;
|
2007-10-04 22:00:00 +02:00
|
|
|
|
if (k) continue; //write only user fields
|
2007-10-03 22:00:00 +02:00
|
|
|
|
if (f) ADD2(",\n");
|
|
|
|
|
f = 1;
|
|
|
|
|
|
|
|
|
|
switch (d->type->aux_type->type)
|
|
|
|
|
{
|
|
|
|
|
case ev_float:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_vector:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
d = d->next->next->next; // skip the elements
|
|
|
|
|
break;
|
|
|
|
|
case ev_string:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_function:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_entity:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
break;
|
|
|
|
|
case ev_integer:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ADD2(va("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ADD2("\n};\n\n");
|
|
|
|
|
|
2007-10-05 22:00:00 +02:00
|
|
|
|
switch(target_version)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2007-10-05 22:00:00 +02:00
|
|
|
|
case QPROGS_VERSION:
|
2007-10-03 22:00:00 +02:00
|
|
|
|
ADD2(va("#define PROGHEADER_CRC %i\n", crc ));
|
|
|
|
|
break;
|
2007-10-05 22:00:00 +02:00
|
|
|
|
case FPROGS_VERSION:
|
|
|
|
|
case VPROGS_VERSION:
|
2007-10-03 22:00:00 +02:00
|
|
|
|
ADD2(va("#define PROG_CRC_%s\t%i\n", header_name, crc ));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ADD2("\n#endif//PROGDEFS_H");
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( ForcedCRC ) crc = ForcedCRC;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if (FS_CheckParm("-progdefs"))
|
|
|
|
|
{
|
|
|
|
|
PR_Message("writing %s\n", filename);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
FS_WriteFile(filename, file, com.strlen(file));
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( host_instance == HOST_NORMAL || host_instance == HOST_DEDICATED )
|
|
|
|
|
{
|
|
|
|
|
char *path = progsoutname;
|
|
|
|
|
string current;
|
|
|
|
|
|
|
|
|
|
com.strncpy( current, progsoutname, MAX_STRING );
|
|
|
|
|
if((path = strstr( current, ".." ))) path += 3; // skip ../
|
|
|
|
|
|
|
|
|
|
// make sure what progs file will be placed into right directory
|
|
|
|
|
com.snprintf( progsoutname, MAX_SYSPATH, "%s/%s", GI->vprogs_dir, path );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch( crc )
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
case 54730:
|
2007-10-08 22:00:00 +02:00
|
|
|
|
PR_Message("QuakeWorld unmodified qwprogs.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "qwprogs.dat");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
break;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
case 32401:
|
|
|
|
|
PR_Message("Tenebrae unmodified progs.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "progs.dat");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
break;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
case 5927:
|
|
|
|
|
PR_Message("Quake1 unmodified progs.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "progs.dat");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
break;
|
2008-07-18 22:00:00 +02:00
|
|
|
|
case 1320:
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_Message("Xash3D unmodified server.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "server.dat");
|
2008-01-28 22:00:00 +01:00
|
|
|
|
break;
|
2008-07-18 22:00:00 +02:00
|
|
|
|
case 9488:
|
2008-05-23 22:00:00 +02:00
|
|
|
|
PR_Message("Xash3D unmodified client.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "client.dat");
|
2008-05-23 22:00:00 +02:00
|
|
|
|
break;
|
2008-07-18 22:00:00 +02:00
|
|
|
|
case 2460:
|
2008-01-28 22:00:00 +01:00
|
|
|
|
PR_Message("Xash3D unmodified uimenu.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "uimenu.dat");
|
2007-11-20 22:00:00 +01:00
|
|
|
|
break;
|
|
|
|
|
case 12923:
|
|
|
|
|
PR_Message("Blank progs.dat\n");
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "blank.dat");
|
2007-11-20 22:00:00 +01:00
|
|
|
|
break;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
default:
|
2007-10-17 22:00:00 +02:00
|
|
|
|
PR_Message("Custom progs crc %d\n", crc );
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "progs.dat");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return crc;
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
void PR_WriteLNOfile(char *destname)
|
|
|
|
|
{
|
|
|
|
|
dlno_t lno;
|
2007-11-18 22:00:00 +01:00
|
|
|
|
file_t *f;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
char filename[MAX_QPATH];
|
|
|
|
|
|
|
|
|
|
if(!opt_writelinenums) return;
|
|
|
|
|
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.strncpy( filename, destname, MAX_QPATH );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
FS_StripExtension( filename );
|
|
|
|
|
FS_DefaultExtension( filename, ".lno" );
|
|
|
|
|
|
|
|
|
|
lno.header = LINENUMSHEADER;
|
|
|
|
|
lno.version = LNNUMS_VERSION;
|
|
|
|
|
lno.numglobaldefs = numglobaldefs;
|
|
|
|
|
lno.numglobals = numpr_globals;
|
|
|
|
|
lno.numfielddefs = numfielddefs;
|
|
|
|
|
lno.numstatements = numstatements;
|
|
|
|
|
|
2007-11-18 22:00:00 +01:00
|
|
|
|
f = FS_Open( filename, "w" );
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( !f ) PR_ParseError( ERR_INTERNAL, "Couldn't open file %s", filename );
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_Write(f, &lno, sizeof(dlno_t)); // header
|
|
|
|
|
FS_Write(f, statement_linenums, numstatements * sizeof(int));
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
MsgDev(D_INFO, "Writing %s, total size %d bytes\n", filename, ((FS_Tell(f)+3) & ~3));
|
2007-11-18 22:00:00 +01:00
|
|
|
|
FS_Close( f );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PR_WriteDAT( void )
|
|
|
|
|
{
|
|
|
|
|
ddef_t *dd;
|
2007-11-18 22:00:00 +01:00
|
|
|
|
file_t *f;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
dprograms_t progs; // header
|
|
|
|
|
char element[MAX_NAME];
|
|
|
|
|
int i, progsize, num_ref;
|
|
|
|
|
int crc, outputsize = 16;
|
|
|
|
|
def_t *def, *comp_x, *comp_y, *comp_z;
|
|
|
|
|
|
|
|
|
|
crc = PR_WriteProgdefs ("progdefs.h"); // write progdefs.h
|
|
|
|
|
|
|
|
|
|
progs.blockscompressed = 0;
|
|
|
|
|
|
2007-11-25 22:00:00 +01:00
|
|
|
|
if(numstatements > MAX_STATEMENTS) PR_ParseError(ERR_INTERNAL, "Too many statements - %i\n", numstatements );
|
|
|
|
|
if(strofs > MAX_STRINGS) PR_ParseError(ERR_INTERNAL, "Too many strings - %i\n", strofs );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
PR_UnmarshalLocals();
|
|
|
|
|
|
|
|
|
|
switch (target_version)
|
|
|
|
|
{
|
|
|
|
|
case QPROGS_VERSION:
|
|
|
|
|
if (bodylessfuncs) PR_Message("warning: There are some functions without bodies.\n");
|
|
|
|
|
if( numpr_globals <= 65530 )
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; pr_optimisations[i].enabled; i++)
|
|
|
|
|
{
|
|
|
|
|
if(*pr_optimisations[i].enabled && pr_optimisations[i].flags & FLAG_V7_ONLY)
|
|
|
|
|
*pr_optimisations[i].enabled = false; // uncompatiable
|
|
|
|
|
}
|
|
|
|
|
// not much of a different format. Rewrite output to get it working on original executors?
|
|
|
|
|
if (numpr_globals >= 32768)
|
|
|
|
|
PR_Warning(WARN_IMAGETOOBIG, NULL, 0, "globals limit exceeds 32768, image may not run\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
target_version = FPROGS_VERSION;
|
|
|
|
|
outputsize = 32;
|
|
|
|
|
PR_Message("force target to version %d[%dbit]\n", target_version, outputsize );
|
|
|
|
|
}
|
|
|
|
|
// intentional falltrough
|
|
|
|
|
case FPROGS_VERSION:
|
|
|
|
|
if (numpr_globals > 65530) outputsize = 32;
|
|
|
|
|
if(opt_compstrings) progs.blockscompressed |= COMP_STRINGS;
|
|
|
|
|
if(opt_compfunctions)
|
|
|
|
|
{
|
|
|
|
|
progs.blockscompressed |= COMP_FUNCTIONS;
|
|
|
|
|
progs.blockscompressed |= COMP_STATEMENTS;
|
|
|
|
|
}
|
|
|
|
|
if(opt_compress_other)
|
|
|
|
|
{
|
|
|
|
|
progs.blockscompressed |= COMP_DEFS;
|
|
|
|
|
progs.blockscompressed |= COMP_FIELDS;
|
|
|
|
|
progs.blockscompressed |= COMP_GLOBALS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// compression of blocks?
|
|
|
|
|
if (opt_writelinenums) progs.blockscompressed |= COMP_LINENUMS;
|
|
|
|
|
if (opt_writetypes) progs.blockscompressed |= COMP_TYPES;
|
|
|
|
|
break;
|
|
|
|
|
case VPROGS_VERSION:
|
|
|
|
|
outputsize = 32; //as default
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// part of how compilation works. This def is always present, and never used.
|
|
|
|
|
def = PR_GetDef(NULL, "end_sys_globals", NULL, false, 0);
|
|
|
|
|
if(def) def->references++;
|
|
|
|
|
|
|
|
|
|
def = PR_GetDef(NULL, "end_sys_fields", NULL, false, 0);
|
|
|
|
|
if(def) def->references++;
|
|
|
|
|
|
|
|
|
|
for (def = pr.def_head.next; def; def = def->next)
|
|
|
|
|
{
|
|
|
|
|
if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector))
|
|
|
|
|
{
|
|
|
|
|
// do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.sprintf(element, "%s_x", def->name);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
comp_x = PR_GetDef(NULL, element, def->scope, false, 0);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.sprintf(element, "%s_y", def->name);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
comp_y = PR_GetDef(NULL, element, def->scope, false, 0);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.sprintf(element, "%s_z", def->name);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
comp_z = PR_GetDef(NULL, element, def->scope, false, 0);
|
|
|
|
|
|
|
|
|
|
num_ref = def->references;
|
|
|
|
|
if (comp_x && comp_y && comp_z)
|
|
|
|
|
{
|
|
|
|
|
num_ref += comp_x->references;
|
|
|
|
|
num_ref += comp_y->references;
|
|
|
|
|
num_ref += comp_z->references;
|
|
|
|
|
|
|
|
|
|
if (!def->references)
|
|
|
|
|
{
|
|
|
|
|
if (!comp_x->references || !comp_y->references || !comp_z->references)
|
|
|
|
|
num_ref = 0; // one of these vars is useless...
|
|
|
|
|
}
|
|
|
|
|
def->references = num_ref;
|
|
|
|
|
|
|
|
|
|
if (!num_ref) num_ref = 1;
|
|
|
|
|
if (comp_x) comp_x->references = num_ref;
|
|
|
|
|
if (comp_y) comp_y->references = num_ref;
|
|
|
|
|
if (comp_z) comp_z->references = num_ref;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (def->references <= 0)
|
|
|
|
|
{
|
|
|
|
|
if(def->local) PR_Warning(WARN_NOTREFERENCED, strings + def->s_file, def->s_line, "'%s' : unreferenced local variable", def->name);
|
|
|
|
|
if (opt_unreferenced && def->type->type != ev_field) continue;
|
|
|
|
|
}
|
|
|
|
|
if (def->type->type == ev_function)
|
|
|
|
|
{
|
|
|
|
|
if (opt_function_names && functions[G_FUNCTION(def->ofs)].first_statement<0)
|
|
|
|
|
{
|
|
|
|
|
def->name = "";
|
|
|
|
|
}
|
|
|
|
|
if (!def->timescalled)
|
|
|
|
|
{
|
|
|
|
|
if (def->references <= 1)
|
|
|
|
|
PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called or referenced (spawn function or dead code)", def->name);
|
|
|
|
|
}
|
|
|
|
|
if (opt_stripfunctions && def->timescalled >= def->references-1)
|
|
|
|
|
{
|
|
|
|
|
// make sure it's not copied into a different var.
|
|
|
|
|
// if it ever does self.think then it could be needed for saves.
|
|
|
|
|
// if it's only ever called explicitly, the engine doesn't need to know.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (def->type->type == ev_field)
|
|
|
|
|
{
|
|
|
|
|
dd = &fields[numfielddefs];
|
|
|
|
|
dd->type = def->type->aux_type->type;
|
|
|
|
|
dd->s_name = PR_CopyString (def->name, opt_noduplicatestrings );
|
|
|
|
|
dd->ofs = G_INT(def->ofs);
|
|
|
|
|
numfielddefs++;
|
|
|
|
|
}
|
|
|
|
|
else if ((def->scope||def->constant) && (def->type->type != ev_string || opt_constant_names_strings))
|
|
|
|
|
{
|
|
|
|
|
if (opt_constant_names) continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dd = &qcc_globals[numglobaldefs];
|
|
|
|
|
numglobaldefs++;
|
|
|
|
|
|
|
|
|
|
if (opt_writetypes) dd->type = def->type-qcc_typeinfo;
|
|
|
|
|
else dd->type = def->type->type;
|
|
|
|
|
|
|
|
|
|
if ( def->saved && ((!def->initialized || def->type->type == ev_function) && def->type->type != ev_field && def->scope == NULL))
|
|
|
|
|
dd->type |= DEF_SAVEGLOBAL;
|
|
|
|
|
|
|
|
|
|
if (def->shared) dd->type |= DEF_SHARED;
|
|
|
|
|
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if (opt_locals && (def->scope || !com.strcmp(def->name, "IMMEDIATE")))
|
2007-10-08 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
dd->s_name = 0;
|
|
|
|
|
}
|
|
|
|
|
else dd->s_name = PR_CopyString (def->name, opt_noduplicatestrings );
|
|
|
|
|
dd->ofs = def->ofs;
|
|
|
|
|
}
|
2007-11-25 22:00:00 +01:00
|
|
|
|
if(numglobaldefs > MAX_GLOBALS) PR_ParseError(ERR_INTERNAL, "Too many globals - %i\n", numglobaldefs );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
strofs = (strofs + 3) & ~3;
|
|
|
|
|
|
|
|
|
|
PR_Message("Linking...\n");
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( host_instance == COMP_QCCLIB )
|
|
|
|
|
{
|
|
|
|
|
// don't flood into engine console
|
|
|
|
|
MsgDev(D_INFO, "%6i strofs (of %i)\n", strofs, MAX_STRINGS);
|
|
|
|
|
MsgDev(D_INFO, "%6i numstatements (of %i)\n", numstatements, MAX_STATEMENTS);
|
|
|
|
|
MsgDev(D_INFO, "%6i numfunctions (of %i)\n", numfunctions, MAX_FUNCTIONS);
|
|
|
|
|
MsgDev(D_INFO, "%6i numglobaldefs (of %i)\n", numglobaldefs, MAX_GLOBALS);
|
|
|
|
|
MsgDev(D_INFO, "%6i numfielddefs (%i unique) (of %i)\n", numfielddefs, pr.size_fields, MAX_FIELDS);
|
|
|
|
|
MsgDev(D_INFO, "%6i numpr_globals (of %i)\n", numpr_globals, MAX_REGS);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-18 22:00:00 +01:00
|
|
|
|
f = FS_Open( progsoutname, "wb" );
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( !f ) PR_ParseError( ERR_INTERNAL, "Couldn't open file %s", progsoutname );
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_Write(f, &progs, sizeof(progs));
|
|
|
|
|
FS_Write(f, "\r\n\r\n", 4);
|
2008-06-04 22:00:00 +02:00
|
|
|
|
FS_Write(f, v_copyright, com.strlen(v_copyright) + 1);
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_Write(f, "\r\n\r\n", 4);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_strings = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numstrings = strofs;
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_strings, strings, strofs, progs.blockscompressed & COMP_STRINGS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_statements = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numstatements = numstatements;
|
|
|
|
|
|
|
|
|
|
switch(outputsize)
|
|
|
|
|
{
|
|
|
|
|
case 32:
|
|
|
|
|
for (i = 0; i < numstatements; i++)
|
|
|
|
|
{
|
|
|
|
|
statements32[i].op = LittleLong(statements32[i].op);
|
|
|
|
|
statements32[i].a = LittleLong(statements32[i].a);
|
|
|
|
|
statements32[i].b = LittleLong(statements32[i].b);
|
|
|
|
|
statements32[i].c = LittleLong(statements32[i].c);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_statements, statements32, progs.numstatements*sizeof(dstatement32_t), progs.blockscompressed & COMP_STATEMENTS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case 16:
|
|
|
|
|
default:
|
|
|
|
|
for (i = 0; i < numstatements; i++) // resize as we go - scaling down
|
|
|
|
|
{
|
|
|
|
|
statements16[i].op = LittleShort((word)statements32[i].op);
|
|
|
|
|
if (statements32[i].a < 0) statements16[i].a = LittleShort((short)statements32[i].a);
|
|
|
|
|
else statements16[i].a = (word)LittleShort((word)statements32[i].a);
|
|
|
|
|
if (statements32[i].b < 0) statements16[i].b = LittleShort((short)statements32[i].b);
|
|
|
|
|
else statements16[i].b = (word)LittleShort((word)statements32[i].b);
|
|
|
|
|
if (statements32[i].c < 0) statements16[i].c = LittleShort((short)statements32[i].c);
|
|
|
|
|
else statements16[i].c = (word)LittleShort((word)statements32[i].c);
|
|
|
|
|
}
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_statements, statements16, progs.numstatements*sizeof(dstatement16_t), progs.blockscompressed & COMP_STATEMENTS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_functions = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numfunctions = numfunctions;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < numfunctions; i++)
|
|
|
|
|
{
|
|
|
|
|
functions[i].first_statement = LittleLong (functions[i].first_statement);
|
|
|
|
|
functions[i].parm_start = LittleLong (functions[i].parm_start);
|
|
|
|
|
functions[i].s_name = LittleLong (functions[i].s_name);
|
|
|
|
|
functions[i].s_file = LittleLong (functions[i].s_file);
|
|
|
|
|
functions[i].numparms = LittleLong ((functions[i].numparms > MAX_PARMS) ? MAX_PARMS : functions[i].numparms);
|
|
|
|
|
functions[i].locals = LittleLong (functions[i].locals);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_functions, functions, progs.numfunctions*sizeof(dfunction_t), progs.blockscompressed & COMP_FUNCTIONS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
switch(outputsize)
|
|
|
|
|
{
|
|
|
|
|
case 32:
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_globaldefs = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numglobaldefs = numglobaldefs;
|
|
|
|
|
for (i = 0; i < numglobaldefs; i++)
|
|
|
|
|
{
|
|
|
|
|
qcc_globals32[i].type = LittleLong(qcc_globals32[i].type);
|
|
|
|
|
qcc_globals32[i].ofs = LittleLong(qcc_globals32[i].ofs);
|
|
|
|
|
qcc_globals32[i].s_name = LittleLong(qcc_globals32[i].s_name);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_globaldefs, qcc_globals32, progs.numglobaldefs*sizeof(ddef32_t), progs.blockscompressed & COMP_DEFS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_fielddefs = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numfielddefs = numfielddefs;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < numfielddefs; i++)
|
|
|
|
|
{
|
|
|
|
|
fields32[i].type = LittleLong(fields32[i].type);
|
|
|
|
|
fields32[i].ofs = LittleLong(fields32[i].ofs);
|
|
|
|
|
fields32[i].s_name = LittleLong(fields32[i].s_name);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_fielddefs, fields32, progs.numfielddefs*sizeof(ddef32_t), progs.blockscompressed & COMP_FIELDS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case 16:
|
|
|
|
|
default:
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_globaldefs = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numglobaldefs = numglobaldefs;
|
|
|
|
|
for (i = 0; i < numglobaldefs; i++)
|
|
|
|
|
{
|
|
|
|
|
qcc_globals16[i].type = (word)LittleShort ((word)qcc_globals32[i].type);
|
|
|
|
|
qcc_globals16[i].ofs = (word)LittleShort ((word)qcc_globals32[i].ofs);
|
|
|
|
|
qcc_globals16[i].s_name = LittleLong(qcc_globals32[i].s_name);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_globaldefs, qcc_globals16, progs.numglobaldefs*sizeof(ddef16_t), progs.blockscompressed & COMP_DEFS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_fielddefs = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numfielddefs = numfielddefs;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < numfielddefs; i++)
|
|
|
|
|
{
|
|
|
|
|
fields16[i].type = (word)LittleShort ((word)fields32[i].type);
|
|
|
|
|
fields16[i].ofs = (word)LittleShort ((word)fields32[i].ofs);
|
|
|
|
|
fields16[i].s_name = LittleLong (fields32[i].s_name);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_fielddefs, fields16, progs.numfielddefs*sizeof(ddef16_t), progs.blockscompressed & COMP_FIELDS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_globals = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numglobals = numpr_globals;
|
|
|
|
|
|
|
|
|
|
for (i = 0; (uint) i < numpr_globals; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_globals, pr_globals, numpr_globals*4, progs.blockscompressed & COMP_GLOBALS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if(opt_writetypes)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < numtypeinfos; i++)
|
|
|
|
|
{
|
|
|
|
|
if (qcc_typeinfo[i].aux_type) qcc_typeinfo[i].aux_type = (type_t*)(qcc_typeinfo[i].aux_type - qcc_typeinfo);
|
|
|
|
|
if (qcc_typeinfo[i].next) qcc_typeinfo[i].next = (type_t*)(qcc_typeinfo[i].next - qcc_typeinfo);
|
|
|
|
|
qcc_typeinfo[i].name = (char *)PR_CopyString(qcc_typeinfo[i].name, true );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
progs.ofsfiles = 0;
|
|
|
|
|
progs.ofslinenums = 0;
|
2007-11-27 22:00:00 +01:00
|
|
|
|
progs.ident = 0;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.ofsbodylessfuncs = 0;
|
|
|
|
|
progs.numbodylessfuncs = 0;
|
|
|
|
|
progs.ofs_types = 0;
|
|
|
|
|
progs.numtypes = 0;
|
|
|
|
|
progs.version = target_version;
|
|
|
|
|
|
|
|
|
|
switch(target_version)
|
|
|
|
|
{
|
|
|
|
|
case QPROGS_VERSION:
|
|
|
|
|
PR_WriteLNOfile( progsoutname );
|
|
|
|
|
break;
|
|
|
|
|
case FPROGS_VERSION:
|
2007-11-27 22:00:00 +01:00
|
|
|
|
if (outputsize == 16) progs.ident = VPROGSHEADER16;
|
|
|
|
|
if (outputsize == 32) progs.ident = VPROGSHEADER32;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofsbodylessfuncs = FS_Tell(f);
|
|
|
|
|
progs.numbodylessfuncs = PR_WriteBodylessFuncs(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if (opt_writelinenums)
|
|
|
|
|
{
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofslinenums = FS_Tell(f);
|
|
|
|
|
PR_WriteBlock(f, progs.ofslinenums, statement_linenums, numstatements*sizeof(int), progs.blockscompressed & COMP_LINENUMS);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else progs.ofslinenums = 0;
|
|
|
|
|
|
|
|
|
|
if (opt_writetypes)
|
|
|
|
|
{
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofs_types = FS_Tell(f);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.numtypes = numtypeinfos;
|
2007-11-20 22:00:00 +01:00
|
|
|
|
PR_WriteBlock(f, progs.ofs_types, qcc_typeinfo, progs.numtypes*sizeof(type_t), progs.blockscompressed & COMP_TYPES);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
progs.ofs_types = 0;
|
|
|
|
|
progs.numtypes = 0;
|
|
|
|
|
}
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progs.ofsfiles = PR_WriteSourceFiles(f, &progs, opt_writesources);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case VPROGS_VERSION:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
progsize = ((FS_Tell(f)+3) & ~3);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
progs.entityfields = pr.size_fields;
|
|
|
|
|
progs.crc = crc;
|
|
|
|
|
|
|
|
|
|
// byte swap the header and write it out
|
|
|
|
|
for (i = 0; i < sizeof(progs)/4; i++)((int *)&progs)[i] = LittleLong (((int *)&progs)[i]);
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_Seek(f, 0, SEEK_SET);
|
|
|
|
|
FS_Write(f, &progs, sizeof(progs));
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( asmfile ) FS_Close(asmfile);
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( host_instance == COMP_QCCLIB )
|
|
|
|
|
MsgDev(D_INFO, "Writing %s, total size %i bytes\n", progsoutname, progsize );
|
|
|
|
|
FS_Close( f );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-10-03 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=======================
|
|
|
|
|
PR_UnmarshalLocals
|
|
|
|
|
|
|
|
|
|
marshalled locals remaps all the functions to use the range MAX_REGS
|
|
|
|
|
onwards for the offset to thier locals.
|
|
|
|
|
this function remaps all the locals back into the function.
|
|
|
|
|
=======================
|
|
|
|
|
*/
|
|
|
|
|
void PR_UnmarshalLocals( void )
|
|
|
|
|
{
|
|
|
|
|
def_t *def;
|
|
|
|
|
uint ofs;
|
|
|
|
|
uint maxo;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
ofs = numpr_globals;
|
|
|
|
|
maxo = ofs;
|
|
|
|
|
|
|
|
|
|
for (def = pr.def_head.next ; def ; def = def->next)
|
|
|
|
|
{
|
|
|
|
|
if (def->ofs >= MAX_REGS) //unmap defs.
|
|
|
|
|
{
|
|
|
|
|
def->ofs = def->ofs + ofs - MAX_REGS;
|
|
|
|
|
if (maxo < def->ofs)
|
|
|
|
|
maxo = def->ofs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < numfunctions; i++)
|
|
|
|
|
{
|
|
|
|
|
if (functions[i].parm_start == MAX_REGS)
|
|
|
|
|
functions[i].parm_start = ofs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PR_RemapOffsets(0, numstatements, MAX_REGS, MAX_REGS + maxo-numpr_globals + 3, ofs);
|
|
|
|
|
|
|
|
|
|
numpr_globals = maxo+3;
|
|
|
|
|
if (numpr_globals > MAX_REGS)
|
2007-10-04 22:00:00 +02:00
|
|
|
|
PR_ParseError(ERR_INTERNAL, "Too many globals are in use to unmarshal all locals");
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
if (maxo-ofs) PR_Message("Total of %i marshalled globals\n", maxo-ofs);
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-19 22:00:00 +02:00
|
|
|
|
byte *PR_LoadFile( char *filename, bool crash, int type )
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2008-07-19 22:00:00 +02:00
|
|
|
|
int length;
|
2007-10-08 22:00:00 +02:00
|
|
|
|
cachedsourcefile_t *newfile;
|
2008-07-19 22:00:00 +02:00
|
|
|
|
string fullname;
|
|
|
|
|
byte *file;
|
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
|
|
// NOTE: in-game we can't use ../pathes, but root directory always
|
|
|
|
|
// ahead over ../pathes, so tranlate path from
|
|
|
|
|
// ../common/svc_user.h to source/common/svc_user.h
|
|
|
|
|
if( host_instance == HOST_NORMAL || host_instance == HOST_DEDICATED )
|
|
|
|
|
{
|
|
|
|
|
if((path = strstr( filename, ".." )))
|
|
|
|
|
{
|
|
|
|
|
path += 2; // skip ..
|
|
|
|
|
com.snprintf( fullname, MAX_STRING, "%s%s", GI->source_dir, path );
|
|
|
|
|
}
|
|
|
|
|
else com.snprintf( fullname, MAX_STRING, "%s/%s/%s", GI->source_dir, sourcedir, filename );
|
|
|
|
|
}
|
|
|
|
|
else com.strncpy( fullname, filename, MAX_STRING );
|
|
|
|
|
|
|
|
|
|
file = FS_LoadFile( fullname, &length );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( !file || !length )
|
2007-10-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-19 22:00:00 +02:00
|
|
|
|
if( crash ) PR_ParseError(ERR_INTERNAL, "Couldn't open file %s", filename);
|
2007-10-17 22:00:00 +02:00
|
|
|
|
else return NULL;
|
|
|
|
|
}
|
2008-07-19 22:00:00 +02:00
|
|
|
|
newfile = (cachedsourcefile_t*)Qalloc(sizeof(cachedsourcefile_t));
|
2007-10-08 22:00:00 +02:00
|
|
|
|
newfile->next = sourcefile;
|
|
|
|
|
sourcefile = newfile; // make chain
|
|
|
|
|
|
2008-07-19 22:00:00 +02:00
|
|
|
|
com.strcpy(sourcefile->filename, fullname );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
sourcefile->file = file;
|
|
|
|
|
sourcefile->type = type;
|
|
|
|
|
sourcefile->size = length;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
return sourcefile->file;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-19 22:00:00 +02:00
|
|
|
|
bool PR_Include( char *filename )
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2007-10-08 22:00:00 +02:00
|
|
|
|
char *newfile;
|
|
|
|
|
char fname[512];
|
|
|
|
|
char *opr_file_p;
|
|
|
|
|
string_t os_file, os_file2;
|
|
|
|
|
int opr_source_line;
|
|
|
|
|
char *ocompilingfile;
|
|
|
|
|
includechunk_t *oldcurrentchunk;
|
|
|
|
|
|
|
|
|
|
ocompilingfile = compilingfile;
|
|
|
|
|
os_file = s_file;
|
|
|
|
|
os_file2 = s_file2;
|
|
|
|
|
opr_source_line = pr_source_line;
|
|
|
|
|
opr_file_p = pr_file_p;
|
|
|
|
|
oldcurrentchunk = currentchunk;
|
|
|
|
|
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.strcpy(fname, filename);
|
2008-07-19 22:00:00 +02:00
|
|
|
|
newfile = QCC_LoadFile( fname, true );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
currentchunk = NULL;
|
|
|
|
|
pr_file_p = newfile;
|
2008-07-19 22:00:00 +02:00
|
|
|
|
PR_CompileFile( newfile, fname );
|
2007-10-08 22:00:00 +02:00
|
|
|
|
currentchunk = oldcurrentchunk;
|
|
|
|
|
|
|
|
|
|
compilingfile = ocompilingfile;
|
|
|
|
|
s_file = os_file;
|
|
|
|
|
s_file2 = os_file2;
|
|
|
|
|
pr_source_line = opr_source_line;
|
|
|
|
|
pr_file_p = opr_file_p;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
2007-10-08 22:00:00 +02:00
|
|
|
|
return true;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-11-20 22:00:00 +01:00
|
|
|
|
void PR_WriteBlock(file_t *f, fs_offset_t pos, const void *data, size_t blocksize, bool compress)
|
2007-10-03 22:00:00 +02:00
|
|
|
|
{
|
2007-11-20 22:00:00 +01:00
|
|
|
|
vfile_t *h;
|
|
|
|
|
int len = 0;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if (compress)
|
|
|
|
|
{
|
2007-11-20 22:00:00 +01:00
|
|
|
|
h = VFS_Open( f, "wz" );
|
|
|
|
|
VFS_Write( h, data, blocksize ); // write into buffer
|
|
|
|
|
FS_Write(f, &len, sizeof(int)); // first four bytes it's a compressed filesize
|
|
|
|
|
f = VFS_Close(h); // deflate, then write into disk
|
|
|
|
|
len = LittleLong(FS_Tell(f) - pos); // calculate complength
|
|
|
|
|
FS_Seek(f, pos, SEEK_SET); // seek back to start block...
|
|
|
|
|
FS_Write(f, &len, sizeof(int)); // ... and write real complength value.
|
|
|
|
|
FS_Seek(f, 0, SEEK_END); // return
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|
2007-11-20 22:00:00 +01:00
|
|
|
|
else FS_Write(f, data, blocksize); // just write data
|
2007-10-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
byte *PR_CreateProgsSRC( void )
|
|
|
|
|
{
|
2007-12-11 22:00:00 +01:00
|
|
|
|
search_t *qc = FS_Search( "*", true );
|
2007-10-17 22:00:00 +02:00
|
|
|
|
const char *datname = "unknown.dat\n"; // outname will be set by PR_WriteProgdefs
|
|
|
|
|
byte *newprogs_src = NULL;
|
|
|
|
|
char headers[2][MAX_QPATH]; // contains filename with struct description
|
2007-12-11 22:00:00 +01:00
|
|
|
|
char searchmask[8][16];
|
|
|
|
|
int i, k, j = 0;
|
|
|
|
|
bool have_entvars = 0;
|
|
|
|
|
bool have_globals = 0;
|
|
|
|
|
|
|
|
|
|
// hard-coded table! don't change!
|
2008-06-04 22:00:00 +02:00
|
|
|
|
com.strcpy(searchmask[0], "qh" ); // quakec header
|
|
|
|
|
com.strcpy(searchmask[1], "h" ); // c-style header
|
|
|
|
|
com.strcpy(searchmask[2], "qc" ); // quakec sources
|
|
|
|
|
com.strcpy(searchmask[3], "c" ); // c-style sources
|
2007-12-11 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if(!qc)
|
2007-10-17 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
PR_ParseError(ERR_INTERNAL, "Couldn't open file progs.src" );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
memset(headers, '/0', 2 * MAX_QPATH);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < qc->numfilenames; i++)
|
|
|
|
|
{
|
2007-12-11 22:00:00 +01:00
|
|
|
|
// search by mask
|
|
|
|
|
for( k = 0; k < 8; k++)
|
2007-10-17 22:00:00 +02:00
|
|
|
|
{
|
2007-12-11 22:00:00 +01:00
|
|
|
|
// skip blank mask
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strlen(searchmask[k])) continue;
|
2007-12-11 22:00:00 +01:00
|
|
|
|
if(!com.stricmp(searchmask[k], FS_FileExtension(qc->filenames[i]))) // validate ext
|
2007-10-17 22:00:00 +02:00
|
|
|
|
{
|
2007-12-11 22:00:00 +01:00
|
|
|
|
if(Com_LoadScript( qc->filenames[i], NULL, 0 ))
|
2007-10-17 22:00:00 +02:00
|
|
|
|
{
|
2007-12-11 22:00:00 +01:00
|
|
|
|
while ( 1 )
|
|
|
|
|
{
|
|
|
|
|
// parse all sources for "end_sys_globals"
|
|
|
|
|
if(!Com_GetToken( true )) break; //EOF
|
|
|
|
|
if(Com_MatchToken( "end_sys_globals" ))
|
|
|
|
|
{
|
|
|
|
|
com.strncpy(headers[0], qc->filenames[i], MAX_QPATH );
|
|
|
|
|
have_globals = true;
|
|
|
|
|
}
|
|
|
|
|
else if(Com_MatchToken( "end_sys_fields" ))
|
|
|
|
|
{
|
|
|
|
|
com.strncpy(headers[1], qc->filenames[i], MAX_QPATH );
|
|
|
|
|
have_entvars = true;
|
|
|
|
|
}
|
|
|
|
|
if(have_globals && have_entvars)
|
|
|
|
|
goto buildnewlist; // end of parsing
|
|
|
|
|
}
|
2007-10-17 22:00:00 +02:00
|
|
|
|
}
|
2007-12-11 22:00:00 +01:00
|
|
|
|
}
|
2007-10-17 22:00:00 +02:00
|
|
|
|
}
|
2007-12-11 22:00:00 +01:00
|
|
|
|
}
|
2007-10-17 22:00:00 +02:00
|
|
|
|
|
2007-12-11 22:00:00 +01:00
|
|
|
|
// globals and locals not declared
|
|
|
|
|
PR_ParseError(ERR_INTERNAL, "Couldn't open file progs.src" );
|
|
|
|
|
return NULL;
|
2007-10-17 22:00:00 +02:00
|
|
|
|
buildnewlist:
|
|
|
|
|
|
2008-06-04 22:00:00 +02:00
|
|
|
|
newprogs_src = Qrealloc(newprogs_src, j + com.strlen(datname) + 1); // outfile name
|
|
|
|
|
Mem_Copy(newprogs_src + j, (char *)datname, com.strlen(datname));
|
|
|
|
|
j += com.strlen(datname) + 1; // null term
|
2007-10-17 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// file contains "sys_globals" and possible "sys_fields"
|
2008-06-04 22:00:00 +02:00
|
|
|
|
newprogs_src = Qrealloc(newprogs_src, j + com.strlen(headers[0]) + 2); // first file
|
|
|
|
|
com.strncat(newprogs_src, va("%s\n", headers[0]), com.strlen(headers[0]) + 1);
|
|
|
|
|
j += com.strlen(headers[0]) + 2; //null term
|
2007-10-17 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if(STRCMP(headers[0], headers[1] ))
|
|
|
|
|
{
|
|
|
|
|
// file contains sys_fields description
|
2008-06-04 22:00:00 +02:00
|
|
|
|
newprogs_src = Qrealloc(newprogs_src, j + com.strlen(headers[1]) + 2); // second file (option)
|
|
|
|
|
com.strncat(newprogs_src, va("%s\n", headers[1]), com.strlen(headers[1]) + 1);
|
|
|
|
|
j += com.strlen(headers[1]) + 2; //null term
|
2007-10-17 22:00:00 +02:00
|
|
|
|
}
|
2007-12-11 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// add headers
|
|
|
|
|
for(i = 0; i < qc->numfilenames; i++)
|
|
|
|
|
{
|
|
|
|
|
for( k = 0; k < 2; k++)
|
|
|
|
|
{
|
|
|
|
|
// skip blank mask
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strlen(searchmask[k])) continue;
|
2007-12-11 22:00:00 +01:00
|
|
|
|
if(!com.stricmp(searchmask[k], FS_FileExtension(qc->filenames[i]))) // validate ext
|
|
|
|
|
{
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(qc->filenames[i], headers[0]) || !com.strcmp(qc->filenames[i], headers[1]))
|
2007-12-11 22:00:00 +01:00
|
|
|
|
break; //we already have it, just skip
|
2008-06-04 22:00:00 +02:00
|
|
|
|
newprogs_src = Qrealloc( newprogs_src, j + com.strlen(qc->filenames[i]) + 2);
|
|
|
|
|
com.strncat(newprogs_src, va("%s\n", qc->filenames[i]), com.strlen(qc->filenames[i]) + 1);
|
|
|
|
|
j += com.strlen(qc->filenames[i]) + 2;
|
2007-12-11 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-17 22:00:00 +02:00
|
|
|
|
// add other sources
|
|
|
|
|
for(i = 0; i < qc->numfilenames; i++)
|
|
|
|
|
{
|
2007-12-11 22:00:00 +01:00
|
|
|
|
for( k = 2; k < 8; k++)
|
|
|
|
|
{
|
|
|
|
|
// skip blank mask
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strlen(searchmask[k])) continue;
|
2007-12-11 22:00:00 +01:00
|
|
|
|
if(!com.stricmp(searchmask[k], FS_FileExtension(qc->filenames[i]))) // validate ext
|
|
|
|
|
{
|
2008-06-04 22:00:00 +02:00
|
|
|
|
if(!com.strcmp(qc->filenames[i], headers[0]) || !com.strcmp(qc->filenames[i], headers[1]))
|
2007-12-11 22:00:00 +01:00
|
|
|
|
break; //we already have it, just skip
|
2008-06-04 22:00:00 +02:00
|
|
|
|
newprogs_src = Qrealloc( newprogs_src, j + com.strlen(qc->filenames[i]) + 2);
|
|
|
|
|
com.strncat(newprogs_src, va("%s\n", qc->filenames[i]), com.strlen(qc->filenames[i]) + 1);
|
|
|
|
|
j += com.strlen(qc->filenames[i]) + 2;
|
2007-12-11 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-10-17 22:00:00 +02:00
|
|
|
|
}
|
2008-01-28 22:00:00 +01:00
|
|
|
|
Mem_Free( qc ); // free search
|
2007-11-20 22:00:00 +01:00
|
|
|
|
FS_WriteFile("progs.src", newprogs_src, j );
|
2007-10-17 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
return newprogs_src;
|
2007-10-03 22:00:00 +02:00
|
|
|
|
}
|