5

I want to include a file and have all the lines indented. I want it to be a code block in a markdown document.

Basically I want something like this:

text
include(somefile)
text

to have this output:

text
    content
    from
    somefile
text

I looked through the manual and found patsubst. I also found this question and answer: How to indent a block of text in an m4 macro

That works for files containing no commas:

$ cat textnocomma 
some text.
with sentences.
and no commas.

$ cat patsubstincludenocomma
text
patsubst(include(textnocomma), `^', `    ')
text

$ m4 patsubstincludenocomma
text
    some text.
    with sentences.
    and no commas.

text

But when I include a file that contains a comma:

$ cat textcomma 
some text.
with sentences.
and, commas.

$ cat patsubstincludecomma
text
patsubst(include(textcomma), `^', `    ')
text

$ m4 patsubstincludecomma
text
m4:patsubstincludecommanoquote:3: Warning: excess arguments to builtin `patsubst' ignored
some text.
with sentences.
and
text

The problem seems to be the naive way m4 does macro expansion. The comma from the included text is interpreted as syntax of the patsubst macro. The solution (should be) simple: quote the included text.

But if I quote the include then just the first line is indented:

$ cat patsubstincludecommaquote 
text
patsubst(`include(textcomma)', `^', `    ')
text

$ m4 patsubstincludecommaquote
text
    some text.
with sentences.
and, commas.

text

I have tried different combinations of quoting and literal newlines instead of regex newlines. But all I got so far is either the excess arguments error message or just the first line indented.

How can I include text with comma, and maybe other m4 syntax, and have it indented in m4?

Lesmana
  • 25,663
  • 9
  • 82
  • 87

2 Answers2

4

i have done some research and can conclude that quoting the include makes patsubst no longer recognize ^ (beginning of line) in the text apart from the first line. at least on my system.

$ m4 --version
m4 (GNU M4) 1.4.18
...

observe:

$ cat textnocomma 
some text.
with sentences.
and no commas.

$ cat includenocomma 
foo
patsubst(include(textnocomma), `^', `    ')
bar
patsubst(`include(textnocomma)', `^', `    ')
baz

$ m4 includenocomma 
foo
    some text.
    with sentences.
    and no commas.

bar
    some text.
with sentences.
and no commas.

baz

this also happens when defining the text as "string literals" instead of include:

$ cat definestringliterals 
define(`sometext', `first line
second line
third line')dnl
foo
patsubst(sometext, `^', `    ')
bar
patsubst(`sometext', `^', `    ')
baz

$ m4 definestringliterals 
foo
    first line
    second line
    third line
bar
    first line
second line
third line
baz

here is a question and answer that supports this observation: How to match newlines in GNU M4 _properly_

strangely this does not happen if putting the string literals directly inside patsubst:

$ cat patsubststringliterals 
foo
patsubst(first line
second line
third line, `^', `    ')
bar
patsubst(`first line
second line
third line', `^', `    ')
baz

$ m4 patsubststringliterals 
foo
    first line
    second line
    third line
bar
    first line
    second line
    third line
baz

using parens to "quote" the text does not have this problem. but now my text has parens around it:

$ cat textcomma 
some text.
with sentences.
and, commas.

$ cat includecomma 
foo
patsubst(include(textcomma), `^', `    ')
bar
patsubst(`include(textcomma)', `^', `    ')
baz
patsubst((include(textcomma)), `^', `    ')
qux

$ m4 includecomma 
foo
m4:includecomma:2: Warning: excess arguments to builtin `patsubst' ignored
some text.
with sentences.
and
bar
    some text.
with sentences.
and, commas.

baz
    (some text.
    with sentences.
    and, commas.
    )
qux

so i guess this is a bug. if quoting include then patsubst will no longer recognize ^ apart from the first line. But quoting include is necessary to prevent a comma in the text to be interpreted as syntax.

Lesmana
  • 25,663
  • 9
  • 82
  • 87
3

Why don't you use external commands?

esyscmd(`sed "s,^,    ," textcomma')
uzsolt
  • 5,832
  • 2
  • 20
  • 32
  • it seems to be a viable workaround. although it feels kinda silly to use an external tool when a builtin exists which promises this exact functionality. the only problem seems to be the quoting. – Lesmana Feb 21 '19 at 20:53
  • As I see the bultin solutions don't work with included file - I don't know why. Only the first line will be idented (with `divert`, `paste` or `include` too). – uzsolt Feb 22 '19 at 08:51