]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - fs.c
added dir and ls console commands (yes they are different), these search paks (althou...
[xonotic/darkplaces.git] / fs.c
diff --git a/fs.c b/fs.c
index b0c2de1e7c924d0f741f27e63f8cd92ada5d4a93..084f062042fa2a8ebc728defc08ef6bc72ef8853 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -751,7 +751,7 @@ void FS_AddGameDirectory (char *dir)
        {
                if (matchpattern(current->text, "*.pak", true))
                {
-                       sprintf (pakfile, "%s/%s", dir, current->text);
+                       snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
                        pak = FS_LoadPackPAK (pakfile);
                        if (pak)
                        {
@@ -770,7 +770,7 @@ void FS_AddGameDirectory (char *dir)
        {
                if (matchpattern(current->text, "*.pk3", true))
                {
-                       sprintf (pakfile, "%s/%s", dir, current->text);
+                       snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
                        pak = FS_LoadPackPK3 (pakfile);
                        if (pak)
                        {
@@ -816,6 +816,8 @@ char *FS_FileExtension (const char *in)
        return exten;
 }
 
+void FS_Dir_f(void);
+void FS_Ls_f(void);
 
 /*
 ================
@@ -831,6 +833,8 @@ void FS_Init (void)
        pak_mempool = Mem_AllocPool("paks");
 
        Cmd_AddCommand ("path", FS_Path_f);
+       Cmd_AddCommand ("dir", FS_Dir_f);
+       Cmd_AddCommand ("ls", FS_Ls_f);
 
        strcpy(fs_basedir, ".");
 
@@ -982,6 +986,103 @@ qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
 
        filenamelen = strlen (filename);
 
+       // LordHavoc: this is not written right!
+       // (should search have higher priority for files in each gamedir, while
+       // preserving the gamedir priorities, not searching for all paks in all
+       // gamedirs and then all files in all gamedirs)
+#ifdef AKVERSION
+       // first we search for a real file, after that we start to search through the paks
+       // search through the path, one element at a time
+       search = fs_searchpaths;
+
+       for( ; search ; search = search->next)
+               if(!search->pack)
+               {
+                       snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
+
+                       if (!FS_SysFileExists (netpath))
+                               continue;
+
+                       if (!quiet)
+                               Sys_Printf ("FindFile: %s\n",netpath);
+                       return FS_OpenRead (netpath, -1, -1);
+               }
+
+       search = fs_searchpaths;
+       for ( ; search ; search = search->next)
+               // is the element a pak file?
+               if (search->pack)
+               {
+                       // look through all the pak file elements
+                       pak = search->pack;
+                       for (i=0 ; i<pak->numfiles ; i++)
+                       {
+                               if (pak->ignorecase)
+                                       matched = !strcasecmp (pak->files[i].name, filename);
+                               else
+                                       matched = !strcmp (pak->files[i].name, filename);
+                               if (matched)  // found it?
+                               {
+                                       qfile_t *file;
+
+                                       if (!quiet)
+                                               Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
+
+                                       // If we don't have the true offset, get it now
+                                       if (! (pak->files[i].flags & FILE_FLAG_TRUEOFFS))
+                                               PK3_GetTrueFileOffset (&pak->files[i], pak);
+
+                                       // No Zlib DLL = no compressed files
+                                       if (!zlib_dll && (pak->files[i].flags & FILE_FLAG_DEFLATED))
+                                       {
+                                               Con_Printf ("WARNING: can't open the compressed file %s\n"
+                                                                       "You need the Zlib DLL to use compressed files\n", filename);
+                                               fs_filesize = -1;
+                                               return NULL;
+                                       }
+
+                                       // open a new file in the pakfile
+                                       file = FS_OpenRead (pak->filename, pak->files[i].offset, pak->files[i].packsize);
+                                       fs_filesize = pak->files[i].realsize;
+
+                                       if (pak->files[i].flags & FILE_FLAG_DEFLATED)
+                                       {
+                                               ztoolkit_t *ztk;
+
+                                               file->flags |= FS_FLAG_DEFLATED;
+
+                                               // We need some more variables
+                                               ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
+
+                                               ztk->real_length = pak->files[i].realsize;
+
+                                               // Initialize zlib stream
+                                               ztk->zstream.next_in = ztk->input;
+                                               ztk->zstream.avail_in = 0;
+
+                                               /* From Zlib's "unzip.c":
+                                                *
+                                                * windowBits is passed < 0 to tell that there is no zlib header.
+                                                * Note that in this case inflate *requires* an extra "dummy" byte
+                                                * after the compressed stream in order to complete decompression and
+                                                * return Z_STREAM_END.
+                                                * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+                                                * size of both compressed and uncompressed data
+                                                */
+                                               if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
+                                                       Sys_Error ("inflate init error (file: %s)", filename);
+
+                                               ztk->zstream.next_out = ztk->output;
+                                               ztk->zstream.avail_out = sizeof (ztk->output);
+
+                                               file->z = ztk;
+                                       }
+
+                                       return file;
+                               }
+                       }
+               }
+#else
        // search through the path, one element at a time
        search = fs_searchpaths;
 
@@ -1061,7 +1162,7 @@ qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
                }
                else
                {
-                       sprintf (netpath, "%s/%s",search->filename, filename);
+                       snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
 
                        if (!FS_SysFileExists (netpath))
                                continue;
@@ -1071,6 +1172,7 @@ qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
                        return FS_OpenRead (netpath, -1, -1);
                }
        }
+#endif
 
        if (!quiet)
                Sys_Printf ("FindFile: can't find %s\n", filename);
@@ -1603,7 +1705,7 @@ qboolean FS_WriteFile (const char *filename, void *data, int len)
        FILE *handle;
        char name[MAX_OSPATH];
 
-       sprintf (name, "%s/%s", fs_gamedir, filename);
+       snprintf (name, sizeof (name), "%s/%s", fs_gamedir, filename);
 
        // Create directories up to the file
        FS_CreatePath (name);
@@ -1635,16 +1737,21 @@ OTHERS PUBLIC FUNCTIONS
 FS_StripExtension
 ============
 */
-void FS_StripExtension (const char *in, char *out)
+void FS_StripExtension (const char *in, char *out, size_t size_out)
 {
        char *last = NULL;
-       while (*in)
+
+       if (size_out == 0)
+               return;
+
+       while (*in && size_out > 1)
        {
                if (*in == '.')
                        last = out;
                else if (*in == '/' || *in == '\\' || *in == ':')
                        last = NULL;
                *out++ = *in++;
+               size_out--;
        }
        if (last)
                *last = 0;
@@ -1695,7 +1802,7 @@ qboolean FS_FileExists (const char *filename)
                }
                else
                {
-                       sprintf (netpath, "%s/%s",search->filename, filename);
+                       snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
                        if (FS_SysFileExists (netpath))
                                return true;
                }
@@ -1736,3 +1843,242 @@ void FS_mkdir (const char *path)
        mkdir (path, 0777);
 #endif
 }
+
+/*
+===========
+FS_Search
+
+Allocate and fill a search structure with information on matching filenames.
+===========
+*/
+fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
+{
+       fssearch_t *search;
+       searchpath_t *searchpath;
+       pack_t *pak;
+       int i, basepathlength, numfiles, numchars, step;
+       stringlist_t *dir, *dirfile;
+       const char *slash, *backslash, *colon, *separator;
+       char *basepath;
+       char netpath[MAX_OSPATH];
+
+       while(!strncmp(pattern, "./", 2))
+               pattern += 2;
+       while(!strncmp(pattern, ".\\", 2))
+               pattern += 2;
+
+       search = NULL;
+       numfiles = 0;
+       numchars = 0;
+       slash = strrchr(pattern, '/');
+       backslash = strrchr(pattern, '\\');
+       colon = strrchr(pattern, ':');
+       separator = slash;
+       if (separator < backslash)
+               separator = backslash;
+       if (separator < colon)
+               separator = colon;
+       if (separator)
+               basepathlength = separator + 1 - pattern;
+       else
+               basepathlength = 0;
+       basepath = Z_Malloc(basepathlength + 1);
+       if (basepathlength)
+               memcpy(basepath, pattern, basepathlength);
+       basepath[basepathlength] = 0;
+
+       for (step = 0;step < 2;step++)
+       {
+               // search through the path, one element at a time
+               for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
+               {
+                       // is the element a pak file?
+                       if (searchpath->pack)
+                       {
+                               // look through all the pak file elements
+                               pak = searchpath->pack;
+                               for (i = 0;i < pak->numfiles;i++)
+                               {
+                                       if (matchpattern(pak->files[i].name, (char *)pattern, caseinsensitive || pak->ignorecase))
+                                       {
+                                               if (search)
+                                               {
+                                                       search->filenames[numfiles] = search->filenamesbuffer + numchars;
+                                                       strcpy(search->filenames[numfiles], pak->files[i].name);
+                                               }
+                                               numfiles++;
+                                               numchars += strlen(pak->files[i].name) + 1;
+                                               if (!quiet)
+                                                       Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, pak->files[i].name);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               // get a directory listing and look at each name
+                               snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, pattern);
+                               if ((dir = listdirectory(netpath)))
+                               {
+                                       for (dirfile = dir;dirfile;dirfile = dirfile->next)
+                                       {
+                                               if (matchpattern(dirfile->text, (char *)pattern + basepathlength, caseinsensitive || pak->ignorecase))
+                                               {
+                                                       if (search)
+                                                       {
+                                                               search->filenames[numfiles] = search->filenamesbuffer + numchars;
+                                                               memcpy(search->filenames[numfiles], basepath, basepathlength);
+                                                               strcpy(search->filenames[numfiles] + basepathlength, dirfile->text);
+                                                       }
+                                                       numfiles++;
+                                                       numchars += basepathlength + strlen(dirfile->text) + 1;
+                                                       if (!quiet)
+                                                               Sys_Printf("SearchDirFile: %s\n", dirfile->text);
+                                               }
+                                       }
+                                       freedirectory(dir);
+                               }
+                       }
+               }
+
+               if (step == 0)
+               {
+                       if (!numfiles || !numchars)
+                       {
+                               Z_Free(basepath);
+                               return NULL;
+                       }
+                       // prepare for second pass (allocate the memory to fill in)
+                       search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
+                       search->filenames = (char **)((char *)search + sizeof(fssearch_t));
+                       search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
+                       search->numfilenames = numfiles;
+                       // these are used for tracking as the buffers are written on the second pass
+                       numfiles = 0;
+                       numchars = 0;
+               }
+       }
+
+       Z_Free(basepath);
+       return search;
+}
+
+void FS_FreeSearch(fssearch_t *search)
+{
+       Z_Free(search);
+}
+
+extern int con_linewidth;
+int FS_ListDirectory(const char *pattern, int oneperline)
+{
+       int numfiles;
+       int numcolumns;
+       int numlines;
+       int columnwidth;
+       int linebufpos;
+       int i, j, k, l;
+       const char *name;
+       char linebuf[4096];
+       fssearch_t *search;
+       search = FS_Search(pattern, true, false);
+       if (!search)
+               return 0;
+       numfiles = search->numfilenames;
+       if (!oneperline)
+       {
+               // FIXME: the names could be added to one column list and then
+               // gradually shifted into the next column if they fit, and then the
+               // next to make a compact variable width listing but it's a lot more
+               // complicated...
+               // find width for columns
+               columnwidth = 0;
+               for (i = 0;i < numfiles;i++)
+               {
+                       l = strlen(search->filenames[i]);
+                       if (columnwidth < l)
+                               columnwidth = l;
+               }
+               // count the spacing character
+               columnwidth++;
+               // calculate number of columns
+               numcolumns = con_linewidth / columnwidth;
+               // don't bother with the column printing if it's only one column
+               if (numcolumns >= 2)
+               {
+                       numlines = (numfiles + numcolumns - 1) / numcolumns;
+                       for (i = 0;i < numlines;i++)
+                       {
+                               linebufpos = 0;
+                               for (k = 0;k < numcolumns;k++)
+                               {
+                                       l = i * numcolumns + k;
+                                       if (l < numfiles)
+                                       {
+                                               name = search->filenames[l];
+                                               for (j = 0;name[j] && j < (int)sizeof(linebuf) - 1;j++)
+                                                       linebuf[linebufpos++] = name[j];
+                                               // space out name unless it's the last on the line
+                                               if (k < (numcolumns - 1) && l < (numfiles - 1))
+                                                       for (;j < columnwidth && j < (int)sizeof(linebuf) - 1;j++)
+                                                               linebuf[linebufpos++] = ' ';
+                                       }
+                               }
+                               linebuf[linebufpos] = 0;
+                               Con_Printf("%s\n", linebuf);
+                       }
+               }
+               else
+                       oneperline = true;
+       }
+       if (oneperline)
+               for (i = 0;i < numfiles;i++)
+                       Con_Printf("%s\n", search->filenames[i]);
+       FS_FreeSearch(search);
+       return numfiles;
+}
+
+void FS_Dir_f(void)
+{
+       char pattern[MAX_OSPATH];
+       if (Cmd_Argc() > 3)
+       {
+               Con_Printf("usage:\ndir [path/pattern]\n");
+               return;
+       }
+       if (Cmd_Argc() == 2)
+       {
+               snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
+               if (!FS_ListDirectory(pattern, true))
+               {
+                       snprintf(pattern, sizeof(pattern), "%s/*", Cmd_Argv(1));
+                       if (!FS_ListDirectory(pattern, true))
+                               Con_Printf("No files found.\n");
+               }
+       }
+       else
+       {
+               if (!FS_ListDirectory("*", true))
+                       Con_Printf("No files found.\n");
+       }
+}
+
+void FS_Ls_f(void)
+{
+       char pattern[MAX_OSPATH];
+       if (Cmd_Argc() > 3)
+       {
+               Con_Printf("usage:\ndir [path/pattern]\n");
+               return;
+       }
+       if (Cmd_Argc() == 2)
+       {
+               snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
+               if (!FS_ListDirectory(pattern, false))
+               {
+                       snprintf(pattern, sizeof(pattern), "%s/*", Cmd_Argv(1));
+                       FS_ListDirectory(pattern, false);
+               }
+       }
+       else
+               FS_ListDirectory("*", false);
+}
+