#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <limits.h>
int islsflag( char * arg) ;
int printout( char * dir, int Rflag, int lflag, int gflag) ;
int main( int argc, char ** argv) {
int lflag= 0 , gflag= 0 , Rflag= 0 ;
int argexist= 0 ; //флаг существования аргументов - каталогов
for ( int i= 1 ; i< argc; i++ )
if ( islsflag( argv[ i] ) ) {
char c;
for ( int j= 1 ; ( c= argv[ i] [ j] ) != '\0 ' ; j++ ) {
if ( c== 'l' ) lflag= 1 ;
else if ( c== 'g' ) gflag= 1 ;
if ( c== 'R' ) Rflag= 1 ;
}
}
else argexist= 1 ;
if ( lflag && gflag) {
fprintf ( stderr
, "ls: wrong usage of flags" ) ; return 1 ;
}
char l[ PATH_MAX] ;
getcwd( l, PATH_MAX) ;
if ( argexist) {
for ( int i= 1 ; i< argc; i++ ) if ( ! islsflag( argv[ i] ) ) {
char s[ PATH_MAX] ;
if ( ! Rflag
) printf ( "%s:\n " , argv
[ i
] ) ; if ( ! islsflag( argv[ i] ) && printout( s, Rflag, lflag, gflag) )
return 1 ; //в printout произошла ошибка
}
return 0 ; //ошибок не произошло
}
return printout( l, Rflag, lflag, gflag) ;
}
/* возвращает 0, если аргумент - не флаг, и 1 - если флаг*/
int islsflag( char * arg) {
if ( arg[ 0 ] == '-' ) {
char c;
for ( int j= 1 ; ( c= arg[ j] ) != '\0 ' ; j++ ) {
if ( ( c!= 'l' ) && ( c!= 'g' ) && ( c!= 'R' ) )
return 0 ;
}
return 1 ;
}
return 0 ;
}
/* показать тип файла в первой позиции выходной строки */
void display_file_type( int st_mode) {
switch ( st_mode & S_IFMT ) {
case S_IFDIR
: putchar ( 'd' ) ; return ; case S_IFCHR
: putchar ( 'c' ) ; return ; case S_IFBLK
: putchar ( 'b' ) ; return ; case S_IFREG
: putchar ( '-' ) ; return ; case S_IFLNK
: putchar ( 'l' ) ; return ; case S_IFSOCK
: putchar ( 's' ) ; return ; }
}
/* показать права доступа для владельца, группы и прочих пользователей, а также все спец.флаги*/
void display_permission( int st_mode) {
static const char rwxmas[ 10 ] = "rwxrwxrwx" ;
char amode[ 10 ] ;
int i, j;
for ( i = 0 , j = ( 1 << 8 ) ; i < 9 ; i++, j >>= 1 )
amode[ i] = ( st_mode& j) ? rwxmas[ i] : '-' ;
if ( st_mode & S_ISUID ) amode[ 2 ] = 's' ;
if ( st_mode & S_ISGID ) amode[ 5 ] = 's' ;
if ( st_mode & S_ISVTX ) amode[ 8 ] = 't' ;
amode[ 9 ] = '\0 ' ;
}
char * settime( struct tm * u) {
char * s;
int size= 20 ;
char * tmp;
int length;
while ( ! ( length
= strftime ( s
, size
, "%d.%m.%Y %H:%M:%S" , u
) ) ) { size+= 10 ;
}
/* в строку s скопируем строку из кавычек, заменяя спецификаторы
* данными из структуры времени, не более size символов*/
return ( tmp) ;
}
/* перечислить атрибуты одного файла*/
/* от lflag (0 или 1) зависит, будет ли выводиться имя владельца*/
void long_list( char * path_name, char * fname, int lflag) {
struct stat statv;
struct passwd * pw_d;
struct group * grpv;
struct tm * timev;
if ( lstat( path_name,& statv) ) {
return ;
}
display_file_type( statv.st_mode ) ;
display_permission( statv.st_mode ) ;
printf ( "%4ld " , statv.
st_nlink ) ; /*значение счетчика жестких связей*/
if ( lflag) {
if ( ( pw_d= getpwuid( statv.st_uid ) ) == NULL) {
/* преобразовать UID в имя пользователя*/
return ;
}
}
if ( ( grpv= getgrgid( statv.st_gid ) ) == NULL) {
/* преобразовать gid в имя группы*/
return ;
}
/* показать размер файла*/
printf ( "%8ld " , statv.
st_size ) ;
/* показать время последнего изменения файла*/
const time_t
ctime = statv.
st_ctime ; char * strtime= settime( timev) ;
/* показать имя файла*/
}
/* вывод, возвращает 0, если ошибок нет, 1 - если есть*/
int printout( char * dir, int Rflag, int lflag, int gflag) {
DIR * d;
struct dirent * dd;
off_t o;
struct stat s;
char name[ PATH_MAX] ;
char * delim= "/" ;
/* если в качестве каталога передан корневой, то разделитель '/' не нужен*/
if ( ! strcmp ( dir
, "/" ) ) delim
= "" ;
if ( ! ( d= opendir( dir) ) ) {
return 1 ;
}
if ( Rflag
) printf ( "%s:\n " , dir
) ; while ( ( dd= readdir( d) ) ) {
continue ;
//сформируем полный путь
snprintf ( name
, PATH_MAX
, "%s%s%s" , dir
, delim
, dd
-> d_name
) ;
if ( lstat( name, & s) < 0 )
continue ;
if ( lflag || gflag) {
long_list( name, dd-> d_name, lflag) ; //вывод полной информации
}
else
printf ( "%s " , dd
-> d_name
) ; //только имя }
if ( ! lflag
&& ! gflag
) printf ( "\n " ) ;
if ( ! Rflag) return 0 ;
seekdir( d, 0 ) ;
snprintf ( name
, PATH_MAX
, "%s%s" , dir
, delim
) ; while ( ( dd= readdir( d) ) ) {
continue ;
char mas[ PATH_MAX] ;
if ( lstat( mas, & s) < 0 )
continue ;
if ( S_ISDIR( s.st_mode ) ) {
//если это каталог
char mas[ PATH_MAX] ;
o= telldir( d) ; //запомнить место в записи
closedir( d) ; //для экономии дескрипторов
chdir( mas) ;
if ( printout( mas, Rflag, lflag, gflag) ) return 1 ;
chdir( name) ;
//вернемся в прежнюю директорию
if ( ! ( d= opendir( dir) ) ) {
return 1 ;
}
seekdir( d, o) ; //вернуться на прежнее место
}
}
closedir( d) ;
return 0 ;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzeXMvdHlwZXMuaD4KI2luY2x1ZGUgPHN5cy9zdGF0Lmg+CiNpbmNsdWRlIDxwd2QuaD4KI2luY2x1ZGUgPGdycC5oPgojaW5jbHVkZSA8ZmNudGwuaD4KI2luY2x1ZGUgPGRpcmVudC5oPgojaW5jbHVkZSA8dW5pc3RkLmg+CiNpbmNsdWRlIDxzdHJpbmcuaD4KI2luY2x1ZGUgPHRpbWUuaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8bGltaXRzLmg+CgppbnQgaXNsc2ZsYWcoY2hhciAqIGFyZyk7CmludCBwcmludG91dChjaGFyICogZGlyLCBpbnQgUmZsYWcsIGludCBsZmxhZywgaW50IGdmbGFnKTsKCmludCBtYWluKGludCBhcmdjLGNoYXIgKiogYXJndil7CglpbnQgbGZsYWc9MCxnZmxhZz0wLFJmbGFnPTA7CglpbnQgYXJnZXhpc3Q9MDsgLy/QoeKAntCgwrvQoMKw0KDRliDQodCD0KHRk9Ch4oCw0KDCtdCh0IPQoeKAmtCg0IbQoNGV0KDQhtCgwrDQoNCF0KDRkdCh0I8g0KDCsNCh0ILQoNGW0KHRk9Cg0ZjQoMK10KDQhdCh4oCa0KDRldCg0IYgLSDQoNGU0KDCsNCh4oCa0KDCsNCgwrvQoNGV0KDRltCg0ZXQoNCGCglmb3IgKGludCBpPTE7aTxhcmdjO2krKykKCQlpZiAoaXNsc2ZsYWcoYXJndltpXSkpewoJCQljaGFyIGM7CgkJCWZvciAoaW50IGo9MTsoYz1hcmd2W2ldW2pdKSE9J1wwJztqKyspewoJCQkJaWYgKGM9PSdsJykgbGZsYWc9MTsKCQkJCWVsc2UgaWYgKGM9PSdnJykgZ2ZsYWc9MTsKCQkJCWlmIChjPT0nUicpIFJmbGFnPTE7CgkJCX0KCQl9CgkJZWxzZSBhcmdleGlzdD0xOwoJaWYgKGxmbGFnICYmIGdmbGFnKXsKCQlmcHJpbnRmKHN0ZGVyciwibHM6IHdyb25nIHVzYWdlIG9mIGZsYWdzIik7CgkJcmV0dXJuIDE7Cgl9CgogICAgICAgIGNoYXIgbFtQQVRIX01BWF07CglnZXRjd2QobCxQQVRIX01BWCk7CgoJaWYgKGFyZ2V4aXN0KXsKCQlmb3IgKGludCBpPTE7aTxhcmdjO2krKykgaWYgKCFpc2xzZmxhZyhhcmd2W2ldKSl7CgkJCWNoYXIgc1tQQVRIX01BWF07IAoJCQlzdHJjcHkocyxsKTsKCQkJc3RyY2F0KHMsIi8iKTsKCQkJc3RyY2F0KHMsYXJndltpXSk7CgkJCWlmICghUmZsYWcpIHByaW50ZigiJXM6XG4iLGFyZ3ZbaV0pOwoJCQlpZiAoIWlzbHNmbGFnKGFyZ3ZbaV0pICYmIHByaW50b3V0KHMsUmZsYWcsbGZsYWcsZ2ZsYWcpKQoJCQkJcmV0dXJuIDE7IC8v0KDQhiBwcmludG91dCDQoNGX0KHQgtCg0ZXQoNGR0KDCt9Cg0ZXQoeKCrNCgwrvQoMKwINCg0ZXQoeKCrNCg0ZHQoMKx0KDRlNCgwrAKCQl9CgkJcmV0dXJuIDA7IC8v0KDRldCh4oKs0KDRkdCgwrHQoNGV0KDRlCDQoNCF0KDCtSDQoNGX0KHQgtCg0ZXQoNGR0KDCt9Cg0ZXQoeKCrNCgwrvQoNGVCgl9CglyZXR1cm4gcHJpbnRvdXQobCxSZmxhZyxsZmxhZyxnZmxhZyk7Cgp9CgovKiDQoNCG0KDRldCgwrfQoNCG0KHQgtCgwrDQoeKAsNCgwrDQoMK10KHigJogMCwg0KDCtdCh0IPQoMK70KDRkSDQoMKw0KHQgtCg0ZbQodGT0KDRmNCgwrXQoNCF0KHigJogLSDQoNCF0KDCtSDQoeKAntCgwrvQoMKw0KDRliwg0KDRkSAxIC0g0KDCtdCh0IPQoMK70KDRkSDQoeKAntCgwrvQoMKw0KDRliovCmludCBpc2xzZmxhZyhjaGFyICogYXJnKXsKCWlmIChhcmdbMF09PSctJyl7CgkJY2hhciBjOwoJCWZvciAoaW50IGo9MTsoYz1hcmdbal0pIT0nXDAnO2orKyl7CgkJCWlmICggKGMhPSdsJykgJiYgKGMhPSdnJykgJiYgKGMhPSdSJykgKSAKCQkJCXJldHVybiAwOwoJCX0KCQlyZXR1cm4gMTsKCX0KCXJldHVybiAwOwp9CgovKiDQoNGX0KDRldCg0ZTQoMKw0KDCt9CgwrDQoeKAmtCh0Iog0KHigJrQoNGR0KDRlyDQoeKAntCgwrDQoOKEltCgwrvQoMKwINCg0IYg0KDRl9CgwrXQodCC0KDQhtCg0ZXQoOKEliDQoNGX0KDRldCgwrfQoNGR0KHigKDQoNGR0KDRkSDQoNCG0KHigLnQoeKAptCg0ZXQoNKR0KDQhdCg0ZXQoOKEliDQodCD0KHigJrQodCC0KDRldCg0ZTQoNGRICovCnZvaWQgZGlzcGxheV9maWxlX3R5cGUoaW50IHN0X21vZGUpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCglzd2l0Y2ggKCBzdF9tb2RlICYgU19JRk1UICl7CiAgICAgICAgCWNhc2UgU19JRkRJUjogIHB1dGNoYXIgKCAnZCcgKTsgcmV0dXJuOwoJICAgICAgICBjYXNlIFNfSUZDSFI6ICBwdXRjaGFyICggJ2MnICk7IHJldHVybjsKCSAgICAgICAgY2FzZSBTX0lGQkxLOiAgcHV0Y2hhciAoICdiJyApOyByZXR1cm47CgkgICAgICAgIGNhc2UgU19JRlJFRzogIHB1dGNoYXIgKCAnLScgKTsgcmV0dXJuOwoJICAgICAgICBjYXNlIFNfSUZMTks6ICBwdXRjaGFyICggJ2wnICk7IHJldHVybjsKCSAgICAgICAgY2FzZSBTX0lGU09DSzogcHV0Y2hhciAoICdzJyApOyByZXR1cm47Cgl9Cn0gCiAKLyog0KDRl9Cg0ZXQoNGU0KDCsNCgwrfQoMKw0KHigJrQodCKINCg0ZfQodCC0KDCsNCg0IbQoMKwINCg0pHQoNGV0KHQg9Ch4oCa0KHRk9Cg0ZfQoMKwINCg0pHQoMK70KHQjyDQoNCG0KDCu9CgwrDQoNKR0KDCtdCgwrvQodCK0KHigKDQoMKwLCDQoNGW0KHQgtCh0ZPQoNGX0KDRl9Ch4oC5INCg0ZEg0KDRl9Ch0ILQoNGV0KHigKHQoNGR0KHigKYgINCg0ZfQoNGV0KDCu9Ch0IrQoMK30KDRldCg0IbQoMKw0KHigJrQoMK10KDCu9CgwrXQoOKEliwg0KDCsCDQoeKAmtCgwrDQoNGU0KDCttCgwrUg0KDQhtCh0IPQoMK1INCh0IPQoNGX0KDCtdCh4oCgLtCh4oCe0KDCu9CgwrDQoNGW0KDRkSovCnZvaWQgZGlzcGxheV9wZXJtaXNzaW9uKGludCBzdF9tb2RlKXsKCXN0YXRpYyBjb25zdCBjaGFyIHJ3eG1hc1sxMF0gPSAicnd4cnd4cnd4IjsKCWNoYXIgICAgIGFtb2RlWzEwXTsKCWludCAgICAgIGksIGo7CgkgCglmb3IgKCBpID0gMCwgaiA9ICggMSA8PCA4ICk7IGkgPCA5OyBpKyssIGogPj49IDEgKQoJCWFtb2RlW2ldID0gKHN0X21vZGUmaikgPyByd3htYXNbaV06ICctJzsKCWlmICggc3RfbW9kZSAmIFNfSVNVSUQgKSAgIGFtb2RlWzJdPSAncyc7CglpZiAoIHN0X21vZGUgJiBTX0lTR0lEICkgICBhbW9kZVs1XT0gJ3MnOwoJaWYgKCBzdF9tb2RlICYgU19JU1ZUWCApICAgYW1vZGVbOF09ICd0JzsKCWFtb2RlWzldPSdcMCc7CglwcmludGYgKCAiJXMgIixhbW9kZSApOwp9CgpjaGFyICogc2V0dGltZShzdHJ1Y3QgdG0gKnUpewoJY2hhciAqczsKCWludCBzaXplPTIwOwoJY2hhciAqdG1wOwoJaW50IGxlbmd0aDsKCXM9KGNoYXIqKW1hbGxvYyhzaXplKTsKCgl3aGlsZSAoIShsZW5ndGg9c3RyZnRpbWUocyxzaXplLCIlZC4lbS4lWSAlSDolTTolUyIsdSkpKXsKCQlzaXplKz0xMDsKCQlzPShjaGFyKilyZWFsbG9jKHMsc2l6ZSk7Cgl9CgkvKiDQoNCGINCh0IPQoeKAmtCh0ILQoNGV0KDRlNCh0ZMgcyDQodCD0KDRlNCg0ZXQoNGX0KDRkdCh0ILQodGT0KDCtdCg0Zgg0KHQg9Ch4oCa0KHQgtCg0ZXQoNGU0KHRkyDQoNGR0KDCtyDQoNGU0KDCsNCg0IbQoeKAudCh4oCh0KDCtdCg0ZQsINCgwrfQoMKw0KDRmNCgwrXQoNCF0KHQj9Ch0I8g0KHQg9Cg0ZfQoMK10KHigKDQoNGR0KHigJ7QoNGR0KDRlNCgwrDQoeKAmtCg0ZXQodCC0KHigLkKCSAqINCg0pHQoMKw0KDQhdCg0IXQoeKAudCg0ZjQoNGRINCg0ZHQoMK3INCh0IPQoeKAmtCh0ILQodGT0KDRlNCh4oCa0KHRk9Ch0ILQoeKAuSDQoNCG0KHQgtCgwrXQoNGY0KDCtdCg0IXQoNGRLCDQoNCF0KDCtSDQoMKx0KDRldCgwrvQoMK10KDCtSBzaXplINCh0IPQoNGR0KDRmNCg0IbQoNGV0KDCu9Cg0ZXQoNCGKi8KCgl0bXA9KGNoYXIqKW1hbGxvYyhzaXplb2YocykpOwoJc3RyY3B5KHRtcCxzKTsKCXJldHVybih0bXApOwp9CgovKiDQoNGX0KDCtdCh0ILQoMK10KHigKHQoNGR0KHQg9CgwrvQoNGR0KHigJrQodCKINCgwrDQoeKAmtCh0ILQoNGR0KDCsdCh0ZPQoeKAmtCh4oC5INCg0ZXQoNKR0KDQhdCg0ZXQoNGW0KDRlSDQoeKAntCgwrDQoOKEltCgwrvQoMKwKi8KLyog0KDRldCh4oCaIGxmbGFnICgwINCg0ZHQoMK70KDRkSAxKSDQoMK30KDCsNCg0IbQoNGR0KHQg9Cg0ZHQoeKAmiwg0KDCsdCh0ZPQoNKR0KDCtdCh4oCaINCgwrvQoNGRINCg0IbQoeKAudCg0IbQoNGV0KDSkdCg0ZHQoeKAmtCh0IrQodCD0KHQjyDQoNGR0KDRmNCh0I8g0KDQhtCgwrvQoMKw0KDSkdCgwrXQoMK70KHQitCh4oCg0KDCsCovCnZvaWQgbG9uZ19saXN0KGNoYXIgKiBwYXRoX25hbWUsIGNoYXIgKiBmbmFtZSwgaW50IGxmbGFnKXsKCXN0cnVjdCBzdGF0ICAgICBzdGF0djsKCXN0cnVjdCBwYXNzd2QgICpwd19kOwoJc3RydWN0IGdyb3VwICAgKmdycHY7CglzdHJ1Y3QgdG0gICAgICAqdGltZXY7CgoJaWYgKGxzdGF0KHBhdGhfbmFtZSwmc3RhdHYpKXsKCQlwZXJyb3IocGF0aF9uYW1lKTsKCQlyZXR1cm47Cgl9CglkaXNwbGF5X2ZpbGVfdHlwZShzdGF0di5zdF9tb2RlKTsKCWRpc3BsYXlfcGVybWlzc2lvbihzdGF0di5zdF9tb2RlKTsKCXByaW50ZigiJTRsZCAiLHN0YXR2LnN0X25saW5rKTsgLyrQoMK30KDQhdCgwrDQoeKAodCgwrXQoNCF0KDRkdCgwrUg0KHQg9Ch4oCh0KDCtdCh4oCa0KHigKHQoNGR0KDRlNCgwrAg0KDCttCgwrXQodCD0KHigJrQoNGU0KDRkdCh4oCmINCh0IPQoNCG0KHQj9CgwrfQoMK10KDihJYqLwoKCWlmIChsZmxhZyl7CgkJaWYgKChwd19kPWdldHB3dWlkKHN0YXR2LnN0X3VpZCkpPT1OVUxMKXsgCgkJLyog0KDRl9Ch0ILQoMK10KDRldCgwrHQodCC0KDCsNCgwrfQoNGV0KDQhtCgwrDQoeKAmtCh0IogVUlEINCg0IYg0KDRkdCg0ZjQodCPINCg0ZfQoNGV0KDCu9Ch0IrQoMK30KDRldCg0IbQoMKw0KHigJrQoMK10KDCu9Ch0I8qLwoJCQlwZXJyb3IoIiIpOwoJCQlyZXR1cm47CgkJfQkgIAoJCXByaW50ZiAoIiVzICIscHdfZC0+cHdfbmFtZSk7ICAgCgl9CgoJaWYgKChncnB2PWdldGdyZ2lkKHN0YXR2LnN0X2dpZCkpPT1OVUxMKXsKCSAgLyog0KDRl9Ch0ILQoMK10KDRldCgwrHQodCC0KDCsNCgwrfQoNGV0KDQhtCgwrDQoeKAmtCh0IogZ2lkINCg0IYg0KDRkdCg0ZjQodCPINCg0ZbQodCC0KHRk9Cg0ZfQoNGX0KHigLkqLwoJCXBlcnJvcigiIik7CgkJcmV0dXJuOwoJfQoJcHJpbnRmKCIlcyAiLGdycHYtPmdyX25hbWUpOwoJCgkvKiDQoNGX0KDRldCg0ZTQoMKw0KDCt9CgwrDQoeKAmtCh0Iog0KHQgtCgwrDQoMK30KDRmNCgwrXQodCCINCh4oCe0KDCsNCg4oSW0KDCu9CgwrAqLwoJcHJpbnRmKCIlOGxkICIsc3RhdHYuc3Rfc2l6ZSk7CgkKCS8qINCg0ZfQoNGV0KDRlNCgwrDQoMK30KDCsNCh4oCa0KHQiiDQoNCG0KHQgtCgwrXQoNGY0KHQjyDQoNGX0KDRldCh0IPQoMK70KDCtdCg0pHQoNCF0KDCtdCg0ZbQoNGVINCg0ZHQoMK30KDRmNCgwrXQoNCF0KDCtdCg0IXQoNGR0KHQjyDQoeKAntCgwrDQoOKEltCgwrvQoMKwKi8KCWNvbnN0IHRpbWVfdCBjdGltZT1zdGF0di5zdF9jdGltZTsKCXRpbWV2PWxvY2FsdGltZSgmY3RpbWUpOwoJY2hhciAqIHN0cnRpbWU9c2V0dGltZSh0aW1ldik7CglwcmludGYoIiVzIixzdHJ0aW1lKTsKCgkvKiDQoNGX0KDRldCg0ZTQoMKw0KDCt9CgwrDQoeKAmtCh0Iog0KDRkdCg0ZjQodCPINCh4oCe0KDCsNCg4oSW0KDCu9CgwrAqLwoJcHJpbnRmKCIgJXNcbiIsIGZuYW1lKTsKfQoKCgovKiDQoNCG0KHigLnQoNCG0KDRldCg0pEsINCg0IbQoNGV0KDCt9Cg0IbQodCC0KDCsNCh4oCw0KDCsNCgwrXQoeKAmiAwLCDQoMK10KHQg9CgwrvQoNGRINCg0ZXQoeKCrNCg0ZHQoMKx0KDRldCg0ZQg0KDQhdCgwrXQoeKAmiwgMSAtINCgwrXQodCD0KDCu9Cg0ZEg0KDCtdCh0IPQoeKAmtCh0IoqLwppbnQgcHJpbnRvdXQoY2hhciAqIGRpcixpbnQgUmZsYWcsaW50IGxmbGFnLGludCBnZmxhZyl7CglESVIgKmQ7CglzdHJ1Y3QgZGlyZW50ICpkZDsKCW9mZl90IG87CglzdHJ1Y3Qgc3RhdCBzOwoJY2hhciBuYW1lW1BBVEhfTUFYXTsKCWNoYXIgKmRlbGltPSIvIjsKCQoJLyog0KDCtdCh0IPQoMK70KDRkSDQoNCGINCg0ZTQoMKw0KHigKHQoMK10KHQg9Ch4oCa0KDQhtCgwrUg0KDRlNCgwrDQoeKAmtCgwrDQoMK70KDRldCg0ZbQoMKwINCg0ZfQoMK10KHQgtCgwrXQoNKR0KDCsNCg0IUg0KDRlNCg0ZXQodCC0KDQhdCgwrXQoNCG0KDRldCg4oSWLCDQoeKAmtCg0ZUg0KHQgtCgwrDQoMK30KDSkdCgwrXQoMK70KDRkdCh4oCa0KDCtdCgwrvQodCKICcvJyDQoNCF0KDCtSDQoNCF0KHRk9CgwrbQoMK10KDQhSovCglpZiAoIXN0cmNtcChkaXIsICIvIikpIGRlbGltPSAiIjsKCQoJaWYgKCEoZD1vcGVuZGlyKGRpcikpKXsKCQlwZXJyb3IoZGlyKTsKCQlyZXR1cm4gMTsKCX0KIAlpZiAoUmZsYWcpIHByaW50ZigiJXM6XG4iLGRpcik7Cgl3aGlsZSAoKGRkPXJlYWRkaXIoZCkpKXsKCQlpZighc3RyY21wKGRkLT5kX25hbWUsICIuIikgfHwgIXN0cmNtcChkZC0+ZF9uYW1lLCAiLi4iKSkKCQkJY29udGludWU7CgoJCS8v0KHQg9Ch4oCe0KDRldCh0ILQoNGY0KDRkdCh0ILQodGT0KDCtdCg0Zgg0KDRl9Cg0ZXQoMK70KDQhdCh4oC50KDihJYg0KDRl9Ch0ZPQoeKAmtCh0IoKCQlzbnByaW50ZihuYW1lLCBQQVRIX01BWCwgIiVzJXMlcyIsIGRpciwgZGVsaW0sIGRkLT5kX25hbWUpOwoKCQlpZihsc3RhdChuYW1lLCAmcykgPCAwKSAKCQkJY29udGludWU7CgkJaWYgKGxmbGFnIHx8IGdmbGFnKXsKCQkJcHJpbnRmKCIgICIpOwoJCQlsb25nX2xpc3QobmFtZSwgZGQtPmRfbmFtZSwgbGZsYWcpOyAvL9Cg0IbQoeKAudCg0IbQoNGV0KDSkSDQoNGX0KDRldCgwrvQoNCF0KDRldCg4oSWINCg0ZHQoNCF0KHigJ7QoNGV0KHQgtCg0ZjQoMKw0KHigKDQoNGR0KDRkQoJCX0KCQllbHNlIAoJCQlwcmludGYoIiVzICIsZGQtPmRfbmFtZSk7Ly/QoeKAmtCg0ZXQoMK70KHQitCg0ZTQoNGVINCg0ZHQoNGY0KHQjwoJfQoJaWYgKCFsZmxhZyAmJiAhZ2ZsYWcpIHByaW50ZigiXG4iKTsKCQoJaWYgKCFSZmxhZykgcmV0dXJuIDA7CglpZiAoIXN0cmNtcChkaXIsIi4uIikgfHwgIXN0cmNtcChkaXIsIi4iKSkgcmV0dXJuIDA7CglwcmludGYoIlxuIik7CglzZWVrZGlyKGQsMCk7CglzbnByaW50ZihuYW1lLCBQQVRIX01BWCwgIiVzJXMiLCBkaXIsIGRlbGltKTsKCXdoaWxlICgoZGQ9cmVhZGRpcihkKSkpewoJCWlmKCFzdHJjbXAoZGQtPmRfbmFtZSwgIi4iKSB8fCAhc3RyY21wKGRkLT5kX25hbWUsICIuLiIpKQoJCQljb250aW51ZTsKCQljaGFyIG1hc1tQQVRIX01BWF07CgkJc3RyY3B5KG1hcyxuYW1lKTsKCQlzdHJjYXQobWFzLGRkLT5kX25hbWUpOwoJCWlmKGxzdGF0KG1hcywgJnMpIDwgMCkgCgkJCWNvbnRpbnVlOwoJCWlmKFNfSVNESVIocy5zdF9tb2RlKSl7CgkJLy/QoMK10KHQg9CgwrvQoNGRINCh0IzQoeKAmtCg0ZUg0KDRlNCgwrDQoeKAmtCgwrDQoMK70KDRldCg0ZYKCQkJY2hhciBtYXNbUEFUSF9NQVhdOwoJCQlvPXRlbGxkaXIoZCk7IC8v0KDCt9CgwrDQoNGX0KDRldCg0ZjQoNCF0KDRkdCh4oCa0KHQiiDQoNGY0KDCtdCh0IPQoeKAmtCg0ZUg0KDQhiDQoMK30KDCsNCg0ZfQoNGR0KHQg9Cg0ZEKCQkJY2xvc2VkaXIoZCk7IC8v0KDSkdCgwrvQodCPINCh0IzQoNGU0KDRldCg0IXQoNGV0KDRmNCg0ZHQoNGRINCg0pHQoMK10KHQg9Cg0ZTQodCC0KDRkdCg0ZfQoeKAmtCg0ZXQodCC0KDRldCg0IYKCQkJc3RyY3B5KG1hcyxuYW1lKTsKCQkJc3RyY2F0KG1hcyxkZC0+ZF9uYW1lKTsKCgkJCWNoZGlyKG1hcyk7CgkJCWlmIChwcmludG91dChtYXMsUmZsYWcsbGZsYWcsZ2ZsYWcpKSByZXR1cm4gMTsKCQkJY2hkaXIobmFtZSk7CgkJCS8v0KDQhtCgwrXQodCC0KDQhdCgwrXQoNGY0KHQg9Ch0I8g0KDQhiDQoNGX0KHQgtCgwrXQoMK20KDQhdCh0IvQodCLINCg0pHQoNGR0KHQgtCgwrXQoNGU0KHigJrQoNGV0KHQgtCg0ZHQodCLCgkJCWlmKCEoZD1vcGVuZGlyKGRpcikpKSB7CgkJCQlwZXJyb3IoZGlyKTsKCQkJCXJldHVybiAxOwoJCQl9CgkJCXNlZWtkaXIoZCwgbyk7IC8v0KDQhtCgwrXQodCC0KDQhdCh0ZPQoeKAmtCh0IrQodCD0KHQjyDQoNCF0KDCsCDQoNGX0KHQgtCgwrXQoMK20KDQhdCgwrXQoMK1INCg0ZjQoMK10KHQg9Ch4oCa0KDRlQoJCX0KCX0KCWNsb3NlZGlyKGQpOwoJcmV0dXJuIDA7Cn0=