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_ */
 |