2007-04-22 20:03:12 +10:00
/*
2008-01-13 05:18:48 +10:00
Copyright ( C ) 2005 - 2008 Axel Liljencrantz
2007-04-22 20:03:12 +10:00
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 .
*/
2012-02-22 12:00:02 -08:00
/** \file fish_indent.cpp
2012-11-18 11:23:22 +01:00
The fish_indent proegram .
2007-04-22 20:03:12 +10:00
*/
# 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"
2008-01-14 02:47:47 +10:00
/**
2012-02-22 12:00:02 -08:00
Read the entire contents of a file into the specified string
2008-01-14 02:47:47 +10:00
*/
2012-11-18 16:30:30 -08:00
static void read_file ( FILE * f , wcstring & b )
2007-04-22 20:03:12 +10:00
{
2012-11-18 16:30:30 -08:00
while ( 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
errno = 0 ;
wint_t c = fgetwc ( f ) ;
if ( c = = WEOF )
{
if ( errno )
{
wperror ( L " fgetwc " ) ;
exit ( 1 ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
break ;
}
b . push_back ( ( wchar_t ) c ) ;
2012-11-18 11:23:22 +01:00
}
2007-04-22 20:03:12 +10:00
}
2008-01-14 02:47:47 +10:00
/**
2012-02-22 12:00:02 -08:00
Insert the specified number of tabs into the output buffer
2008-01-14 02:47:47 +10:00
*/
2012-11-18 16:30:30 -08:00
static void insert_tabs ( wcstring & out , int indent )
2007-04-22 20:03:12 +10:00
{
2012-08-05 13:24:33 -07:00
if ( indent > 0 )
out . append ( ( size_t ) indent , L ' \t ' ) ;
2012-11-18 11:23:22 +01:00
2007-04-22 20:03:12 +10:00
}
2008-01-14 02:47:47 +10:00
/**
Indent the specified input
*/
2012-11-18 16:30:30 -08:00
static int indent ( wcstring & out , const wcstring & in , int flags )
2007-04-22 20:03:12 +10:00
{
2012-11-18 16:30:30 -08:00
int res = 0 ;
int is_command = 1 ;
int indent = 0 ;
int do_indent = 1 ;
int prev_type = 0 ;
int prev_prev_type = 0 ;
2012-11-21 17:48:35 -08:00
tokenizer_t tok ( in . c_str ( ) , TOK_SHOW_COMMENTS ) ;
2012-11-18 16:30:30 -08:00
for ( ; tok_has_next ( & tok ) ; tok_next ( & tok ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
int type = tok_last_type ( & tok ) ;
2012-11-21 22:09:35 -08:00
const wchar_t * last = tok_last ( & tok ) ;
2012-11-18 16:30:30 -08:00
switch ( type )
{
2012-11-19 00:31:03 -08:00
case TOK_STRING :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
if ( is_command )
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
int next_indent = indent ;
is_command = 0 ;
wcstring unesc = last ;
unescape_string ( unesc , UNESCAPE_SPECIAL ) ;
if ( parser_keywords_is_block ( unesc ) )
{
next_indent + + ;
}
else if ( unesc = = L " else " )
{
indent - - ;
}
/* case should have the same indent level as switch*/
else if ( unesc = = L " case " )
{
indent - - ;
}
else if ( unesc = = L " end " )
{
indent - - ;
next_indent - - ;
}
if ( do_indent & & flags & & prev_type ! = TOK_PIPE )
{
insert_tabs ( out , indent ) ;
}
append_format ( out , L " %ls " , last ) ;
indent = next_indent ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
}
else
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
if ( prev_type ! = TOK_REDIRECT_FD )
out . append ( L " " ) ;
out . append ( last ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case TOK_END :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
if ( prev_type ! = TOK_END | | prev_prev_type ! = TOK_END )
out . append ( L " \n " ) ;
do_indent = 1 ;
is_command = 1 ;
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case TOK_PIPE :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
out . append ( L " " ) ;
if ( last [ 0 ] = = ' 2 ' & & ! last [ 1 ] )
{
out . append ( L " ^ " ) ;
}
else if ( last [ 0 ] ! = ' 1 ' | | last [ 1 ] )
{
out . append ( last ) ;
out . append ( L " > " ) ;
}
out . append ( L " | " ) ;
is_command = 1 ;
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case TOK_REDIRECT_OUT :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
out . append ( L " " ) ;
if ( wcscmp ( last , L " 2 " ) = = 0 )
{
out . append ( L " ^ " ) ;
}
else
{
if ( wcscmp ( last , L " 1 " ) ! = 0 )
out . append ( last ) ;
out . append ( L " > " ) ;
}
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case TOK_REDIRECT_APPEND :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
out . append ( L " " ) ;
if ( wcscmp ( last , L " 2 " ) = = 0 )
{
out . append ( L " ^^ " ) ;
}
else
{
if ( wcscmp ( last , L " 1 " ) ! = 0 )
out . append ( last ) ;
out . append ( L " >> " ) ;
}
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case TOK_REDIRECT_IN :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
out . append ( L " " ) ;
if ( wcscmp ( last , L " 0 " ) ! = 0 )
2012-11-18 16:30:30 -08:00
out . append ( last ) ;
2012-11-19 00:31:03 -08:00
out . append ( L " < " ) ;
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case TOK_REDIRECT_FD :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
out . append ( L " " ) ;
2012-11-18 16:30:30 -08:00
if ( wcscmp ( last , L " 1 " ) ! = 0 )
out . append ( last ) ;
2012-11-19 00:31:03 -08:00
out . append ( L " >& " ) ;
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case TOK_BACKGROUND :
{
out . append ( L " & \n " ) ;
do_indent = 1 ;
is_command = 1 ;
break ;
}
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case TOK_COMMENT :
{
if ( do_indent & & flags )
{
insert_tabs ( out , indent ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
append_format ( out , L " %ls " , last ) ;
do_indent = 1 ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
default :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
debug ( 0 , L " Unknown token '%ls' " , last ) ;
exit ( 1 ) ;
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
prev_prev_type = prev_type ;
prev_type = type ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return res ;
2007-04-22 20:03:12 +10:00
}
2008-01-14 02:47:47 +10:00
/**
Remove any prefix and suffix newlines from the specified
2012-02-22 12:00:02 -08:00
string .
2008-01-14 02:47:47 +10:00
*/
2012-11-18 16:30:30 -08:00
static void trim ( wcstring & str )
2007-04-23 04:54:29 +10:00
{
2012-02-22 12:00:02 -08:00
if ( str . empty ( ) )
return ;
2007-04-23 04:54:29 +10:00
2012-02-22 12:00:02 -08:00
size_t pos = str . find_first_not_of ( L " \n " ) ;
if ( pos > 0 )
str . erase ( 0 , pos ) ;
2012-11-18 11:23:22 +01:00
2012-02-22 12:00:02 -08:00
pos = str . find_last_not_of ( L " \n " ) ;
if ( pos ! = wcstring : : npos & & pos + 1 < str . length ( ) )
str . erase ( pos + 1 ) ;
2007-04-23 04:54:29 +10:00
}
2008-01-14 02:47:47 +10:00
/**
The main mathod . Run the program .
*/
2012-11-18 16:30:30 -08:00
int main ( int argc , char * * argv )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
int do_indent = 1 ;
set_main_thread ( ) ;
2012-03-07 11:35:22 -08:00
setup_fork_guards ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wsetlocale ( LC_ALL , L " " ) ;
program_name = L " fish_indent " ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( 1 )
{
static struct option
long_options [ ] =
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
{
" no-indent " , no_argument , 0 , ' i '
}
,
{
" help " , no_argument , 0 , ' h '
}
,
{
" version " , no_argument , 0 , ' v '
}
,
{
0 , 0 , 0 , 0
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
;
int opt_index = 0 ;
int opt = getopt_long ( argc ,
argv ,
GETOPT_STRING ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
2012-11-18 11:23:22 +01:00
{
2012-11-19 00:31:03 -08:00
case 0 :
{
break ;
}
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' h ' :
{
print_help ( " fish_indent " , 1 ) ;
exit ( 0 ) ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' v ' :
{
fwprintf ( stderr ,
_ ( L " %ls, version %s \n " ) ,
program_name ,
PACKAGE_VERSION ) ;
exit ( 0 ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' i ' :
{
do_indent = 0 ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' ? ' :
{
exit ( 1 ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2007-04-22 20:03:12 +10:00
2012-02-22 12:00:02 -08:00
wcstring sb_in , sb_out ;
2012-11-18 16:30:30 -08:00
read_file ( stdin , sb_in ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wutil_init ( ) ;
2007-04-22 20:03:12 +10:00
2012-11-18 16:30:30 -08:00
if ( ! indent ( sb_out , sb_in , do_indent ) )
{
2012-02-22 12:00:02 -08:00
trim ( sb_out ) ;
2012-11-18 16:30:30 -08:00
fwprintf ( stdout , L " %ls " , sb_out . c_str ( ) ) ;
}
else
{
/*
Indenting failed - print original input
*/
fwprintf ( stdout , L " %ls " , sb_in . c_str ( ) ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wutil_destroy ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return 0 ;
2007-04-22 20:03:12 +10:00
}