aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 571ff7b235ac9ff0c4732beb5181f02f5378ac7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
## What is `cppawk`?

`cppawk` is a tiny shell script that is used like `awk`. It invokes
the C preprocessor (GNU `cpp`) on the Awk code and calls `gawk`.

`cppawk` understands the basic Awk options like `-F` and `-v`, and also
understand common `cpp` options like `-I` and `-Dmacro=value`.

There is a `man` page with all the details.

For instance, if we define a file called `awkloop.h` which has these contents

    :::c
    #define awkloop(file)  for (; getline < file || (close(file) && 0); )
    #define nextrec        continue
    #define rule(cond)     if (cond)

Then this sort of code is possible:

    ::c
    #include "awkloop.h"

    function main()
    {
      awkloop ("/proc/mounts") {
        rule ($3 != "ext4") { nextrec }
        rule ($2 == "/") { print $1 }
      }
    }

    BEGIN {
      main()
    }

We have implemented a facsimile of an Awk input scanning loop inside a function
with a bit of syntactic sugar.

If you know C and the C preprocessor, and if you know Awk, the utility
and applications for this should be obvious; you may skip the next section
and go get it!

## Why or who might use `cppawk`?

0.  Why not? It's just a tiny shell script.

1.  You know how to use the C preprocessor, and are doing work on a system or
    situation where you can count on it being installed, such as build
    scripts or continuous integration. Make use of what you know.

2.  It makes some things easy, like making a program out of multiple
    files, which easily find each other in the same directory or relative
    path. Or macros, for some syntactic sugars.

3.  Though GNU Awk has `@include`, that feature provides no preprocessor
    features and works with GNU Awk only. `cppawk` calls `gawk`, but can
    easily be tweaked to target any Awk; any Awk can have file inclusion.
    There is the possibility of using `#ifdef` to make code
    work on different Awks from one file. (The default cppawk installation uses
    gawk, and also defines `__gawk__` as 1, which you can test for.)

4.  Comments. Awk has no comments that don't end at the end of
    the line; `cppawk` gives you `/*...*/`.

5.  Temporarily disabling code with `#if 0` ... `#endif` rather than
    fiddling with hash marks.

6.  Exploration: Awk is syntactically C like, but not C: what
    implications does that have for writing macros? You can discover some
    new-ish techniques, though it won't be earth-shattering.

7.  Weird access to some host attributes intended for C:

        $ cppawk '#include <limits.h>
        BEGIN { print PATH_MAX, ULONG_MAX }'
        4096 214748364701

    this sort of thing can be useful in devops land.

## How about systems that have `awk` but no `cpp`?

`cppawk` is used directly on systems that have `cpp`, as if
it were an Awk implementation.

`cppawk --prepro-only` will generate the preprocessed Awk code,
which can be captured and transferred to a system that has no
preprocessor installed, such as an embedded board that has
BusyBox Awk.

Of course, capturing the preprocessed output has other uses.
It's possible to generate different versions of an Awk program
by using `cppawk --prepro-only` in conjunction with conditional
preprocessing which reacts to different values of a macro defined
on the command line via `-D`.