Diverting
매크로 치환 외에 특정 영역을 나중 or 먼저 출력하거나 또는 출력에서 제외하는 등 출력 조절이 필요할 때가 있습니다. 이와 같은 기능을 제공하는 것이 diverting and undiverting 입니다.
divert
divert
divert ( Number )
M4 는 언제든지 출력을 임시 영역에 저장했다가 필요할 때 출력할 수 있습니다.
임시 영역은 양의 정수로 나타내는데 0
은 디폴트로 normal output stream 을 나타냅니다.
그러니까 divert(3)
으로 임시 영역 3
에 출력을 저장한 후에
divert(0)
을 하면 다시 normal output stream 으로 돌아와 출력되는것입니다.
저장한 내용을 나중에 직접 undivert 를 이용해 출력하지 않으면 자동으로 마지막에
undivert 되어 출력됩니다. 이때 출력은 번호순서에 따라 출력됩니다.
()
없는divert
는divert(0)
와 같습니다.
divert(-1) send to /dev/null
divert(0) send to stdout
divert(1) send to buffer #1
divert(2) send to buffer #2
divert(3) send to buffer #3
. . .
아래는 활용예 입니다.
- divert :
divert(1)
에 의해 AAA, BBB 라인이 임시 영역1
에 저장되고 라인 222 는divert(0)
에 의해 normal output stream 으로 출력되므로 111, 222 라인이 먼저 출력되고 나중에 AAA, BBB 라인이 출력됩니다.
- order : 라인 BBB 는
divert(2)
에 해당하고 라인 AAA 는divert(3)
에 해당하므로 출력시 BBB, AAA 라인 순으로 출력됩니다.
- append : 같은 divert 번호를 사용하면 내용이 append 됩니다.
divert(4)
가 두 군데로 분리되어 있지만 내용이 append 되어 함께 출력됩니다.
- discard : 출력을 저장할 때 사용할 수 있는 번호는 양의 정수이므로 음수는 출력을 discard 할때 사용됩니다. AAA, BBB 라인이 discard 되어 출력되지 않는 것을 볼 수 있습니다. 이때 출력만 discard 되는 것이지 내용중 매크로는 정상적으로 실행되므로 foo 매크로가 정의되어 100 이 출력됩니다.
# divert # order # append # discard
$ m4 <<\@ $ m4 <<\@ $ m4 <<\@ $ m4 <<\@
111111111 111111111 divert(4)dnl 111111111
divert(1)dnl divert(3)dnl AAAAAAAAA divert(-1)dnl
AAAAAAAAA AAAAAAAAA divert(0)dnl AAAAAAAAA
BBBBBBBBB divert(2)dnl 111111111 define(foo, 100)
divert(0)dnl BBBBBBBBB divert(4)dnl BBBBBBBBB
222222222 divert(0)dnl BBBBBBBBB divert(0)dnl
@ 222222222 divert(0)dnl 222222222
@ 222222222 foo
111111111 @ @
222222222 111111111
AAAAAAAAA 222222222 111111111 111111111
BBBBBBBBB BBBBBBBBB 222222222 222222222
AAAAAAAAA AAAAAAAAA 100
BBBBBBBBB
다음과 같이 divert(-1)
를 활용하면 comment 와 매크로를 define 할 때 생성되는 trailing newline 들이 출력에서 제외됩니다.
마지막 forloop 매크로 확장 결과를 보면 공백 라인이 하나도 생성되지 않는 것을 볼 수 있습니다.
$ m4 <<\@
divert(`-1')
# forloop(var, from, to, stmt) - improved version:
# works even if VAR is not a strict macro name
# performs sanity check that FROM is larger than TO
# allows complex numerical expressions in TO and FROM
define(`forloop', `ifelse(eval(`($2) <= ($3)'), `1',
`pushdef(`$1')_$0(`$1', eval(`$2'),
eval(`$3'), `$4')popdef(`$1')')')
define(`_forloop',
`define(`$1', `$2')$4`'ifelse(`$2', `$3', `',
`$0(`$1', incr(`$2'), `$3', `$4')')')
divert`'dnl # divert`'dnl 은 divert(0)dnl 과 같은것임
forloop(`x', 1, 5, `[x] ')
@
[1] [2] [3] [4] [5]
undivert
undivert
undivert ( Number . . . )
undivert ( File . . . )
undivert 는 divert 로 저장해놓은 영역을 현재 divert 영역으로 출력할 때 사용합니다.
그러니까 divert(3)
으로 저장해놓은 영역을 normal output stream 으로 출력하려면
먼저 divert(0)
을 한 후에 undivert(3)
해야 하는 것입니다.
( 물론 현재 divert(0) 이면 먼저 divert(0) 할 필요는 없습니다 ).
또한 divert(3)
영역을 divert(2)
영역으로 출력할 수도 있는데
이때도 먼저 divert(2)
로 변경한 후에 undivert(3)
하면 됩니다.
번호는 여러 개를 입력할 수 있고 입력된 순서에 따라서 출력됩니다.
()
없이 undivert
하면 현재 저장되어 있는 모든 divert 영역을 출력합니다.
한번 undivert 하면 해당 영역은 empty 가 되므로 다시 출력할 수 없습니다.
undivert 시 매크로 확장은 발생하지 않습니다.
undivert(1) dump buffer #1 to the current data stream
undivert(2) dump buffer #2 to the current data stream
undivert(3,1,2) dump buffer #3, #1, #2 to the current data stream
undivert dumps all buffers in numeric order
$ m4 <<\@ $ m4 <<\@ $ m4 <<\@ $ m4 <<\@
111111111 111111111 111111111 111111111
divert(3)dnl divert(3)dnl divert(3)dnl divert(3)dnl
AAAAAAAAA AAAAAAAAA AAAAAAAAA AAAAAAAAA
divert(2)dnl divert(2)dnl divert(2)dnl divert(2)dnl
BBBBBBBBB BBBBBBBBB BBBBBBBBB BBBBBBBBB
divert(1)dnl divert(1)dnl undivert(3)dnl divert(1)dnl
CCCCCCCCC CCCCCCCCC divert(1)dnl CCCCCCCCC
divert(0)dnl divert(0)dnl CCCCCCCCC divert(0)dnl
222222222 undivert(3,1,2)dnl divert(0)dnl undivert`'dnl
@ 222222222 undivert(2,1)dnl 222222222
@ 222222222 @
111111111 @
222222222 111111111 111111111
CCCCCCCCC AAAAAAAAA 111111111 CCCCCCCCC
BBBBBBBBB CCCCCCCCC BBBBBBBBB BBBBBBBBB
AAAAAAAAA BBBBBBBBB AAAAAAAAA AAAAAAAAA
222222222 CCCCCCCCC 222222222
222222222
divert 영역 삭제
저장해놓은 divert 영역을 삭제하려면 먼저 divert(-1)
로 변경한 후에 undivert
하면 됩니다.
divert(0)
영역은 삭제되지 않습니다.
$ m4 <<\@ $ m4 <<\@ $ m4 <<\@ $ m4 <<\@
111111111 111111111 111111111 111111111
divert(3)dnl divert(3)dnl divert(3)dnl divert(3)dnl
AAAAAAAAA AAAAAAAAA AAAAAAAAA AAAAAAAAA
divert(2)dnl divert(2)dnl divert(2)dnl divert(2)dnl
BBBBBBBBB BBBBBBBBB BBBBBBBBB BBBBBBBBB
divert(1)dnl divert(1)dnl divert(1)dnl divert(-1)dnl
CCCCCCCCC CCCCCCCCC CCCCCCCCC undivert(3)
divert(0)dnl divert(0)dnl divert(0)dnl divert(1)dnl
222222222 222222222 222222222 CCCCCCCCC
@ divert(-1)dnl divert(-1)dnl divert(0)dnl
undivert undivert(3,2) 222222222
111111111 @ @ @
222222222
CCCCCCCCC 111111111 111111111 111111111
BBBBBBBBB 222222222 222222222 222222222
AAAAAAAAA CCCCCCCCC CCCCCCCCC
BBBBBBBBB
활용 예제 )
$ m4 <<\EOF
divert(-1)
m4 has multiple output queues that can be manipulated with the
`divert' macro. Valid queues range from 0 to 10, inclusive, with
the default queue being 0. As an extension, GNU m4 supports more
diversions, limited only by integer type size.
Calling the `divert' macro with an invalid queue causes text to be
discarded until another call. Note that even while output is being
discarded, quotes around `divert' and other macros are needed to
prevent expansion.
# Macros aren't expanded within comments, meaning that keywords such
# as divert and other built-ins may be used without consequence.
# HTML utility macro:
define(`H2_COUNT', 0)
# The H2_COUNT macro is redefined every time the H2 macro is used:
define(`H2',
`define(`H2_COUNT', incr(H2_COUNT))<h2>H2_COUNT. $1</h2>')
divert(1)dnl
dnl
dnl The dnl macro causes m4 to discard the rest of the line, thus
dnl preventing unwanted blank lines from appearing in the output.
dnl
H2(First Section)
H2(Second Section)
H2(Conclusion)
dnl
divert(0)dnl
dnl
<HTML>
undivert(1)dnl One of the queues is being pushed to output.
</HTML>
EOF
--------------------------
<HTML>
<h2>1. First Section</h2>
<h2>2. Second Section</h2>
<h2>3. Conclusion</h2>
</HTML>
undivert 를 이용한 파일 include
undivert 를 이용해 파일도 include 할 수 있습니다. 기본적으로 undivert 시에는 매크로 확장이 안되므로 문자 그대로 파일 내용이 include 됩니다.
undivert(`foo.txt') dump file `foo.txt' to the current data stream
undivert(`foo.txt',`bar.txt') dump file `foo.txt', `bar.txt' . . .
$ cat /usr/share/doc/m4/examples/incl.m4 # include 에 사용되는 파일
Include file start
foo
Include file end
---------------------------------------
$ m4 <<\@ -I /usr/share/doc/m4/examples
define(`foo', `hello include')dnl
include(`incl.m4')dnl # include 매크로
@
Include file start
hello include # foo 매크로가 확장된다.
Include file end
---------------------------------------
$ m4 <<\@ -I /usr/share/doc/m4/examples
define(`foo', `hello include')dnl
undivert(`incl.m4')dnl # undivert 매크로
@
Include file start
foo # undivert 는 매크로 확장이 안된다.
Include file end
만약에 파일이 존재하지 않거나, 읽을 수 없거나, 디렉토리 이거나 할 경우는
stderr 로 오류 메시지가 출력되고 확장 결과는 void 가 됩니다.
하지만 include 매크로와 달리 종료 상태 값은 0
이 됩니다.
$ m4 <<\@
111111111
undivert(`not_exist.m4')dnl
222222222
@
111111111
m4:stdin:2: cannot undivert `not_exist.m4': No such file or directory
222222222
$ echo $? # 종료 상태 값은 0 이된다.
0
divnum
divnum
built-in 매크로는 현재 divert 영역 번호를 반환합니다.
$ m4 <<\@
Initial divnum
divert(1)dnl
Diversion one: divnum
divert(2)dnl
Diversion two: divnum
divert(3)dnl
Diversion three: divnum
@
Initial 0
Diversion one: 1
Diversion two: 2
Diversion three: 3
cleardivert 사용자 정의 매크로
cleardivert
cleardivert ( Number . . . )
divert 영역을 삭제할 때 다음과 같이 매크로를 정의해 사용하면 편리합니다.
cleardivert
는 전체 divert 영역을 삭제하고
Number
인수를 추가하면 해당 영역만 삭제됩니다.
define(`cleardivert',
`pushdef(`tmp', divnum)divert(-1)ifelse($#, 0,
`undivert`'', `undivert($@)')divert(tmp)popdef(`tmp')')