当我 时\immediate\write\somefile{foo}
,TeX 会将内容写入foo
输出流中打开的文件\somefile
,但它也会转到下一行。(生成的文件有 4 个字节。)
由于我正在编写文件并将它们作为某些环境的主体读取,如果我可以禁用这个额外的换行符就好了。
主要问题是当我foo^^M
在文件末尾写入时,我写入的换行符与“默认”换行符结合在一起:它会导致虚假的\par
,从而破坏短宏(和align
环境)。
那么,是否可以避免使用转到下一行\write
?
答案1
回答你的问题:不,您无法避免插入换行符。请参阅下文了解我是如何得出这个结论的。
我发现 TeX 的源代码非常混乱,所以我很可能在这里遗漏了一些东西。我读到的这个\write
是作为扩展实现的,并不是因为它实际上是一个扩展,只是 Knuth 想给出一个编写扩展的示例。具体来说,\write
是作为 whatsit 节点实现的:
@<Implement \.{\\write}@>=
begin k:=cur_cs; new_write_whatsit(write_node_size);@/
cur_cs:=k; p:=scan_toks(false,false); write_tokens(tail):=def_ref;
end
无需追踪 whatsits 的具体处理方式,只需查找\immediate
因为\immediate\write
立即执行写入的实现即可。代码的相关部分如下。
@<Implement \.{\\immediate}@>=
begin get_x_token;
if cur_cmd=extension then begin
if cur_chr<=close_node then
begin p:=tail; do_extension; {append a whatsit node}
out_what(tail); {do the action immediately}
flush_node_list(tail); tail:=p; link(p):=null;
end
显然,这是附加一个 whatsit 节点、执行该节点、刷新它(可能释放与其关联的内存),然后将链接列表恢复到附加节点之前的状态。我们感兴趣的是out_what
。同样,相关部分如下。
procedure out_what(@!p:pointer);
var j:small_number; {write stream number}
begin case subtype(p) of
open_node,write_node,close_node:@<Do some work that has been queued up
for \.{\\write}@>;
@<Do some work that has been queued up...@>=
if not doing_leaders then
begin j:=write_stream(p);
if subtype(p)=write_node then write_out(p)
显然,我们想要write_out
。
procedure write_out(@!p:pointer);
var old_setting:0..max_selector; {holds print |selector|}
@!old_mode:integer; {saved |mode|}
@!j:small_number; {write stream number}
@!q,@!r:pointer; {temporary variables for list manipulation}
begin @<Expand macros in the token list
and make |link(def_ref)| point to the result@>;
old_setting:=selector; j:=write_stream(p);
if write_open[j] then selector:=j
else begin {write to the terminal if file isn't open}
if (j=17)and(selector=term_and_log) then selector:=log_only;
print_nl("");
end;
token_show(def_ref); print_ln;
flush_list(def_ref); selector:=old_setting;
end;
全局变量selector
用于确定输出应定向到何处。对于文件\write
,它将是一个 0-15 之间的数字。该行将if write_open[j] then selector:=j
设置selector
为j
。根据token_show(def_ref)
打印指向的标记。然后调用。def_ref
selector
print_ln
@ To end a line of text output, we call |print_ln|.
@<Basic print...@>=
procedure print_ln; {prints an end-of-line}
begin case selector of
term_and_log: begin wterm_cr; wlog_cr;
term_offset:=0; file_offset:=0;
end;
log_only: begin wlog_cr; file_offset:=0;
end;
term_only: begin wterm_cr; term_offset:=0;
end;
no_print,pseudo,new_string: do_nothing;
othercases write_ln(write_file[selector])
endcases;@/
end; {|tally| is not affected}
正如该评论所说,print_ln
用于结束一行文本。
实际上,正是在这一点上我陷入了困境。我找不到 的定义write_ln
。我最好的猜测是 WEB 删除了下划线,因此它变成了web2c 二进制文件转换的write_ln
pascal 。从 的顶部开始:writeln
fixwrites
fixwrites.c
/* fixwrites -- convert Pascal write/writeln's into fprintf's or putc's.
Originally by Tim Morgan, October 10, 1987. */
无论如何,生成的函数中的第一个函数pdftex0.c
是
void
println ( void )
{
println_regmem
switch ( selector )
{
/* elided cases 17 through 21 */
default:
putc ('\n', writefile [selector ]);
break;
}
}
答案2
想想看,我怀疑你正在遇到以下问题
使用 \immediate\write 给出的每条消息都从新行开始;用户可以通过在消息中包含带数字的字符 \newlinechar 来强制新行。此参数在 \message 中也有效。
(TeX 按主题分类,就像经常发生的那样。)为了控制线路,您只需使用一条线路,并在需要新线路的地方\write
使用。^^J
答案3
这不是一个直接的答案,但是既然你说你正在将文件读回到 TeX 中,那么你可以尝试在\relax
你写出的内容的末尾附加:\immediate\write\somefile{foo\relax}
。\relax
将吞噬所有以下空间,这听起来好像可以解决问题的症状,但不能解决根源。显然,这不是一个完美的解决方案,但可能已经足够好了。(我对实际解决方案的猜测是\newlinechar=-1
,但我对所做的任何更改\newlinechar
似乎都没有任何作用。)