file_access_updated.txt
来自「quake1 dos源代码最新版本」· 文本 代码 · 共 681 行 · 第 1/2 页
TXT
681 行
================================================================
Title : Tutorial: Implementing the QuakeC file access into the Quake engine
(including new QuakeC string manipulation functions)
Date : 2001-11-01
Filename : FILE_ACCESS_UPDATED.TXT
Author : Ryan "FrikaC" Smith
Matthias "Maddes" Buecher
Email Address : kryten@adelphia.net
maddes@go.to
Homepage : FrikBot
http://www.inside3d.com/frikbot/
Quake Info Pool
http://www.quake-info-pool.net/
Quake Standards Group (short QSG)
http://www.quakesrc.org/
Complexity : Low
================================================================
This is the updated version of FrikaC's file access tutorial. The builtin
function numbers and names have been changed, so they do not interfere with
already used numbers in QuakeWorld and registered functions of Lord Havoc.
Additionally the string functions are now protected against memory leaks and the
file read function can distinguish between an empty line and the end of the
file.
The builtin functions were added to the QSG standard by using the Enhanced
BuiltIn Function System (EBFS). If you want to add these functions to your own
engine, then you should add the EBFS before.
FrikaC's new functions may lead to very very long strings, so we have to avoid
memory leaks. There's also a potentioal memory leak in id's PF_Varstring().
First we define the maximum size (length + 0-byte for EndOfString) of a temp
string at the top of PR_CMDS.C...
#define PR_MAX_TEMPSTRING 2048 // 2001-10-25 Enhanced temp string handling by Maddes
To fix PF_Varstring() place the following definition before it...
char pr_varstring_temp[PR_MAX_TEMPSTRING]; // 2001-10-25 Enhanced temp string handling by Maddes
... and change PF_Varstring to the following ...
char *PF_VarString (int first)
{
int i;
// 2001-10-25 Enhanced temp string handling by Maddes start
int maxlen;
char *add;
pr_varstring_temp[0] = 0;
for (i=first ; i<pr_argc ; i++)
{
maxlen = PR_MAX_TEMPSTRING - strlen(pr_varstring_temp) - 1; // -1 is EndOfString
add = G_STRING((OFS_PARM0+i*3));
if (maxlen > strlen(add))
{
strcat (pr_varstring_temp, add);
}
else
{
strncat (pr_varstring_temp, add, maxlen);
pr_varstring_temp[PR_MAX_TEMPSTRING-1] = 0;
break; // can stop here
}
}
return pr_varstring_temp;
// 2001-10-25 Enhanced temp string handling by Maddes end
}
Change the definition of pr_string_temp before PF_ftos() to ...
char pr_string_temp[PR_MAX_TEMPSTRING]; // 2001-10-25 Enhanced temp string handling by Maddes
Now follows FrikaC's original tutorial, which now incorporates the new function
numbers in conjunction with EBFS and avoids memory leaks in PF_strcat(),
PF_substring() and PF_fgets().
The file read function was also enhanced to distinguish between an empty line
and the end of the file.
With all due respect to Quake Engine Resources, their QuakeC file tutorial
certainly isn't up to par with the rest of their code. While they create awesome
graphics code, not ever being QC Coders they over looked some of the quirks of
QuakeC, and some of their functions simply do not work. At the request of many
in the QuakeC community, I have created the following tutorial which adds
"better" QuakeC file support to the engine. It's a bit more limited than QER's
version, but it's also much simpler to use. (It's output is also human-readable)
In addition, included are functions for string manipulation and handling in
QuakeC. These are needed because all file I/O in this tutorial is done with
strings. Most of these functions can also be used in a wide variety of other
circumstances. Anyway, lets get started. First the engine code, then a little
explanation of how the functions work in QC. Open up pr_cmds.c in your IDE of
choice, and find PF_Fixme near the bottom of the file. Above it, copy and paste
this gigantic function set:
// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes start
/*
=================
PF_strzone
string strzone (string)=================
*/
void PF_strzone (void)
{
char *m, *p;
m = G_STRING(OFS_PARM0);
p = Z_Malloc(strlen(m) + 1);
strcpy(p, m);
G_INT(OFS_RETURN) = p - pr_strings;
}
/*
=================
PF_strunzone
string strunzone (string)=================
*/
void PF_strunzone (void)
{
Z_Free(G_STRING(OFS_PARM0));
G_INT(OFS_PARM0) = OFS_NULL; // empty the def
};
/*
=================
PF_strlen
float strlen (string)=================
*/
void PF_strlen (void)
{
char *p = G_STRING(OFS_PARM0);
G_FLOAT(OFS_RETURN) = strlen(p);
}
/*
=================
PF_strcat
string strcat (string, string)=================
*/
void PF_strcat (void)
{
char *s1, *s2;
int maxlen; // 2001-10-25 Enhanced temp string handling by Maddes
s1 = G_STRING(OFS_PARM0);
s2 = PF_VarString(1);
// 2001-10-25 Enhanced temp string handling by Maddes start
pr_string_temp[0] = 0;
if (strlen(s1) < PR_MAX_TEMPSTRING)
{
strcpy(pr_string_temp, s1);
}
else
{
strncpy(pr_string_temp, s1, PR_MAX_TEMPSTRING);
pr_string_temp[PR_MAX_TEMPSTRING-1] = 0;
}
maxlen = PR_MAX_TEMPSTRING - strlen(pr_string_temp) - 1; // -1 is EndOfString
if (maxlen > 0)
{
if (maxlen > strlen(s2))
{
strcat (pr_string_temp, s2);
}
else
{
strncat (pr_string_temp, s2, maxlen);
pr_string_temp[PR_MAX_TEMPSTRING-1] = 0;
}
}
// 2001-10-25 Enhanced temp string handling by Maddes end
G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
}
/*
=================
PF_substring
string substring (string, float, float)=================
*/
void PF_substring (void)
{
int offset, length;
int maxoffset; // 2001-10-25 Enhanced temp string handling by Maddes
char *p;
p = G_STRING(OFS_PARM0);
offset = (int)G_FLOAT(OFS_PARM1); // for some reason, Quake doesn't like G_INT
length = (int)G_FLOAT(OFS_PARM2);
// cap values
maxoffset = strlen(p);
if (offset > maxoffset)
{
offset = maxoffset;
}
if (offset < 0)
offset = 0;
// 2001-10-25 Enhanced temp string handling by Maddes start
if (length >= PR_MAX_TEMPSTRING)
length = PR_MAX_TEMPSTRING-1;
// 2001-10-25 Enhanced temp string handling by Maddes end
if (length < 0)
length = 0;
p += offset;
strncpy(pr_string_temp, p, length);
pr_string_temp[length]=0;
G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
}
/*
=================
PF_stof
float stof (string)=================
*/
// thanks Zoid, taken from QuakeWorld
void PF_stof (void)
{
char *s;
s = G_STRING(OFS_PARM0);
G_FLOAT(OFS_RETURN) = atof(s);
}
/*
=================
PF_stov
vector stov (string)=================
*/
void PF_stov (void)
{
char *v;
int i;
vec3_t d;
v = G_STRING(OFS_PARM0);
for (i=0; i<3; i++)
{
while(v && (v[0] == ' ' || v[0] == '\'')) //skip unneeded data
v++;
d[i] = atof(v);
while (v && v[0] != ' ') // skip to next space
v++;
}
VectorCopy (d, G_VECTOR(OFS_RETURN));
}
// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes end
// 2001-09-20 QuakeC file access by FrikaC/Maddes start
/*
=================
PF_fopen
float fopen (string,float)=================
*/
void PF_fopen (void)
{
char *p = G_STRING(OFS_PARM0);
char *ftemp;
int fmode = G_FLOAT(OFS_PARM1);
int h = 0, fsize = 0;
switch (fmode)
{
case 0: // read
Sys_FileOpenRead (va("%s/%s",com_gamedir, p), &h);
G_FLOAT(OFS_RETURN) = (float) h;
return;
case 1: // append -- this is nasty
// copy whole file into the zone
fsize = Sys_FileOpenRead(va("%s/%s",com_gamedir, p), &h);
if (h == -1)
{
h = Sys_FileOpenWrite(va("%s/%s",com_gamedir, p));
G_FLOAT(OFS_RETURN) = (float) h;
return;
}
ftemp = Z_Malloc(fsize + 1);
Sys_FileRead(h, ftemp, fsize);
Sys_FileClose(h);
// spit it back out
h = Sys_FileOpenWrite(va("%s/%s",com_gamedir, p));
Sys_FileWrite(h, ftemp, fsize);
Z_Free(ftemp); // free it from memory
G_FLOAT(OFS_RETURN) = (float) h; // return still open handle
return;
default: // write
h = Sys_FileOpenWrite (va("%s/%s", com_gamedir, p));
G_FLOAT(OFS_RETURN) = (float) h;
return;
}
}
/*
=================
PF_fclose
void fclose (float)=================
*/
void PF_fclose (void)
{
int h = (int)G_FLOAT(OFS_PARM0);
Sys_FileClose(h);
}
/*
=================
PF_fgets
string fgets (float)=================
*/
void PF_fgets (void)
{
// reads one line (up to a \n) into a string
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?