mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-14 17:07:44 +00:00
402 lines
6.7 KiB
C++
402 lines
6.7 KiB
C++
/*
|
|
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 "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--;
|
|
}
|
|
/* case should have the same indent level as switch*/
|
|
else if( wcscmp( unesc, L"case" ) == 0 )
|
|
{
|
|
indent--;
|
|
}
|
|
else if( wcscmp( unesc, L"end" ) == 0 )
|
|
{
|
|
indent--;
|
|
next_indent--;
|
|
}
|
|
|
|
|
|
if( do_indent && flags && prev_type != TOK_PIPE )
|
|
{
|
|
insert_tabs( out, indent );
|
|
}
|
|
|
|
sb_printf( out, L"%ls", last );
|
|
|
|
indent = next_indent;
|
|
|
|
}
|
|
else
|
|
{
|
|
if ( prev_type != TOK_REDIRECT_FD )
|
|
sb_append( out, L" " );
|
|
sb_append( out, 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" " );
|
|
if ( last[0] == '2' && !last[1] ) {
|
|
sb_append( out, L"^" );
|
|
} else if ( last[0] != '1' || last[1] ) {
|
|
sb_append( out, last, L">" );
|
|
}
|
|
sb_append( out, L" | " );
|
|
is_command = 1;
|
|
break;
|
|
}
|
|
|
|
case TOK_REDIRECT_OUT:
|
|
{
|
|
sb_append( out, L" " );
|
|
if ( wcscmp( last, L"2" ) == 0 ) {
|
|
sb_append( out, L"^" );
|
|
} else {
|
|
if ( wcscmp( last, L"1" ) != 0 )
|
|
sb_append( out, last );
|
|
sb_append( out, L"> " );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TOK_REDIRECT_APPEND:
|
|
{
|
|
sb_append( out, L" " );
|
|
if ( wcscmp( last, L"2" ) == 0 ) {
|
|
sb_append( out, L"^^" );
|
|
} else {
|
|
if ( wcscmp( last, L"1" ) != 0 )
|
|
sb_append( out, last );
|
|
sb_append( out, L">> " );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TOK_REDIRECT_IN:
|
|
{
|
|
sb_append( out, L" " );
|
|
if ( wcscmp( last, L"0" ) != 0 )
|
|
sb_append( out, last );
|
|
sb_append( out, L"< " );
|
|
break;
|
|
}
|
|
|
|
case TOK_REDIRECT_FD:
|
|
{
|
|
sb_append( out, L" " );
|
|
if ( wcscmp( last, L"1" ) != 0 )
|
|
sb_append( out, last );
|
|
sb_append( out, L">& " );
|
|
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;
|
|
set_main_thread();
|
|
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 );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
return 0;
|
|
}
|