size_t real_length; // uncompressed file size (for files opened in "read" mode)
size_t position; // current position in the file
size_t offset; // offset into the package (0 if external file)
+ int ungetc; // single stored character from ungetc, cleared to EOF when read
// Contents buffer
size_t buff_ind, buff_len; // buffer current index and length
{
if (matchpattern(current->text, "*.pak", true))
{
- snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
+ dpsnprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
pak = FS_LoadPackPAK (pakfile);
if (pak)
{
{
if (matchpattern(current->text, "*.pk3", true))
{
- snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
+ dpsnprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
pak = FS_LoadPackPK3 (pakfile);
if (pak)
{
Internal function used to create a qfile_t and open the relevant non-packed file on disk
====================
*/
-static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
+static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking)
{
qfile_t* file;
int mod, opt;
}
}
+#ifndef WIN32
+ if (nonblocking)
+ opt |= O_NONBLOCK;
+#endif
+
file = Mem_Alloc (fs_mempool, sizeof (*file));
memset (file, 0, sizeof (*file));
+ file->ungetc = EOF;
file->handle = open (filepath, mod | opt, 0666);
if (file->handle < 0)
return NULL;
}
- // For files opened in read mode, we now need to get the length
- if (mod == O_RDONLY)
- {
- file->real_length = lseek (file->handle, 0, SEEK_END);
+ file->real_length = lseek (file->handle, 0, SEEK_END);
+
+ // For files opened in append mode, we start at the end of the file
+ if (mod & O_APPEND)
+ file->position = file->real_length;
+ else
lseek (file->handle, 0, SEEK_SET);
- }
return file;
}
file->real_length = pfile->realsize;
file->offset = pfile->offset;
file->position = 0;
+ file->ungetc = EOF;
if (lseek (file->handle, file->offset, SEEK_SET) == -1)
Sys_Error ("FS_OpenPackedFile: can't lseek to %s in %s (offset: %d)",
else
{
char netpath[MAX_OSPATH];
- snprintf(netpath, sizeof(netpath), "%s/%s", search->filename, name);
+ dpsnprintf(netpath, sizeof(netpath), "%s/%s", search->filename, name);
if (FS_SysFileExists (netpath))
{
if (!quiet)
Sets fs_filesize
===========
*/
-qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet)
+qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet, qboolean nonblocking)
{
searchpath_t *search;
int pack_ind;
if (pack_ind < 0)
{
char path [MAX_OSPATH];
- snprintf (path, sizeof (path), "%s/%s", search->filename, filename);
- return FS_SysOpen (path, "rb");
+ dpsnprintf (path, sizeof (path), "%s/%s", search->filename, filename);
+ return FS_SysOpen (path, "rb", nonblocking);
}
// So, we found it in a package...
Open a file. The syntax is the same as fopen
====================
*/
-qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
+qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet, qboolean nonblocking)
{
qfile_t* file;
char real_path [MAX_OSPATH];
// Open the file on disk directly
- snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
+ dpsnprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
// Create directories up to the file
FS_CreatePath (real_path);
- return FS_SysOpen (real_path, mode);
+ return FS_SysOpen (real_path, mode, nonblocking);
}
// Else, we look at the various search paths and open the file in read-only mode
- file = FS_OpenReadFile (filepath, quiet);
+ file = FS_OpenReadFile (filepath, quiet, nonblocking);
if (file != NULL)
fs_filesize = file->real_length;
*/
size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
{
- ssize_t result = write (file->handle, data, datasize);
+ ssize_t result;
+
+ // If necessary, seek to the exact file position we're supposed to be
+ if (file->buff_ind != file->buff_len)
+ lseek (file->handle, file->buff_ind - file->buff_len, SEEK_CUR);
+
+ // Purge cached data
+ FS_Purge (file);
+
+ // Write the buffer and update the position
+ result = write (file->handle, data, datasize);
+ file->position = lseek (file->handle, 0, SEEK_CUR);
+ if (file->real_length < file->position)
+ file->real_length = file->position;
+
if (result < 0)
return 0;
{
size_t count, done;
+ if (buffersize == 0)
+ return 0;
+
+ // Get rid of the ungetc character
+ if (file->ungetc != EOF)
+ {
+ ((char*)buffer)[0] = file->ungetc;
+ buffersize--;
+ file->ungetc = EOF;
+ done = 1;
+ }
+ else
+ done = 0;
+
// First, we copy as many bytes as we can from "buff"
if (file->buff_ind < file->buff_len)
{
count = file->buff_len - file->buff_ind;
- done = (buffersize > count) ? count : buffersize;
+ done += (buffersize > count) ? count : buffersize;
memcpy (buffer, &file->buff[file->buff_ind], done);
file->buff_ind += done;
if (buffersize == 0)
return done;
}
- else
- done = 0;
// NOTE: at this point, the read buffer is always empty
done += nb;
file->position += nb;
- // Invalidate the output data (for FS_Seek)
- file->buff_len = 0;
- file->buff_ind = 0;
+ // Purge cached data
+ FS_Purge (file);
}
}
else
count = buffersize - ztk->zstream.avail_out;
file->position += count;
- // Invalidate the output data (for FS_Seek)
- file->buff_len = 0;
- file->buff_ind = 0;
+ // Purge cached data
+ FS_Purge (file);
}
done += count;
int FS_VPrintf (qfile_t* file, const char* format, va_list ap)
{
int len;
- char tempstring [1024];
+ size_t buff_size;
+ char *tempbuff = NULL;
- len = vsnprintf (tempstring, sizeof(tempstring), format, ap);
- if (len >= sizeof (tempstring))
+ buff_size = 1024;
+ tempbuff = Mem_Alloc (tempmempool, buff_size);
+ len = dpvsnprintf (tempbuff, buff_size, format, ap);
+ while (len < 0)
{
- char *temp = Mem_Alloc (tempmempool, len + 1);
- len = vsnprintf (temp, len + 1, format, ap);
- len = write (file->handle, temp, len);
- Mem_Free (temp);
- return len;
+ Mem_Free (tempbuff);
+ buff_size *= 2;
+ tempbuff = Mem_Alloc (tempmempool, buff_size);
+ len = dpvsnprintf (tempbuff, buff_size, format, ap);
}
- return write (file->handle, tempstring, len);
+ len = write (file->handle, tempbuff, len);
+ Mem_Free (tempbuff);
+
+ return len;
}
}
+/*
+====================
+FS_UnGetc
+
+Put a character back into the read buffer (only supports one character!)
+====================
+*/
+int FS_UnGetc (qfile_t* file, unsigned char c)
+{
+ // If there's already a character waiting to be read
+ if (file->ungetc != EOF)
+ return EOF;
+
+ file->ungetc = c;
+ return c;
+}
+
+
/*
====================
FS_Seek
return 0;
}
- // Invalidate the read buffer contents
- file->buff_ind = 0;
- file->buff_len = 0;
+ // Purge cached data
+ FS_Purge (file);
// Unpacked or uncompressed files can seek directly
if (! (file->flags & QFILE_FLAG_DEFLATED))
/*
====================
-FS_Gets
+FS_Purge
-Extract a line from a file
+Erases any buffered input or output data
====================
*/
-char* FS_Gets (qfile_t* file, char* buffer, size_t buffersize)
+void FS_Purge (qfile_t* file)
{
- size_t ind;
-
- for (ind = 0; ind < (size_t) buffersize - 1; ind++)
- {
- int c = FS_Getc (file);
- switch (c)
- {
- // End of file
- case EOF:
- if (!ind)
- return NULL;
-
- buffer[ind] = '\0';
- return buffer;
-
- // End of line
- case '\r':
- case '\n':
- buffer[ind] = '\n';
- buffer[ind + 1] = '\0';
- return buffer;
-
- default:
- buffer[ind] = c;
- }
-
- }
-
- buffer[buffersize - 1] = '\0';
- return buffer;
-}
-
-
-/*
-==========
-FS_Getline
-
-Dynamic length version of fgets. DO NOT free the buffer.
-==========
-*/
-char *FS_Getline (qfile_t *file)
-{
- static int size = 256;
- static char *buf = 0;
- char *t;
- int len;
-
- if (!buf)
- buf = Mem_Alloc (fs_mempool, size);
-
- if (!FS_Gets (file, buf, size))
- return 0;
-
- len = strlen (buf);
- while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
- {
- t = Mem_Alloc (fs_mempool, size + 256);
- memcpy(t, buf, size);
- Mem_Free(buf);
- size += 256;
- buf = t;
- if (!FS_Gets (file, buf + len, size - len))
- break;
- len = strlen (buf);
- }
- while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
- buf[len - 1] = 0;
- return buf;
+ file->buff_len = 0;
+ file->buff_ind = 0;
+ file->ungetc = EOF;
}
qfile_t *file;
qbyte *buf;
- file = FS_Open (path, "rb", quiet);
+ file = FS_Open (path, "rb", quiet, false);
if (!file)
return NULL;
{
qfile_t *file;
- file = FS_Open (filename, "wb", false);
+ file = FS_Open (filename, "wb", false, false);
if (!file)
{
Con_Printf("FS_WriteFile: failed on %s\n", filename);
else
{
// get a directory listing and look at each name
- snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath);
+ dpsnprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath);
if ((dir = listdirectory(netpath)))
{
for (dirfile = dir;dirfile;dirfile = dirfile->next)
{
- snprintf(temp, sizeof(temp), "%s/%s", basepath, dirfile->text);
+ dpsnprintf(temp, sizeof(temp), "%s/%s", basepath, dirfile->text);
if (matchpattern(temp, (char *)pattern, true))
{
for (listtemp = liststart;listtemp;listtemp = listtemp->next)