引子
跟踪perl和python脚本对文件的访问,实际过程中,perl和python解析器在解析完脚本后,直接关闭了
脚本文件,在进程中查询不到是访问文件的脚本文件名称。
shell、perl和python脚本执行过程
bash脚本执行过程
脚本内容:
#!/usr/bin/env bash echo `date`" hello world!" >> /root/log.txt
使用strace跟踪脚本执行过程,为了节省篇幅,只保留一些关键执行过程:
# strace -q ./test.sh
execve("./test.sh", ["./test.sh"], [/* 35 vars */]) = 0 ##启动脚本进程
......
open("./test.sh", O_RDONLY) = 3 ##打开脚本文件
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff37bb77d0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/usr/bin/env bash
echo `date`"..., 80) = 66
lseek(3, 0, SEEK_SET) = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0
fcntl(255, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 255) = 255 ##复制已打开的脚本文件描述符为255
close(3) = 0 ##关闭已打开的脚本文件描述符3
......
read(255, "#!/usr/bin/env bash
echo `date`"..., 66) = 66 ##读取test.sh脚本内容
.....
open("/root/log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 ## 执行test.sh脚本中打开日志文件的动作
....
read(3, "Sun Feb 3 16:15:31 CST 2019
", 128) = 29 ## 获取date命令结果
read(3, "", 128) = 0
.....
write(1, "Sun Feb 3 15:51:56 CST 2019 hell"..., 41) = 41 ## 执行test.sh脚本中写日志文件的动作
dup2(10, 1) = 1
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(255, "
", 66) = 1
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(255, "", 66) = 0
exit_group(0) = ? ##退出shell脚本执行,这里会关闭所有打开的文件描述符
ksh脚本执行过程:
#!/usr/bin/env ksh echo `date`" hello world!" >> /root/log.txt
strace -q ./test.sh
execve("./test.sh", ["./test.sh"], [/* 35 vars */]) = 0 ##启动脚本进程
......
open("./test.sh", O_RDONLY) = 3 ##打开脚本
fstat(3, {st_mode=S_IFREG|0755, st_size=65, ...}) = 0
fcntl(3, F_DUPFD, 10) = 10 ##复制脚本文件的描述符
close(3) = 0 ## 关闭脚本文件
/*
open("./test.sh", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=65, ...}) = 0
fcntl(3, F_DUPFD, 10) = 11 ##有的系统得出的结果是11
close(3) = 0
fcntl(11, F_SETFD, FD_CLOEXEC) = 0
*/
......
read(10, "#!/usr/bin/env ksh
echo `date`""..., 8192) = 65 ##读脚本文件内容
read(10, "", 8192) = 0
brk(0xf09000) = 0xf09000
......
read(3, "Sun Feb 3 16:24:53 CST 2019
", 8192) = 29 ##获取date命令内容
read(3, "", 8192) = 0
close(3) = 0
......
write(3, "Sun Feb 3 16:24:53 CST 2019
", 29) = 29
......
open("/root/log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 ##打开日志文件
......
write(1, "Sun Feb 3 16:24:53 CST 2019 hell"..., 41) = 41 ##写日志文件
lseek(1, 0, SEEK_CUR) = 492
......
exit_group(0) = ? ##退出shell脚本执行,这里会关闭所有打开的文件描述符
perl脚本执行过程
1 #!/usr/bin/env perl 2 3 $datestring = localtime(); 4 5 open(logfile,">>/mnt/newlog3.txt") or die "Cant't open /mnt/newlog3.txt"; 6 print logfile "$datestring hello world! I am Perl! "; 7 close(logfile);
# strace /usr/bin/perl ../hello.pl
execve("/usr/bin/perl", ["/usr/bin/perl", "../hello.pl"], [/* 62 vars */]) = 0 ##执行hello.pl脚本
......
open("../hello.pl", O_RDONLY) = 3 ##以下代码是打开hello.pl脚本并读取脚本内容(包含脚本解析)
......
read(3, "#!/usr/bin/env perl
$datestring"..., 4096) = 194
read(3, "", 4096) = 0
close(3) = 0 ## 关闭已经打开的hello.pl脚本
open("/etc/localtime", O_RDONLY) = 3 ## 打开时间文件,获取时间:对应脚本第三行
fstat(3, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb976b7b000
read(3, "TZif2 3 3 "..., 4096) = 414
lseek(3, -249, SEEK_CUR) = 165
read(3, "TZif2 3 3 "..., 4096) = 249
close(3) = 0
munmap(0x7fb976b7b000, 4096) = 0
open("/mnt/newlog3.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 ##打开日志文件 /mnt/newlog3.txt:对应脚本第5和6行
lseek(3, 0, SEEK_END) = 389
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7ffd3b444fb0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 389
fstat(3, {st_mode=S_IFREG|0644, st_size=389, ...}) = 0
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
write(3, "Mon Feb 11 18:31:40 2019 hello w"..., 49) = 49
close(3) = 0 ##关闭日志文件 /mnt/newlog3.txt
exit_group(0) = ?
python脚本执行过程
1 #!/usr/bin/python 2 3 import os 4 import datetime,time 5 6 7 with open("/mnt/newlog3.txt", 'a+') as fp: 8 cur_date=datetime.datetime.now() 9 cur_date_str=cur_date.strftime("%Y-%m-%d %H:%M:%S") 10 fp.write("{0} Hello world! I am python! ".format(cur_date_str)) 11 fp.close()
# strace ./hello.py
execve("./hello.py", ["./hello.py"], [/* 62 vars */]) = 0 ##执行hello.py脚本
......
getcwd("/root/liangjs", 4096) = 14
lstat("/root/liangjs/hello.py", {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
stat("./hello.py", {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
open("./hello.py", O_RDONLY) = 3 ##打开hello.py脚本并解析该python脚本
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
lseek(3, 0, SEEK_SET) = 0
read(3, "#!/usr/bin/python
import os
imp"..., 241) = 241
read(3, "e_str))
fp.close()
", 4096) = 22
close(3) = 0
munmap(0x7f67ad9e8000, 4096) = 0
stat("./hello.py", {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
open("./hello.py", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff46f2d390) = -1 ENOTTY (Inappropriate ioctl for device)
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/usr/bin/python
import os
imp"..., 4096) = 263
lseek(3, 263, SEEK_SET) = 263
brk(0x6c7000) = 0x6c7000
read(3, "", 4096) = 0
brk(0x6be000) = 0x6be000
brk(0x6bc000) = 0x6bc000
close(3) = 0 ##关闭已经打开的hello.py脚本文件
munmap(0x7f67ad9e8000, 4096) = 0
......
open("/etc/localtime", O_RDONLY) = 4 ##获取时间信息
fstat(4, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
read(4, "TZif2 3 3 "..., 4096) = 414
lseek(4, -249, SEEK_CUR) = 165
read(4, "TZif2 3 3 "..., 4096) = 249
close(4) = 0
munmap(0x7f67ad9e8000, 4096) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
close(3) = 0
open("/mnt/newlog3.txt", O_RDWR|O_CREAT|O_APPEND, 0666) = 3 ##打开/mnt/newlog3.txt文件:对应脚本第7行
fstat(3, {st_mode=S_IFREG|0644, st_size=438, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=438, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
write(3, "2019-02-11 18:41:16 Hello world!"..., 46) = 46 ##写/mnt/newlog3.txt文件:对应脚本第10行
close(3) = 0 ##关闭/mnt/newlog3.txt文件:对应脚本第11行
munmap(0x7f67ad9e8000, 4096) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f67ad2ac850}, {0x7f67ad54ed38, [], SA_RESTORER, 0x7f67ad2ac850}, 8) = 0
exit_group(0) = ?
从上面分析,shell脚本是边解析边执行,在执行完脚本后,再关闭脚本文件;perl和python脚本是先解析再执行,在执行脚本之前,
已经完成了脚本的解析,直接关闭了脚本文件。
如何控制perl或python脚本在执行脚本时不关闭脚本文件呢?我们需要从perl和python源码着手分析。
perl和python源码分析
python源码分析执行过程
注:以python-2.7.9源码为分析蓝本
1 /* Main program */ 2 3 int 4 Py_Main(int argc, char **argv) 5 { 6 ...... 7 if (sts==-1) { 8 /* call pending calls like signal handlers (SIGINT) */ 9 if (Py_MakePendingCalls() == -1) { 10 PyErr_Print(); 11 sts = 1; 12 } else { 13 sts = PyRun_AnyFileExFlags( 14 fp, 15 filename == NULL ? "<stdin>" : filename, 16 filename != NULL, &cf) != 0; /* 是否执行python脚本文件作为是否关闭脚本文件的依据 */ 17 } 18 } 19 ...... 20 }
1 /* Parse input from a file and execute it */ 2 3 int 4 PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit, 5 PyCompilerFlags *flags) 6 { 7 if (filename == NULL) 8 filename = "???"; 9 if (Py_FdIsInteractive(fp, filename)) { /* 交互式执行python命令 */ 10 int err = PyRun_InteractiveLoopFlags(fp, filename, flags); 11 if (closeit) 12 fclose(fp); 13 return err; 14 } 15 else 16 return PyRun_SimpleFileExFlags(fp, filename, closeit, flags); /* 执行python脚本文件 */ 17 }
PyRun_SimpleFileExFlags调用PyRun_FileExFlags函数:
1 PyObject * 2 PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, 3 PyObject *locals, int closeit, PyCompilerFlags *flags) 4 { 5 PyObject *ret; 6 mod_ty mod; 7 PyArena *arena = PyArena_New(); 8 if (arena == NULL) 9 return NULL; 10 /* Author: 解析python脚本文件 */ 11 mod = PyParser_ASTFromFile(fp, filename, start, 0, 0, 12 flags, NULL, arena); 13 if (closeit) 14 fclose(fp); /* 解析完成后,关闭打开的python脚本文件 */ 15 if (mod == NULL) { 16 PyArena_Free(arena); 17 return NULL; 18 } 19 ret = run_mod(mod, filename, globals, locals, flags, arena); /* 执行python脚本 */ 20 PyArena_Free(arena); 21 return ret; 22 }
从python脚本的执行过程看,当python命令传入的是脚本文件,则先解析python脚本内容,然后关闭打开的脚本文件,最后执行python脚本。
perl源码分析执行过程
注:以perl-5.16.3源码为分析蓝本
1 #ifdef NO_ENV_ARRAY_IN_MAIN 2 extern char **environ; 3 int 4 main(int argc, char **argv) /* in miniperlmain.c */ 5 #else 6 int 7 main(int argc, char **argv, char **env) 8 #endif 9 { 10 ...... 11 exitstatus = perl_parse(my_perl, xs_init, argc, argv, (char **)NULL); /* 做perl脚本解析: S_parse_body函数 */ 12 if (!exitstatus) { 13 perl_run(my_perl); /* 执行perl脚本 */ 14 } 15 ...... 16 } 17 18 19 #define parse_body(a,b) S_parse_body(aTHX_ a,b) 20 /* in perl.c */ 21 int 22 perl_parse(pTHXx_ XSINIT_t xsinit, int argc, char **argv, char **env) 23 { 24 ...... 25 switch (ret) { 26 case 0: 27 parse_body(env,xsinit); /* 真正做perl脚本解析的函数是S_parse_body */ 28 ...... 29 break; 30 ...... 31 }
1 STATIC void * 2 S_parse_body(pTHX_ char **env, XSINIT_t xsinit) 3 { 4 ...... 5 rsfp = open_script(scriptname, dosearch, &suidscript); /* 打开perl脚本文件 */ 6 if (!rsfp) { 7 rsfp = PerlIO_stdin(); 8 lex_start_flags = LEX_DONT_CLOSE_RSFP; 9 } 10 11 ...... 12 lex_start(linestr_sv, rsfp, lex_start_flags); /* 准备perl解析环境和执行环境,实际函数是 Perl_lex_start */ 13 if(linestr_sv) 14 SvREFCNT_dec(linestr_sv); 15 ...... 16 /* now parse the script */ 17 SETERRNO(0,SS_NORMAL); 18 /* yyparse函数解析perl脚本文件,然后关闭脚本: 实际调用Perl_lex_next_chunk函数关闭脚本文件 */ 19 if (yyparse(GRAMPROG) || PL_parser->error_count) { 20 if (PL_minus_c) 21 Perl_croak(aTHX_ "%s had compilation errors. ", PL_origfilename); 22 else { 23 Perl_croak(aTHX_ "Execution of %s aborted due to compilation errors. ", 24 PL_origfilename); 25 } 26 } 27 ...... 28 }
从perl脚本的执行过程看,当perl命令传入的是脚本文件,则先解析perl脚本内容,然后关闭打开的脚本文件,最后执行perl脚本。
从python和perl源码分析过程看,两种脚本的执行过程都有一个参数控制着脚本的关闭方式。在python源码中,是PyRun_FileExFlags函数的closeit参数,
当closeit为0是,python脚本执行完成后,不直接关闭打开的python脚本文件。在perl源码中,是Perl_lex_start函数的flags参数,当flags参数包含LEX_DONT_CLOSE_RSFP时,
perl脚本解析完成后不直接关闭打开的perl脚本文件。
源码修改
依据我们的分析,可以修改源码控制python和perl脚本的关闭方式。源码修改方法如下。
python源码修改方式:
1 int 2 Py_Main(int argc, char **argv) 3 { 4 ...... 5 int closeit = 0, RunAnyFileExFlag = 0; /* 定义是否关闭python脚本的变量 */ 6 ...... 7 if (sts==-1) { 8 /* call pending calls like signal handlers (SIGINT) */ 9 if (Py_MakePendingCalls() == -1) { 10 fprintf(stderr, "call Py_MakePendingCalls return -1... "); 11 PyErr_Print(); 12 sts = 1; 13 } else { 14 /* closeit decide whether closing python file */ 15 closeit = 0; 16 RunAnyFileExFlag = 1; 17 sts = PyRun_AnyFileExFlags( 18 fp, 19 filename == NULL ? "<stdin>" : filename, 20 closeit /* filename != NULL */, &cf) != 0; /* 如果是执行的脚本文件,则不关闭python脚本文件 */ 21 } 22 } 23 ...... 24 if(RunAnyFileExFlag && !closeit){ /* 在python结束之前关闭已经打开的python脚本文件 */ 25 fclose(fp); 26 } 27 #endif 28 Py_Finalize(); 29 ...... 30 }
perl源码修改方式:
1 STATIC void * S_parse_body(pTHX_ char **env, XSINIT_t xsinit) 2 /* lex_start中, 添加 LEX_DONT_CLOSE_RSFP 标记 */ 3 lex_start(linestr_sv, rsfp, lex_start_flags | LEX_DONT_CLOSE_RSFP); 4 /* fprintf(stderr,"lex_start end...... "); */ 5 if(linestr_sv) 6 SvREFCNT_dec(linestr_sv);
笔者注: 在perl脚本执行完成后,由PerlIO_destruct函数完成后perl脚本文件的关闭动作!
修改源码后测试结果
perl脚本执行过程:
1 # strace /root/liangjs/hello.pl 2 execve("/root/liangjs/hello.pl", ["/root/liangjs/hello.pl"], [/* 34 vars */]) = 0 3 .... 4 open("/root/liangjs/hello.pl", O_RDONLY) = 3 ##打开测试perl脚本文件 5 ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffe347e36a0) = -1 ENOTTY (Inappropriate ioctl for device) 6 lseek(3, 0, SEEK_CUR) = 0 7 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 8 ...... 9 read(3, "#!/usr/bin/env perl $datestring"..., 8192) = 194 ##读取perl脚本文件内容并解析 10 read(3, "", 8192) = 0 ##没有关闭perl脚本文件 11 ...... 12 open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 4 ##获取时间信息 13 .... 14 open("/mnt/newlog3.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 4 15 lseek(4, 0, SEEK_END) = 539 16 ioctl(4, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffe347e3540) = -1 ENOTTY (Inappropriate ioctl for device) 17 lseek(4, 0, SEEK_CUR) = 539 18 fstat(4, {st_mode=S_IFREG|0644, st_size=539, ...}) = 0 19 fcntl(4, F_SETFD, FD_CLOEXEC) = 0 20 brk(0) = 0xf88000 21 brk(0xfaa000) = 0xfaa000 22 write(4, "Wed Feb 20 20:05:18 2019 hello w"..., 49) = 49 ##写日志文件/mnt/newlog3.txt 23 close(4) = 0 ##关闭日志文件/mnt/newlog3.txt 24 ........ 25 write(2, "call PerlIO_destruct...... ", 27call PerlIO_destruct...... 26 ) = 27 27 close(3) = 0 ##关闭已经打开的perl脚本文件 28 exit_group(0) = ? 29 +++ exited with 0 +++
python脚本执行过程:
1 stat("/root/liangjs/py_hello.py", {st_mode=S_IFREG|0755, st_size=958, ...}) = 0 2 open("/root/liangjs/py_hello.py", O_RDONLY) = 3 3 fstat(3, {st_mode=S_IFREG|0755, st_size=958, ...}) = 0 4 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8830aa9000 5 fstat(3, {st_mode=S_IFREG|0755, st_size=958, ...}) = 0 6 lseek(3, 0, SEEK_SET) = 0 7 read(3, "#!/usr/bin/env python import os"..., 936) = 936 8 read(3, "t/newlog3.txt", 0644) ", 4096) = 22 9 close(3) = 0 ##第一次打开python脚本文件后关闭!!! 10 munmap(0x7f8830aa9000, 4096) = 0 11 stat("/root/liangjs/py_hello.py", {st_mode=S_IFREG|0755, st_size=958, ...}) = 0 12 write(2, "second open python script file.."..., 34second open python script file... 13 ) = 34 14 open("/root/liangjs/py_hello.py", O_RDONLY) = 3 15 fstat(3, {st_mode=S_IFREG|0755, st_size=958, ...}) = 0 16 write(2, "call PyRun_AnyFileExFlags... ", 29call PyRun_AnyFileExFlags... 17 ) = 29 18 ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffd9da9be30) = -1 ENOTTY (Inappropriate ioctl for device) 19 brk(0) = 0x1a9e000 20 brk(0x1ac0000) = 0x1ac0000 21 fstat(3, {st_mode=S_IFREG|0755, st_size=958, ...}) = 0 22 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8830aa9000 23 read(3, "#!/usr/bin/env python import os"..., 4096) = 958 24 stat("/etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned", 0x7ffd9da9bb10) = -1 ENOENT (No such file or directory) 25 read(3, "", 4096) = 0 ##第二次打开python脚本文件后没有关闭动作!!! 26 ..... 27 write(2, "close python file, RunAnyFileExF"..., 53close python file, RunAnyFileExFlag = 1, closeit = 0 28 ) = 53 29 close(3) = 0 ##最后关闭打开的python脚本文件 30 munmap(0x7f8830aa9000, 4096) = 0 31 rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f8830743370}, {0x4fe640, [], SA_RESTORER, 0x7f8830743370}, 8) = 0 32 exit_group(0) = ? 33 +++ exited with 0 +++
修改python和perl源码后,从以上执行过程来看,都是在执行完python和perl脚本之后才关闭相应的脚本文件。
说明这种修改方式符合我们控制perl和python脚本文件关闭时刻的预期!
进一步的工作
默认动作还是解析完perl和python脚本后,直接关闭脚本文件;可以添加脚本执行参数,控制脚本文件解析完成后是否关闭。
相关议题
在perl较低版本中,例如perl-5.10.0版本,yy_parser结构体中没有lex_flags成员,所以要实现控制脚本文件关闭,需要添加相应的成员和控制流程。
Perl-5.10.0版本源码修改
parser.h文件
1 typedef struct yy_parser { 2 3 /* parser state */ 4 5 struct yy_parser *old_parser; /* previous value of PL_parser */ 6 ...... 7 char tokenbuf[256]; 8 /* 2018-11-14, with no close file */ 9 U8 lex_flags; 10 } yy_parser;
toke.c文件:
1 void 2 Perl_lex_start(pTHX_ SV *line, PerlIO *rsfp, bool new_filter) 3 { 4 ...... 5 parser->copline = NOLINE; 6 parser->lex_state = LEX_NORMAL; 7 parser->expect = XSTATE; 8 parser->rsfp = rsfp; 9 parser->rsfp_filters = (new_filter || !oparser) ? newAV() 10 : (AV*)SvREFCNT_inc(oparser->rsfp_filters); 11 /* add 2018-11-14, for no closefile */ 12 parser->lex_flags = LEX_DONT_CLOSE_RSFP; 13 14 Newx(parser->lex_brackstack, 120, char); 15 Newx(parser->lex_casestack, 12, char); 16 *parser->lex_casestack = '