Codebase list fish / debian/1.23.1-1 fish_indent.c
debian/1.23.1-1

Tree @debian/1.23.1-1 (Download .tar.gz)

fish_indent.c @debian/1.23.1-1raw · history · blame

/*
Copyright (C) 2005-2008 Axel Liljencrantz

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


/** \file fish_indent.c
	The fish_indent proegram.
*/

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <locale.h>

#include "fallback.h"
#include "util.h"
#include "common.h"
#include "wutil.h"
#include "halloc.h"
#include "halloc_util.h"
#include "tokenizer.h"
#include "print_help.h"
#include "parser_keywords.h"

/**
   The string describing the single-character options accepted by the main fish binary
*/
#define GETOPT_STRING "hvi"

/**
   Read the entire contents of a file into the specified string_Buffer_t
 */
static void read_file( FILE *f, string_buffer_t *b )
{
	while( 1 )
	{
		errno=0;
		wint_t c = fgetwc( f );
		if( c == WEOF )
		{
			if( errno )
			{
				wperror(L"fgetwc");
				exit(1);
			}
			
			break;
		}
		
		sb_append_char( b, c );
	}
}

/**
   Insert the specified number of tabe into the output buffer
 */
static void insert_tabs( string_buffer_t *out, int indent )
{
	int i;
	
	for( i=0; i<indent; i++ )
	{
		sb_append( out, L"\t" );
	}
	
}

/**
   Indent the specified input
 */
static int indent( string_buffer_t *out, wchar_t *in, int flags )
{
	tokenizer tok;
	int res=0;
	int is_command = 1;
	int indent = 0;
	int do_indent = 1;
	int prev_type = 0;
	int prev_prev_type = 0;

	tok_init( &tok, in, TOK_SHOW_COMMENTS );
	
	for( ; tok_has_next( &tok ); tok_next( &tok ) )
	{
		int type = tok_last_type( &tok );
		wchar_t *last = tok_last( &tok );
		
		switch( type )
		{
			case TOK_STRING:
			{
				if( is_command )
				{
					int next_indent = indent;
					is_command = 0;

					wchar_t *unesc = unescape( last, UNESCAPE_SPECIAL );
					
					if( parser_keywords_is_block( unesc ) )
					{
						next_indent++;
					}
					else if( wcscmp( unesc, L"else" ) == 0 )
					{
						indent--;
					}
					else if( wcscmp( unesc, L"end" ) == 0 )
					{
						indent--;
						next_indent--;
					}
					
	
					if( do_indent && flags)
					{
						insert_tabs( out, indent );
					}
					
					sb_printf( out, L"%ls", last );
					
					indent = next_indent;
					
				}
				else
				{
					sb_printf( out, L" %ls", last );
				}
				
				break;
			}
			
			case TOK_END:
			{
				if( prev_type != TOK_END || prev_prev_type != TOK_END ) 
					sb_append( out, L"\n" );
				do_indent = 1;
				is_command = 1;
				break;
			}

			case TOK_PIPE:
			{
				sb_append( out, L" | " );
				is_command = 1;
				break;
			}
			
			case TOK_REDIRECT_OUT:
			case TOK_REDIRECT_APPEND:
			case TOK_REDIRECT_IN:
			case TOK_REDIRECT_FD:
			{
				sb_append( out, last );
				switch( type )
				{
					case TOK_REDIRECT_OUT:
						sb_append( out, L"> " );
						break;
						
					case TOK_REDIRECT_APPEND:
						sb_append( out, L">> " );
						break;
						
					case TOK_REDIRECT_IN:
						sb_append( out, L"< " );
						break;
						
					case TOK_REDIRECT_FD:
						sb_append( out, L">& " );
						break;
															
				}
				break;
			}
			

			case TOK_BACKGROUND:
			{
				sb_append( out, L"&\n" );
				do_indent = 1;
				is_command = 1;
				break;
			}
			

			case TOK_COMMENT:
			{
				if( do_indent && flags)
				{
					insert_tabs( out, indent );
				}
				
				sb_printf( out, L"%ls", last );
				do_indent = 1;
				break;				
			}
			
			default:
			{
				debug( 0, L"Unknown token '%ls'", last );
				exit(1);
			}			
		}
		
		prev_prev_type = prev_type;
		prev_type = type;
		
	}
	
	tok_destroy( &tok );

	return res;
}

/**
   Remove any prefix and suffix newlines from the specified
   string. Does not allocete a new string, edits the string in place
   and returns a pointer somewhere into the string.
 */
static wchar_t *trim( wchar_t *in )
{
	wchar_t *end;
	
	while( *in == L'\n' )
	{
		in++;
	}
	
	end = in + wcslen(in);
		
	while( 1 )
	{
		if( end < in+2 )
			break;

		end--;
		
		if( (*end == L'\n' ) && ( *(end-1) == L'\n' ) )
			*end=0;
		else
			break;
	}
	
	return in;
}


/**
   The main mathod. Run the program.
 */
int main( int argc, char **argv )
{
	string_buffer_t sb_in;
	string_buffer_t sb_out;
	
	int do_indent=1;
	
	wsetlocale( LC_ALL, L"" );
	program_name=L"fish_indent";

	while( 1 )
	{
		static struct option
			long_options[] =
			{
				{
					"no-indent", no_argument, 0, 'i' 
				}
				,
				{
					"help", no_argument, 0, 'h' 
				}
				,
				{
					"version", no_argument, 0, 'v' 
				}
				,
				{ 
					0, 0, 0, 0 
				}
			}
		;
		
		int opt_index = 0;
		
		int opt = getopt_long( argc,
				       argv, 
				       GETOPT_STRING,
				       long_options, 
				       &opt_index );
		
		if( opt == -1 )
			break;
		
		switch( opt )
		{
			case 0:
			{
				break;
			}
			
			case 'h':
			{
				print_help( "fish_indent", 1 );
				exit( 0 );				
				break;
			}
			
			case 'v':
			{
				fwprintf( stderr, 
						  _(L"%ls, version %s\n"), 
						  program_name,
						  PACKAGE_VERSION );
				exit( 0 );				
			}

			case 'i':
			{
				do_indent = 0;
				break;
			}
			
			
			case '?':
			{
				exit( 1 );
			}
			
		}		
	}

	halloc_util_init();	

	sb_init( &sb_in );
	sb_init( &sb_out );

	read_file( stdin, &sb_in );
	
	wutil_init();

	if( !indent( &sb_out, (wchar_t *)sb_in.buff, do_indent ) )
	{
		fwprintf( stdout, L"%ls", trim( (wchar_t *)sb_out.buff) );
	}
	else
	{
		/*
		  Indenting failed - print original input
		*/
		fwprintf( stdout, L"%ls", (wchar_t *)sb_in.buff );
	}
	

	wutil_destroy();

	halloc_util_destroy();

	return 0;
}