\write 中出现虚假换行符

\write 中出现虚假换行符

当我 时\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设置selectorj。根据token_show(def_ref)打印指向的标记。然后调用。def_refselectorprint_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_lnpascal 。从 的顶部开始:writelnfixwritesfixwrites.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似乎都没有任何作用。)

相关内容