Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15bb99d27d | ||
|
|
7fb21c35ba | ||
|
|
f6a0430a40 | ||
|
|
ab209448d1 |
No files matched your search
+63
-1
@@ -1165,6 +1165,39 @@ void VS_Print(vsbuf_t *buf, const char *data)
|
||||
//
|
||||
// =========================================================================
|
||||
|
||||
#define NAME cvar_map_t
|
||||
#define KEY_TY const char *
|
||||
#define VAL_TY consvar_t *
|
||||
#define HASH_FN FNV1a_HashLowercaseString
|
||||
#define CMPR_FN vt_cmpr_casestring
|
||||
#include "verstable.h"
|
||||
|
||||
#define NAME netvar_map_t
|
||||
#define KEY_TY UINT16
|
||||
#define VAL_TY consvar_t *
|
||||
#define HASH_FN vt_hash_integer
|
||||
#define CMPR_FN vt_cmpr_integer
|
||||
#include "verstable.h"
|
||||
|
||||
static cvar_map_t cvar_map;
|
||||
static netvar_map_t netvar_map;
|
||||
|
||||
CONSTRUCTOR static void CV_InitMap(void)
|
||||
{
|
||||
// ensure the map is initialized
|
||||
cvar_map_t_init(&cvar_map);
|
||||
cvar_map_t_reserve(&cvar_map, 512);
|
||||
|
||||
netvar_map_t_init(&netvar_map);
|
||||
netvar_map_t_reserve(&netvar_map, 256);
|
||||
}
|
||||
|
||||
DESTRUCTOR static void CV_DestroyMap(void)
|
||||
{
|
||||
cvar_map_t_cleanup(&cvar_map);
|
||||
netvar_map_t_cleanup(&netvar_map);
|
||||
}
|
||||
|
||||
static const char *cv_null_string = "";
|
||||
|
||||
/** Searches if a variable has been registered.
|
||||
@@ -1175,11 +1208,17 @@ static const char *cv_null_string = "";
|
||||
*/
|
||||
consvar_t *CV_FindVar(const char *name)
|
||||
{
|
||||
consvar_t *cvar;
|
||||
cvar_map_t_itr it = cvar_map_t_get(&cvar_map, name);
|
||||
if (!cvar_map_t_is_end(it))
|
||||
return it.data->val;
|
||||
|
||||
// fallback linear search
|
||||
/*
|
||||
consvar_t *cvar;
|
||||
for (cvar = consvar_vars; cvar; cvar = cvar->next)
|
||||
if (fasticmp(name, cvar->name))
|
||||
return cvar;
|
||||
*/
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1213,11 +1252,17 @@ static inline UINT16 CV_ComputeNetid(const char *s)
|
||||
*/
|
||||
static consvar_t *CV_FindNetVar(UINT16 netid)
|
||||
{
|
||||
netvar_map_t_itr it = netvar_map_t_get(&netvar_map, netid);
|
||||
if (!netvar_map_t_is_end(it))
|
||||
return it.data->val;
|
||||
|
||||
/*
|
||||
consvar_t *cvar;
|
||||
|
||||
for (cvar = consvar_vars; cvar; cvar = cvar->next)
|
||||
if (cvar->netid == netid)
|
||||
return cvar;
|
||||
*/
|
||||
|
||||
if (netid == 44542) // ouch this hack
|
||||
return &cv_karteliminatelast;
|
||||
@@ -1283,6 +1328,11 @@ void CV_RegisterVar(consvar_t *variable)
|
||||
|
||||
// the SetValue will set this bit
|
||||
variable->flags &= ~CV_MODIFIED;
|
||||
|
||||
cvar_map_t_insert(&cvar_map, variable->name, variable);
|
||||
|
||||
if (variable->flags & CV_NETVAR)
|
||||
netvar_map_t_insert(&netvar_map, variable->netid, variable);
|
||||
}
|
||||
|
||||
/** Finds the string value of a console variable.
|
||||
@@ -1588,9 +1638,21 @@ size_t CV_LoadNetVars(const UINT8 *bufstart)
|
||||
// prevent "invalid command received"
|
||||
serverloading = true;
|
||||
|
||||
// we can use our netvar map instead of going through all cvars each time
|
||||
netvar_map_t_itr it;
|
||||
for (it = netvar_map_t_first(&netvar_map);
|
||||
!netvar_map_t_is_end(it);
|
||||
it = netvar_map_t_next(it))
|
||||
{
|
||||
cvar = it.data->val;
|
||||
Setvalue(cvar, cvar->defaultvalue, true);
|
||||
}
|
||||
|
||||
/*
|
||||
for (cvar = consvar_vars; cvar; cvar = cvar->next)
|
||||
if (cvar->flags & CV_NETVAR)
|
||||
Setvalue(cvar, cvar->defaultvalue, true);
|
||||
*/
|
||||
|
||||
count = READUINT16(p);
|
||||
while (count--)
|
||||
|
||||
@@ -1384,7 +1384,6 @@ static void I_Fork(void)
|
||||
|
||||
INT32 I_StartupSystem(void)
|
||||
{
|
||||
W_Startup();
|
||||
I_StartupConsole();
|
||||
#ifdef NEWSIGNALHANDLER
|
||||
// This is useful when debugging. It lets GDB attach to
|
||||
|
||||
@@ -573,6 +573,13 @@ INT32 I_GetKey(void);
|
||||
// NOTE: you WILL have nasal troubles if the variable is not initialized
|
||||
#define CLEANUP(f) __attribute__((__cleanup__(f)))
|
||||
|
||||
// the GNU constructor and destructor attributes
|
||||
// The constructor attribute causes the function to be called automatically before execution enters main ().
|
||||
// Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called.
|
||||
// Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.
|
||||
#define CONSTRUCTOR __attribute__((constructor, used))
|
||||
#define DESTRUCTOR __attribute__((destructor, used))
|
||||
|
||||
// An assert-type mechanism.
|
||||
#ifdef PARANOIA
|
||||
#define I_Assert(e) ((e) ? (void)0 : I_Error("assert failed: %s, file %s, line %d", #e, __FILE__, __LINE__))
|
||||
|
||||
+531
-2408
File diff suppressed because it is too large.
Load diff
@@ -110,7 +110,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
poly_t *planepoly; // the generated convex polygon
|
||||
} poly_subsector_t;
|
||||
} extrasubsector_t;
|
||||
|
||||
// Vanilla features
|
||||
//#define USE_MODEL_NEXTFRAME
|
||||
|
||||
@@ -52,12 +52,12 @@ void HWR_ObjectLightLevelPost(gl_vissprite_t *spr, const sector_t *sector, INT32
|
||||
// --------
|
||||
// hw_bsp.c
|
||||
// --------
|
||||
extern poly_subsector_t *poly_subsectors;
|
||||
extern extrasubsector_t *extrasubsectors;
|
||||
#ifdef PARANOIA
|
||||
extern size_t num_poly_subsector;
|
||||
extern size_t addsubsector;
|
||||
#endif
|
||||
void HWR_InitPolyPool(void);
|
||||
void HWR_FreePolyPool(void);
|
||||
|
||||
void HWR_FreeExtraSubsectors(void);
|
||||
|
||||
// --------
|
||||
// hw_cache.c
|
||||
|
||||
+16
-31
@@ -125,7 +125,7 @@ ps_metric_t ps_hw_batchdrawtime = {};
|
||||
static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, boolean noencore, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor, FBITFIELD polyflags);
|
||||
static void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap);
|
||||
|
||||
static void HWR_AddTransparentFloor(lumpnum_t lumpnum, poly_subsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
|
||||
static void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
|
||||
static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, boolean noencore, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap);
|
||||
static void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
|
||||
|
||||
@@ -231,17 +231,6 @@ consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL|CV_SAVE, gl
|
||||
|
||||
consvar_t cv_glsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_glpolytile = {"gr_polytile", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
CV_PossibleValue_t grpolyshape_cons_t[] = {
|
||||
{0, "Subsector"},
|
||||
{1, "Fat"},
|
||||
{2, "Trim"},
|
||||
{3, "NotConvex"},
|
||||
{0, NULL}
|
||||
};
|
||||
consvar_t cv_glpolyshape = {"gr_polygon_shape", "Trim", CV_SAVE, grpolyshape_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_glbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_glwireframe = {"gr_wireframe", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
@@ -559,7 +548,7 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, pslope_t *slope, const sector_t
|
||||
|
||||
// HWR_RenderPlane
|
||||
// Render a floor or ceiling convex polygon
|
||||
static void HWR_RenderPlane(subsector_t *subsector, poly_subsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
|
||||
static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
|
||||
{
|
||||
FSurfaceInfo Surf = {};
|
||||
FOutVector *v3d;
|
||||
@@ -2832,7 +2821,7 @@ static void HWR_AddPolyObjectPlanes(void)
|
||||
sector_t *polyobjsector;
|
||||
INT32 light = 0;
|
||||
|
||||
// Polyobject Planes need their own function for drawing because they don't have poly_subsectors by themselves
|
||||
// Polyobject Planes need their own function for drawing because they don't have extrasubsectors by themselves
|
||||
// It should be okay because polyobjects should always be convex anyway
|
||||
|
||||
for (i = 0; i < numpolys; i++)
|
||||
@@ -2960,9 +2949,9 @@ static void HWR_Subsector(size_t num)
|
||||
ffloor_t *rover;
|
||||
|
||||
#ifdef PARANOIA // no risk while developing, enough debugging nights!
|
||||
if (num >= num_poly_subsector)
|
||||
if (num >= addsubsector)
|
||||
I_Error("HWR_Subsector: ss %s with numss = %s, addss = %s\n",
|
||||
sizeu1(num), sizeu2(numsubsectors), sizeu3(num_poly_subsector));
|
||||
sizeu1(num), sizeu2(numsubsectors), sizeu3(addsubsector));
|
||||
#endif
|
||||
|
||||
if (num < numsubsectors)
|
||||
@@ -3057,7 +3046,7 @@ static void HWR_Subsector(size_t num)
|
||||
if (sub->validcount != validcount)
|
||||
{
|
||||
HWR_GetFlat(levelflats[gl_frontsector->floorpic].lumpnum, R_NoEncore(gl_frontsector, false));
|
||||
HWR_RenderPlane(sub, &poly_subsectors[num], false,
|
||||
HWR_RenderPlane(sub, &extrasubsectors[num], false,
|
||||
gl_frontsector->floorheight,
|
||||
// We now return you to your regularly scheduled rendering.
|
||||
PF_Occlude, floorlightlevel, levelflats[gl_frontsector->floorpic].lumpnum, NULL, 255, floorcolormap);
|
||||
@@ -3072,7 +3061,7 @@ static void HWR_Subsector(size_t num)
|
||||
if (sub->validcount != validcount)
|
||||
{
|
||||
HWR_GetFlat(levelflats[gl_frontsector->ceilingpic].lumpnum, R_NoEncore(gl_frontsector, true));
|
||||
HWR_RenderPlane(sub, &poly_subsectors[num], true,
|
||||
HWR_RenderPlane(sub, &extrasubsectors[num], true,
|
||||
gl_frontsector->ceilingheight,
|
||||
// We now return you to your regularly scheduled rendering.
|
||||
PF_Occlude, ceilinglightlevel, levelflats[gl_frontsector->ceilingpic].lumpnum, NULL, 255, ceilingcolormap);
|
||||
@@ -3119,7 +3108,7 @@ static void HWR_Subsector(size_t num)
|
||||
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
|
||||
|
||||
HWR_AddTransparentFloor(0,
|
||||
&poly_subsectors[num],
|
||||
&extrasubsectors[num],
|
||||
false,
|
||||
*rover->bottomheight,
|
||||
*gl_frontsector->lightlist[light].lightlevel,
|
||||
@@ -3131,7 +3120,7 @@ static void HWR_Subsector(size_t num)
|
||||
light = R_GetPlaneLight(gl_frontsector, centerHeight, (viewz < bottomCullHeight));
|
||||
|
||||
HWR_AddTransparentFloor(levelflats[*rover->bottompic].lumpnum,
|
||||
&poly_subsectors[num],
|
||||
&extrasubsectors[num],
|
||||
false,
|
||||
*rover->bottomheight,
|
||||
*gl_frontsector->lightlist[light].lightlevel,
|
||||
@@ -3143,7 +3132,7 @@ static void HWR_Subsector(size_t num)
|
||||
HWR_GetFlat(levelflats[*rover->bottompic].lumpnum, R_NoEncore(gl_frontsector, false));
|
||||
light = R_GetPlaneLight(gl_frontsector, centerHeight, (viewz < bottomCullHeight));
|
||||
|
||||
HWR_RenderPlane(sub, &poly_subsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
|
||||
HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
|
||||
rover->master->frontsector, 255, gl_frontsector->lightlist[light].extra_colormap);
|
||||
}
|
||||
}
|
||||
@@ -3165,7 +3154,7 @@ static void HWR_Subsector(size_t num)
|
||||
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
|
||||
|
||||
HWR_AddTransparentFloor(0,
|
||||
&poly_subsectors[num],
|
||||
&extrasubsectors[num],
|
||||
true,
|
||||
*rover->topheight,
|
||||
*gl_frontsector->lightlist[light].lightlevel,
|
||||
@@ -3177,7 +3166,7 @@ static void HWR_Subsector(size_t num)
|
||||
light = R_GetPlaneLight(gl_frontsector, centerHeight, (viewz < topCullHeight));
|
||||
|
||||
HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum,
|
||||
&poly_subsectors[num],
|
||||
&extrasubsectors[num],
|
||||
true,
|
||||
*rover->topheight,
|
||||
*gl_frontsector->lightlist[light].lightlevel,
|
||||
@@ -3189,7 +3178,7 @@ static void HWR_Subsector(size_t num)
|
||||
HWR_GetFlat(levelflats[*rover->toppic].lumpnum, R_NoEncore(gl_frontsector, true));
|
||||
light = R_GetPlaneLight(gl_frontsector, centerHeight, (viewz < topCullHeight));
|
||||
|
||||
HWR_RenderPlane(sub, &poly_subsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
|
||||
HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
|
||||
rover->master->frontsector, 255, gl_frontsector->lightlist[light].extra_colormap);
|
||||
}
|
||||
}
|
||||
@@ -4270,7 +4259,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
poly_subsector_t *xsub;
|
||||
extrasubsector_t *xsub;
|
||||
boolean isceiling;
|
||||
fixed_t fixedheight;
|
||||
INT32 lightlevel;
|
||||
@@ -4354,7 +4343,7 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I
|
||||
wallinfo->wallcolormap = wallcolormap;
|
||||
}
|
||||
|
||||
static void HWR_AddTransparentFloor(lumpnum_t lumpnum, poly_subsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
|
||||
static void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
|
||||
{
|
||||
planeinfo_t *planeinfo = static_cast<planeinfo_t*>(HWR_CreateDrawNode(DRAWNODE_PLANE));
|
||||
|
||||
@@ -5824,7 +5813,6 @@ void HWR_RenderPlayerView(void)
|
||||
|
||||
void HWR_LoadLevel(void)
|
||||
{
|
||||
HWR_FreePolyPool();
|
||||
HWR_CreatePlanePolygons((INT32)numnodes - 1);
|
||||
|
||||
// Build the sky dome
|
||||
@@ -5909,8 +5897,6 @@ void HWR_AddCommands(void)
|
||||
CV_RegisterVar(&cv_glanisotropicmode);
|
||||
|
||||
CV_RegisterVar(&cv_glsolvetjoin);
|
||||
CV_RegisterVar(&cv_glpolytile);
|
||||
CV_RegisterVar(&cv_glpolyshape);
|
||||
|
||||
CV_RegisterVar(&cv_glbatching);
|
||||
|
||||
@@ -5938,7 +5924,6 @@ void HWR_Startup(void)
|
||||
CONS_Printf("HWR_Startup()...\n");
|
||||
textureformat = patchformat = GL_TEXFMT_RGBA;
|
||||
|
||||
HWR_InitPolyPool();
|
||||
HWR_InitMapTextures();
|
||||
HWR_InitMD2();
|
||||
|
||||
@@ -6030,7 +6015,7 @@ static void COM_HWR_glinfo(void)
|
||||
void HWR_Shutdown(void)
|
||||
{
|
||||
CONS_Printf("HWR_Shutdown()\n");
|
||||
HWR_FreePolyPool();
|
||||
HWR_FreeExtraSubsectors();
|
||||
HWR_FreeMapTextures();
|
||||
GL_FlushScreenTextures();
|
||||
HWR_ClearAllTextures();
|
||||
|
||||
@@ -195,7 +195,7 @@ extern consvar_t cv_gllightdither;
|
||||
extern consvar_t cv_glfiltermode;
|
||||
extern consvar_t cv_glanisotropicmode;
|
||||
|
||||
extern consvar_t cv_glsolvetjoin, cv_glpolytile, cv_glpolyshape;
|
||||
extern consvar_t cv_glsolvetjoin;
|
||||
|
||||
extern consvar_t cv_glbatching;
|
||||
|
||||
|
||||
@@ -1887,8 +1887,6 @@ INT32 I_StartupSystem(void)
|
||||
SDL_VERSION(&SDLcompiled)
|
||||
SDL_GetVersion(&SDLlinked);
|
||||
|
||||
W_Startup();
|
||||
|
||||
I_StartupConsole();
|
||||
#ifdef NEWSIGNALHANDLER
|
||||
// This is useful when debugging. It lets GDB attach to
|
||||
|
||||
+8
-1
@@ -462,6 +462,8 @@ License (MIT):
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fastcmp.h"
|
||||
|
||||
// Two-way concatenation macro.
|
||||
#define VT_CAT_( a, b ) a##b
|
||||
#define VT_CAT( a, b ) VT_CAT_( a, b )
|
||||
@@ -705,7 +707,12 @@ static inline FORCE_INLINE bool vt_cmpr_integer( uint64_t key_1, uint64_t key_2
|
||||
|
||||
static inline FORCE_INLINE bool vt_cmpr_string( const char *key_1, const char *key_2 )
|
||||
{
|
||||
return strcmp( key_1, key_2 ) == 0;
|
||||
return fastcmp( key_1, key_2 );
|
||||
}
|
||||
|
||||
static inline FORCE_INLINE bool vt_cmpr_casestring( const char *key_1, const char *key_2 )
|
||||
{
|
||||
return fasticmp( key_1, key_2 );
|
||||
}
|
||||
|
||||
// Default allocation and free functions.
|
||||
|
||||
+2
-3
@@ -158,8 +158,7 @@ void W_Shutdown(void)
|
||||
}
|
||||
|
||||
// the lumpnum cache needs to be initialized before use
|
||||
// call this as early as possible!
|
||||
void W_Startup(void)
|
||||
CONSTRUCTOR static void W_Startup(void)
|
||||
{
|
||||
lumpnum_map_init(&lumpnumcache);
|
||||
lumpnum_map_reserve(&lumpnumcache, LUMPNUMCACHESIZE);
|
||||
@@ -367,7 +366,7 @@ static inline INT32 W_MakeFileMD5(const char *filename, void *resblock)
|
||||
{
|
||||
precise_t t = I_GetPreciseTime();
|
||||
|
||||
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",filename);
|
||||
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n", filename);
|
||||
|
||||
if (md5_stream(fhandle, resblock) == 1)
|
||||
{
|
||||
|
||||
@@ -154,7 +154,6 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
|
||||
|
||||
// =========================================================================
|
||||
|
||||
void W_Startup(void);
|
||||
void W_Shutdown(void);
|
||||
|
||||
// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
|
||||
|
||||
Reference in new issue
Block a user