mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			230 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef _C4_YML_WRITER_HPP_
 | |
| #define _C4_YML_WRITER_HPP_
 | |
| 
 | |
| #ifndef _C4_YML_COMMON_HPP_
 | |
| #include "./common.hpp"
 | |
| #endif
 | |
| 
 | |
| #include <c4/substr.hpp>
 | |
| #include <stdio.h>  // fwrite(), fputc()
 | |
| #include <string.h> // memcpy()
 | |
| 
 | |
| 
 | |
| namespace c4 {
 | |
| namespace yml {
 | |
| 
 | |
| 
 | |
| /** Repeat-Character: a character to be written a number of times. */
 | |
| struct RepC
 | |
| {
 | |
|     char c;
 | |
|     size_t num_times;
 | |
| };
 | |
| inline RepC indent_to(size_t num_levels)
 | |
| {
 | |
|     return {' ', size_t(2) * num_levels};
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| /** A writer that outputs to a file. Defaults to stdout. */
 | |
| struct WriterFile
 | |
| {
 | |
|     FILE * m_file;
 | |
|     size_t m_pos;
 | |
| 
 | |
|     WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}
 | |
| 
 | |
|     inline substr _get(bool /*error_on_excess*/)
 | |
|     {
 | |
|         substr sp;
 | |
|         sp.str = nullptr;
 | |
|         sp.len = m_pos;
 | |
|         return sp;
 | |
|     }
 | |
| 
 | |
|     template<size_t N>
 | |
|     inline void _do_write(const char (&a)[N])
 | |
|     {
 | |
|         fwrite(a, sizeof(char), N - 1, m_file);
 | |
|         m_pos += N - 1;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(csubstr sp)
 | |
|     {
 | |
|         #if defined(__clang__)
 | |
|         #   pragma clang diagnostic push
 | |
|         #   pragma GCC diagnostic ignored "-Wsign-conversion"
 | |
|         #elif defined(__GNUC__)
 | |
|         #   pragma GCC diagnostic push
 | |
|         #   pragma GCC diagnostic ignored "-Wsign-conversion"
 | |
|         #endif
 | |
|         if(sp.empty()) return;
 | |
|         fwrite(sp.str, sizeof(csubstr::char_type), sp.len, m_file);
 | |
|         m_pos += sp.len;
 | |
|         #if defined(__clang__)
 | |
|         #   pragma clang diagnostic pop
 | |
|         #elif defined(__GNUC__)
 | |
|         #   pragma GCC diagnostic pop
 | |
|         #endif
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(const char c)
 | |
|     {
 | |
|         fputc(c, m_file);
 | |
|         ++m_pos;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(RepC const rc)
 | |
|     {
 | |
|         for(size_t i = 0; i < rc.num_times; ++i)
 | |
|         {
 | |
|             fputc(rc.c, m_file);
 | |
|         }
 | |
|         m_pos += rc.num_times;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| /** A writer that outputs to an STL-like ostream. */
 | |
| template<class OStream>
 | |
| struct WriterOStream
 | |
| {
 | |
|     OStream& m_stream;
 | |
|     size_t   m_pos;
 | |
| 
 | |
|     WriterOStream(OStream &s) : m_stream(s), m_pos(0) {}
 | |
| 
 | |
|     inline substr _get(bool /*error_on_excess*/)
 | |
|     {
 | |
|         substr sp;
 | |
|         sp.str = nullptr;
 | |
|         sp.len = m_pos;
 | |
|         return sp;
 | |
|     }
 | |
| 
 | |
|     template<size_t N>
 | |
|     inline void _do_write(const char (&a)[N])
 | |
|     {
 | |
|         m_stream.write(a, N - 1);
 | |
|         m_pos += N - 1;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(csubstr sp)
 | |
|     {
 | |
|         #if defined(__clang__)
 | |
|         #   pragma clang diagnostic push
 | |
|         #   pragma GCC diagnostic ignored "-Wsign-conversion"
 | |
|         #elif defined(__GNUC__)
 | |
|         #   pragma GCC diagnostic push
 | |
|         #   pragma GCC diagnostic ignored "-Wsign-conversion"
 | |
|         #endif
 | |
|         if(sp.empty()) return;
 | |
|         m_stream.write(sp.str, sp.len);
 | |
|         m_pos += sp.len;
 | |
|         #if defined(__clang__)
 | |
|         #   pragma clang diagnostic pop
 | |
|         #elif defined(__GNUC__)
 | |
|         #   pragma GCC diagnostic pop
 | |
|         #endif
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(const char c)
 | |
|     {
 | |
|         m_stream.put(c);
 | |
|         ++m_pos;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(RepC const rc)
 | |
|     {
 | |
|         for(size_t i = 0; i < rc.num_times; ++i)
 | |
|         {
 | |
|             m_stream.put(rc.c);
 | |
|         }
 | |
|         m_pos += rc.num_times;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| /** a writer to a substr */
 | |
| struct WriterBuf
 | |
| {
 | |
|     substr m_buf;
 | |
|     size_t m_pos;
 | |
| 
 | |
|     WriterBuf(substr sp) : m_buf(sp), m_pos(0) {}
 | |
| 
 | |
|     inline substr _get(bool error_on_excess)
 | |
|     {
 | |
|         if(m_pos <= m_buf.len)
 | |
|         {
 | |
|             return m_buf.first(m_pos);
 | |
|         }
 | |
|         if(error_on_excess)
 | |
|         {
 | |
|             c4::yml::error("not enough space in the given buffer");
 | |
|         }
 | |
|         substr sp;
 | |
|         sp.str = nullptr;
 | |
|         sp.len = m_pos;
 | |
|         return sp;
 | |
|     }
 | |
| 
 | |
|     template<size_t N>
 | |
|     inline void _do_write(const char (&a)[N])
 | |
|     {
 | |
|         RYML_ASSERT( ! m_buf.overlaps(a));
 | |
|         if(m_pos + N-1 <= m_buf.len)
 | |
|         {
 | |
|             memcpy(&(m_buf[m_pos]), a, N-1);
 | |
|         }
 | |
|         m_pos += N-1;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(csubstr sp)
 | |
|     {
 | |
|         if(sp.empty()) return;
 | |
|         RYML_ASSERT( ! sp.overlaps(m_buf));
 | |
|         if(m_pos + sp.len <= m_buf.len)
 | |
|         {
 | |
|             memcpy(&(m_buf[m_pos]), sp.str, sp.len);
 | |
|         }
 | |
|         m_pos += sp.len;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(const char c)
 | |
|     {
 | |
|         if(m_pos + 1 <= m_buf.len)
 | |
|         {
 | |
|             m_buf[m_pos] = c;
 | |
|         }
 | |
|         ++m_pos;
 | |
|     }
 | |
| 
 | |
|     inline void _do_write(RepC const rc)
 | |
|     {
 | |
|         if(m_pos + rc.num_times <= m_buf.len)
 | |
|         {
 | |
|             for(size_t i = 0; i < rc.num_times; ++i)
 | |
|             {
 | |
|                 m_buf[m_pos + i] = rc.c;
 | |
|             }
 | |
|         }
 | |
|         m_pos += rc.num_times;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| } // namespace yml
 | |
| } // namespace c4
 | |
| 
 | |
| #endif /* _C4_YML_WRITER_HPP_ */
 | 
