# /// BEGIN_NOT_A2T ///
# /// END_NOT_A2T ///
# で囲った部分は変換を行なわないようにしました。

my @type_pairs = (
	["char","TCHAR"],
	["CHAR","TCHAR"],
	["PCHAR","PTCHAR"],
	["LPSTR","LPTSTR"],
	["LPCSTR","LPCTSTR"]
);

my @api_pairs = (
	["main","_tmain"],
	["WinMain","_tWinMain"],
	["environ","_tenviron"],
	["_environ","_tenviron"],
	["__argv","__targv"],
	["printf","_tprintf"],
	["fprintf","_ftprintf"],
	["sprintf","_stprintf"],
	["_snprintf","_sntprintf"],
	["vprintf","_vtprintf"],
	["vfprintf","_vftprintf"],
	["vsprintf","_vstprintf"],
	["_vsnprintf","_vsntprintf"],
	["scanf","_tscanf"],
	["fscanf","_ftscanf"],
	["sscanf","_stscanf"],
	["fgetc","_fgettc"],
	["_fgetchar","_fgettchar"],
	["fgets","_fgetts"],
	["fputc","_fputtc"],
	["_fputchar","_fputtchar"],
	["fputs","_fputts"],
	["getc","_gettc"],
	["getchar","_gettchar"],
	["gets","_getts"],
	["putc","_puttc"],
	["putchar","_puttchar"],
	["puts","_putts"],
	["ungetc","_ungettc"],
	["strtod","_tcstod"],
	["strtol","_tcstol"],
	["strtoul","_tcstoul"],
	["_itoa","_itot"],
	["_ltoa","_ltot"],
	["_ultoa","_ultot"],
	["atoi","_ttoi"],
	["atol","_ttol"],
	["_atoi64","_ttoi64"],
	["_i64toa","_i64tot"],
	["_ui64toa","_ui64tot"],
	["strcat","_tcscat"],
	["strcpy","_tcscpy"],
	["_strdup","_tcsdup"],
	["strlen","_tcslen"],
	["strxfrm","_tcsxfrm"],
	["_execl","_texecl"],
	["_execle","_texecle"],
	["_execlp","_texeclp"],
	["_execlpe","_texeclpe"],
	["_execv","_texecv"],
	["_execve","_texecve"],
	["_execvp","_texecvp"],
	["_execvpe","_texecvpe"],
	["_spawnl","_tspawnl"],
	["_spawnle","_tspawnle"],
	["_spawnlp","_tspawnlp"],
	["_spawnlpe","_tspawnlpe"],
	["_spawnv","_tspawnv"],
	["_spawnve","_tspawnve"],
	["_spawnvp","_tspawnvp"],
	["_spawnvpe","_tspawnvpe"],
	["system","_tsystem"],
	["asctime","_tasctime"],
	["ctime","_tctime"],
	["_strdate","_tstrdate"],
	["_strtime","_tstrtime"],
	["_utime","_tutime"],
	["strftime","_tcsftime"],
	["_chdir","_tchdir"],
	["_getcwd","_tgetcwd"],
	["_getdcwd","_tgetdcwd"],
	["_mkdir","_tmkdir"],
	["_rmdir","_trmdir"],
	["_fullpath","_tfullpath"],
	["getenv","_tgetenv"],
	["_makepath","_tmakepath"],
	["_putenv","_tputenv"],
	["_searchenv","_tsearchenv"],
	["_splitpath","_tsplitpath"],
	["fdopen","_tfdopen"],
	["_fdopen","_tfdopen"],
	["_fsopen","_tfsopen"],
	["fopen","_tfopen"],
	["freopen","_tfreopen"],
	["perror","_tperror"],
	["_popen","_tpopen"],
	["_tempnam","_ttempnam"],
	["tmpnam","_ttmpnam"],
	["_chmod","_tchmod"],
	["_creat","_tcreat"],
	["_findfirst","_tfindfirst"],
	["_findfirsti64","_tfindfirsti64"],
	["_findnext","_tfindnext"],
	["_findnexti64","_tfindnexti64"],
	["_mktemp","_tmktemp"],
	["open","_topen"],
	["access","_taccess"],
	["_open","_topen"],
	["_access","_taccess"],
	["remove","_tremove"],
	["rename","_trename"],
	["_sopen","_tsopen"],
	["_unlink","_tunlink"],
	["_finddata_t","_tfinddata_t"],
	["_finddatai64_t","_tfinddatai64_t"],
	["isascii","_istascii"],
	["iscntrl","_istcntrl"],
	["isxdigit","_istxdigit"],
	["_stat","_tstat"],
	["_stati64","_tstati64"],
	["setlocale","_tsetlocale"],
	["_mbschr","_tcschr"],
	["_mbscspn","_tcscspn"],
	["_mbsnbcat","_tcsncat"],
	["_mbsnbcpy","_tcsncpy"],
	["_mbspbrk","_tcspbrk"],
	["_mbsrchr","_tcsrchr"],
	["_mbsspn","_tcsspn"],
	["_mbsstr","_tcsstr"],
	["_mbstok","_tcstok"],
	["_mbsnbset","_tcsnset"],
	["_mbsrev","_tcsrev"],
	["_mbsset","_tcsset"],
	["_mbscmp","_tcscmp"],
	["_mbsicmp","_tcsicmp"],
	["_mbsncmp","_tcsnccmp"],
	["_mbsnbcmp","_tcsncmp"],
	["_mbsnicmp","_tcsncicmp"],
	["_mbsnbicmp","_tcsnicmp"],
	["_mbscoll","_tcscoll"],
	["_mbsicoll","_tcsicoll"],
	["_mbsncoll","_tcsnccoll"],
	["_mbsnbcoll","_tcsncoll"],
	["_mbsnicoll","_tcsncicoll"],
	["_mbsnbicoll","_tcsnicoll"],
	["_mbslen","_tcsclen"],
	["_mbsncat","_tcsnccat"],
	["_mbsncpy","_tcsnccpy"],
	["_mbsnset","_tcsncset"],
	["_mbsdec","_tcsdec"],
	["_mbsinc","_tcsinc"],
	["_mbsnbcnt","_tcsnbcnt"],
	["_mbsnccnt","_tcsnccnt"],
	["_mbsnextc","_tcsnextc"],
	["_mbsninc","_tcsninc"],
	["_mbsspnp","_tcsspnp"],
	["_mbslwr","_tcslwr"],
	["_mbsupr","_tcsupr"],
	["_mbclen","_tclen"],
	["_mbccpy","_tccpy"],
	["_ismbcalnum","_istalnum"],
	["_ismbcalpha","_istalpha"],
	["_ismbcdigit","_istdigit"],
	["_ismbcgraph","_istgraph"],
	["_ismbclegal","_istlegal"],
	["_ismbclower","_istlower"],
	["_ismbcprint","_istprint"],
	["_ismbcpunct","_istpunct"],
	["_ismbcspace","_istspace"],
	["_ismbcupper","_istupper"],
	["_mbctoupper","_totupper"],
	["_mbctolower","_totlower"],
	["_ismbblead","_istlead"],
	["isleadbyte","_istleadbyte"],
	["strchr","_tcschr"],
	["strcspn","_tcscspn"],
	["strncat","_tcsncat"],
	["strncpy","_tcsncpy"],
	["strpbrk","_tcspbrk"],
	["strrchr","_tcsrchr"],
	["strspn","_tcsspn"],
	["strstr","_tcsstr"],
	["strtok","_tcstok"],
	["_strnset","_tcsnset"],
	["_strrev","_tcsrev"],
	["_strset","_tcsset"],
	["strcmp","_tcscmp"],
	["_stricmp","_tcsicmp"],
	["strncmp","_tcsnccmp"],
	["strncmp","_tcsncmp"],
	["_strnicmp","_tcsncicmp"],
	["_strnicmp","_tcsnicmp"],
	["strcoll","_tcscoll"],
	["_stricoll","_tcsicoll"],
	["_strncoll","_tcsnccoll"],
	["_strncoll","_tcsncoll"],
	["_strnicoll","_tcsncicoll"],
	["_strnicoll","_tcsnicoll"],
	["strlen","_tcsclen"],
	["strncat","_tcsnccat"],
	["strncpy","_tcsnccpy"],
	["_strnset","_tcsncset"],
	["_strdec","_tcsdec"],
	["_strinc","_tcsinc"],
	["_strncnt","_tcsnbcnt"],
	["_strncnt","_tcsnccnt"],
	["_strnextc","_tcsnextc"],
	["_strninc","_tcsninc"],
	["_strspnp","_tcsspnp"],
	["_strlwr","_tcslwr"],
	["_strupr","_tcsupr"],
	["strxfrm","_tcsxfrm"],
	["isalnum","_istalnum"],
	["isalpha","_istalpha"],
	["isdigit","_istdigit"],
	["isgraph","_istgraph"],
	["islower","_istlower"],
	["isprint","_istprint"],
	["ispunct","_istpunct"],
	["isspace","_istspace"],
	["isupper","_istupper"],
	["toupper","_totupper"],
	["tolower","_totlower"]
);


if( $#ARGV == -1 ){
	print "usage: a2t.pl [ files | directories ]...\n";
	exit;
}

my $no_transform = FALSE;

foreach ( @ARGV ){
	if( -d ){
		&enum_file( $_ );
	}elsif( -e ){
		&replace_file( $_ );
	}
}

sub enum_file {
	my $path = shift;
	print "scanning \"".$path."\"\n";

	opendir DIR, $path;
	my @subdir = ();
	my $file;
	while( $name = readdir DIR ){
		my $file = $path."\\".$name;
		if( -d $file and $name !~ /^\.\.?$/ ){
			push( @subdir, $file );
		}
		elsif( $name =~ /\.[ch](?:pp)?$/ ){
			&replace_file( $file );
		}
	}
	closedir DIR;
	foreach( @subdir ){
		&enum_file( $_ );
	}
}

sub replace_file {
	my $path = shift;
	print "replace \"".$path."\"\n";
	
	my $path_bak = $path.".bak";
	rename $path, $path_bak;
	open IN, $path_bak;
	open OUT, ">".$path;
	foreach( <IN> ){
		my $line = replace_line( $_ );
		print OUT $line;
	}
	close OUT;
	close IN;
}

sub replace_line {
	my $line = shift;
	
	my $sp = qr/[\s\t]/;
	my $switch = qr/$sp*\/{3}$sp*/;
	my $begin_not_a2t = qr/^$switch(?:BEGIN_NOT_A2T)$switch/;
	my $end_not_a2t = qr/^$switch(?:END_NOT_A2T)$switch/;
	if( $line =~ /$begin_not_a2t/ ){
		$no_transform = TRUE;
		return $line;
	}elsif( $line =~ /$end_not_a2t/ ){
		$no_transform = FALSE;
		return $line;
	}
	if( $no_transform eq TRUE ){
		return $line;
	}

	my $literal = qr/\"(?:\\\"|[^\"])*\"|\'(?:\\.|[^\'\\])\'|__(?:FILE|LINE|DATE|TIME|TIMESTAMP)__/;
	my $comment = qr/\/\/.*$/;
	return $line if $line =~ /^$sp*#/;	# not プリプロセッサ
	return $line if $line =~ /static$sp+char$sp+THIS_FILE/;	# THIS_FILE の宣言は飛ばす
	
	# コメントがある場合は退避 手抜きなので /* */ の中身は置き換えられてしまいます。
	$line =~ /$comment/;
	my $comment_backup = $&;
	
	for my $i( 0..$#type_pairs ){
		$line =~ s/(?<!\w)$type_pairs[$i][0](?!\w)/$type_pairs[$i][1]/g;
	}
	
	# まず全ての _T マクロを取り除いてしまう
	my $t_macro = qr/(?:_?_T|_?TEXT)\(($sp*$literal$sp*)\)/;
	$line =~ s/(?<!\w)$t_macro/$1/g;
	
	# あらためて _T を付加
	$line =~ s/(?<!L)$literal/_T($&)/g;
	
	# TRACEn マクロなどはお節介なことに内部で _T で括っているので元に戻す
	# GetProcAddress などもついでに戻す
	my $trace_macro = qr/(?<!\w)((?:(?:TRACE|AFX_DUMP)\d|GetProcAddress)\($sp*)((?:$t_macro|\w+|$sp*,$sp*)+)($sp*\))/;
	while( $line =~ /$trace_macro/ ){
		my $trace_rep = $2;
		$trace_rep =~ s/(?<!\w)$t_macro/$1/g;
		$line =~ s/$trace_macro/$1$trace_rep$4/;
	}
	
	# コメントを元に戻す
	$line =~ s/$comment/$comment_backup/;

	# API を置き換え
	for my $i( 0..$#api_pairs ){
		$line =~ s/(?<!\w)$api_pairs[$i][0](?=$sp*\()/$api_pairs[$i][1]/g;
	}

	return $line;
}