tools

various tools
git clone git://deadbeef.fr/tools.git
Log | Files | Refs | README | LICENSE

utils.cpp (3819B)


      1 // Copyright (c) 2020 Morel BĂ©renger
      2 // 
      3 // This software is provided 'as-is', without any express or implied
      4 // warranty. In no event will the authors be held liable for any damages
      5 // arising from the use of this software.
      6 // 
      7 // Permission is granted to anyone to use this software for any purpose,
      8 // including commercial applications, and to alter it and redistribute it
      9 // freely, subject to the following restrictions:
     10 // 
     11 // 1. The origin of this software must not be misrepresented; you must not
     12 //    claim that you wrote the original software. If you use this software
     13 //    in a product, an acknowledgment in the product documentation would be
     14 //    appreciated but is not required.
     15 // 2. Altered source versions must be plainly marked as such, and must not be
     16 //    misrepresented as being the original software.
     17 // 3. This notice may not be removed or altered from any source distribution.
     18 
     19 #include <stdio.h>
     20 #include <errno.h>
     21 #include <limits.h>
     22 #include <assert.h>
     23 #include <string.h>
     24 
     25 #include <iterator>
     26 #include <algorithm>
     27 
     28 #include "utils.hpp"
     29 
     30 #include <sys/ioctl.h>
     31 #include <termios.h>
     32 
     33 //would probably be better without that many ifs
     34 int esc_fputs( const char *s, FILE *stream )
     35 {
     36 	assert( s && stream && "nullpointer provided to esc_fputs" );
     37 	if( !( s && stream ) )
     38 	{
     39 		errno = EINVAL;
     40 		return EOF;
     41 	}
     42 
     43 	const char *str_end = s + strlen( s );
     44 	const char *chunk_start = s;
     45 	const char *chunk_end;
     46 	char bslash[2] = { '\\', '\\' };
     47 	char tohex [4] = { '\\', 'x', 0, 0 };
     48 	char ch;
     49 	char const* buf;
     50 	size_t sz;
     51 
     52 	do
     53 	{
     54 		chunk_end = std::find_if( chunk_start, str_end, []( const char c ){ return c < 0x20 || c == '\\'; } );
     55 		assert( chunk_end - chunk_start >= 0 );
     56 		sz = static_cast<size_t>( chunk_end - chunk_start );
     57 		if( sz != 0 && !fwrite( chunk_start, sz, 1, stream ) )
     58 		{
     59 			return INT_MAX;
     60 		}
     61 		if( chunk_end != str_end )
     62 		{
     63 			ch = *chunk_end;
     64 			buf = bslash;
     65 			sz = sizeof( bslash );
     66 			if( ch != '\\' )
     67 			{
     68 				buf = tohex;
     69 				sz = sizeof( tohex );
     70 				//quick'n dirty ascii to hex convertion for values < 0x20 (space)
     71 				tohex[2] = '0' + ( ch >> 4 );
     72 				ch &= 0x0F;
     73 				tohex[3] = ch + '0' + ( ch > 9 ? 'A' - ( '9' + 1 ) : 0 );
     74 			}
     75 			if( !fwrite( buf, sz, 1, stream ) )
     76 			{
     77 				return INT_MAX;
     78 			}
     79 			++chunk_end;
     80 		}
     81 		chunk_start = chunk_end;
     82 	} while( chunk_start != str_end );
     83 	return 0;
     84 }
     85 
     86 size_t ungets( char const* const str, size_t str_sz )
     87 {
     88 	// reverse push, since otherwise one would start with EOF
     89 	for( size_t i = str_sz; i; --i )
     90 	{
     91 		if( EOF == ungetc( str[i-1], stdin ) )
     92 		{
     93 			return i;
     94 		}
     95 	}
     96 	return 0;
     97 }
     98 
     99 bool term_ch_size( uint16_t *w, uint16_t *h, int fd )
    100 {
    101 	struct winsize wsz;
    102 	if( -1 == ioctl( fd, TIOCGWINSZ, &wsz ) )
    103 	{
    104 		return true;
    105 	}
    106 	*w = wsz.ws_col;
    107 	*h = wsz.ws_row;
    108 	return false;
    109 }
    110 
    111 bool indent_txt( char const* txt, char const* end, uint8_t level, uint16_t max_width, uint8_t tab_width, FILE* target )
    112 {
    113 	uint16_t indent_size = tab_width * level;
    114 	//bad args
    115 	if( !txt || !target )
    116 	{
    117 		return true;
    118 	}
    119 	//overflow
    120 	if( indent_size < tab_width || indent_size < level )
    121 	{
    122 		return true;
    123 	}
    124 	//indent wider than screen
    125 	if( indent_size > max_width )
    126 	{
    127 		return true;
    128 	}
    129 	max_width -= indent_size;
    130 	assert( max_width > 0 );
    131 
    132 	uint16_t pos        = 0;
    133 	uint16_t last_blank = 0;
    134 	char const* ptr = txt;
    135 	for( ; ptr != end; ++ptr, ++pos )
    136 	{
    137 		if( isblank( *ptr ) )
    138 		{
    139 			last_blank = pos;
    140 		}
    141 
    142 		if( *ptr == '\n' || pos == max_width )
    143 		{
    144 			if( *ptr != '\n' && last_blank != 0 )
    145 			{
    146 				assert( pos >= last_blank );
    147 				ptr -= pos - last_blank;
    148 				pos = last_blank;
    149 			}
    150 			for( uint8_t l = 0; l < level; ++l )
    151 			{
    152 				fputc( '\t', target );
    153 			}
    154 			fprintf( target, "%.*s", pos, txt );
    155 			last_blank = 0;
    156 			pos = 0;
    157 			txt = ptr + 1;
    158 			if( *ptr != '\n' )
    159 			{
    160 				fputc( '\n', target );
    161 			}
    162 		}
    163 	}
    164 	return false;
    165 }