Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * string manipulation utility code
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include <string.h>
  30. #include <stdarg.h>
  31.  
  32. #include "u_mem.h"
  33. #include "dxxerror.h"
  34. #include "strutil.h"
  35. #include "inferno.h"
  36.  
  37. #include "compiler-range_for.h"
  38.  
  39. namespace dcx {
  40.  
  41. #ifdef macintosh
  42. void snprintf(char *out_string, int size, char * format, ... )
  43. {
  44.         va_list         args;
  45.         char            buf[1024];
  46.        
  47.         va_start(args, format );
  48.         vsprintf(buf,format,args);
  49.         va_end(args);
  50.  
  51.         // Hack! Don't know any other [simple] way to do this, but I doubt it would ever exceed 1024 long.
  52.         Assert(strlen(buf) < 1024);
  53.         Assert(size < 1024);
  54.  
  55.         strncpy(out_string, buf, size);
  56. }
  57. #endif // macintosh
  58.  
  59. // string compare without regard to case
  60.  
  61. #ifndef DXX_HAVE_STRCASECMP
  62. int d_stricmp( const char *s1, const char *s2 )
  63. {
  64.         for (;; ++s1, ++s2)
  65.         {
  66.                 auto u1 = toupper(static_cast<unsigned>(*s1));
  67.                 auto u2 = toupper(static_cast<unsigned>(*s2));
  68.                 if (u1 != u2)
  69.                         return (u1 > u2) ? 1 : -1;
  70.                 if (!u1)
  71.                         return u1;
  72.         }
  73. }
  74.  
  75. int d_strnicmp(const char *s1, const char *s2, uint_fast32_t n)
  76. {
  77.         for (; n; ++s1, ++s2, --n)
  78.         {
  79.                 auto u1 = toupper(static_cast<unsigned>(*s1));
  80.                 auto u2 = toupper(static_cast<unsigned>(*s2));
  81.                 if (u1 != u2)
  82.                         return (u1 > u2) ? 1 : -1;
  83.                 if (!u1)
  84.                         return u1;
  85.         }
  86.         return 0;
  87. }
  88. #endif
  89.  
  90. void d_strlwr( char *s1 )
  91. {
  92.         while( *s1 )    {
  93.                 *s1 = tolower(*s1);
  94.                 s1++;
  95.         }
  96. }
  97.  
  98. void d_strupr( char *s1 )
  99. {
  100.         while( *s1 )    {
  101.                 *s1 = toupper(*s1);
  102.                 s1++;
  103.         }
  104. }
  105.  
  106. void d_strrev( char *s1 )
  107. {
  108.         char *h, *t;
  109.         h = s1;
  110.         t = s1 + strlen(s1) - 1;
  111.         while (h < t) {
  112.                 char c;
  113.                 c = *h;
  114.                 *h++ = *t;
  115.                 *t-- = c;
  116.         }
  117. }
  118.  
  119. #ifdef DEBUG_MEMORY_ALLOCATIONS
  120. char *(d_strdup)(const char *str, const char *var, const char *file, unsigned line)
  121. {
  122.         char *newstr;
  123.  
  124.         const auto len = strlen(str) + 1;
  125.         MALLOC<char>(newstr, len, var, file, line);
  126.         return static_cast<char *>(memcpy(newstr, str, len));
  127. }
  128. #endif
  129.  
  130. // remove extension from filename
  131. void removeext(const char *const filename, std::array<char, 20> &out)
  132. {
  133.         const char *p = nullptr;
  134.         auto i = filename;
  135.         for (; const char c = *i; ++i)
  136.         {
  137.                 if (c == '.')
  138.                         p = i;
  139.                 /* No break - find the last '.', not the first. */
  140.         }
  141.         if (!p)
  142.                 p = i;
  143.         const std::size_t rawlen = p - filename;
  144.         const std::size_t copy_len = rawlen < out.size() ? rawlen : 0;
  145.         out[copy_len] = 0;
  146.         memcpy(out.data(), filename, copy_len);
  147. }
  148.  
  149.  
  150. //give a filename a new extension, won't append if strlen(dest) > 8 chars.
  151. void change_filename_extension( char *dest, const char *src, const char *ext )
  152. {
  153.         char *p;
  154.        
  155.         strcpy (dest, src);
  156.        
  157.         if (ext[0] == '.')
  158.                 ext++;
  159.        
  160.         p = strrchr(dest, '.');
  161.         if (!p) {
  162.                 if (strlen(dest) > FILENAME_LEN - 5)
  163.                         return; // a non-opened file is better than a bad memory access
  164.                
  165.                 p = dest + strlen(dest);
  166.                 *p = '.';
  167.         }
  168.        
  169.         strcpy(p+1,ext);
  170. }
  171.  
  172. void d_splitpath(const char *name, struct splitpath_t *path)
  173. {
  174.         const char *s, *p;
  175.  
  176.         p = name;
  177.         s = strchr(p, ':');
  178.         if ( s != NULL ) {
  179.                 path->drive_start = p;
  180.                 path->drive_end = s;
  181.                 p = s+1;
  182.         } else
  183.                 path->drive_start = path->drive_end = NULL;
  184.         s = strrchr(p, '\\');
  185.         if ( s != NULL) {
  186.                 path->path_start = p;
  187.                 path->path_end = s + 1;
  188.                 p = s+1;
  189.         } else
  190.                 path->path_start = path->path_end = NULL;
  191.  
  192.         s = strchr(p, '.');
  193.         if ( s != NULL) {
  194.                 path->base_start = p;
  195.                 path->base_end = s;
  196.                 p = s+1;
  197.         } else
  198.                 path->base_start = path->base_end = NULL;
  199.         path->ext_start = p;
  200. }
  201.  
  202. int string_array_sort_func(const void *v0, const void *v1)
  203. {
  204.         const auto e0 = reinterpret_cast<const char *const *>(v0);
  205.         const auto e1 = reinterpret_cast<const char *const *>(v1);
  206.         return d_stricmp(*e0, *e1);
  207. }
  208.  
  209. void string_array_t::add(const char *s)
  210. {
  211.         const auto insert_string = [this, s]{
  212.                 auto &b = this->buffer;
  213.                 b.insert(b.end(), s, s + strlen(s) + 1);
  214.         };
  215.         if (buffer.empty())
  216.         {
  217.                 insert_string();
  218.                 ptr.emplace_back(&buffer.front());
  219.                 return;
  220.         }
  221.         const char *ob = &buffer.front();
  222.         ptr.emplace_back(1 + &buffer.back());
  223.         insert_string();
  224.         if (auto d = &buffer.front() - ob)
  225.         {
  226.                 // Update all the pointers in the pointer list
  227.                 range_for (auto &i, ptr)
  228.                         i += d;
  229.         }
  230. }
  231.  
  232. void string_array_t::tidy(std::size_t offset, int (*comp)( const char *, const char * ))
  233. {
  234.         // Sort by name, starting at offset
  235.         auto b = std::next(ptr.begin(), offset);
  236.         auto e = ptr.end();
  237.         std::sort(b, e, [](const char *sa, const char *sb) { return d_stricmp(sa, sb) < 0; });
  238.         // Remove duplicates
  239.         // Can't do this before reallocating, otherwise it makes a mess of things (the strings in the buffer aren't ordered)
  240.         ptr.erase(std::unique(b, e, [=](const char *sa, const char *sb) { return (*comp)(sa, sb) == 0; }), e);
  241. }
  242.  
  243. }
  244.