This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/vprogs/pr_utils.c

1224 lines
34 KiB
C
Raw Normal View History

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
}