/etc/passwdΒΆ

This example shows how to parse simple file formats such as the /etc/passwd file. This file consists of multiple lines of the form user : password : UID : GID : info : home : command. Our example file is the following [/etc/passwd]:

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
portage:x:250:250:portage:/var/tmp/portage:/bin/false

[etc_passwd.re]

 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
#include <stdio.h>
#include <stdlib.h>

/*!max:re2c*/

static int lex(const char *YYCURSOR)
{
    const char *YYMARKER, *n, *p, *u, *g, *i, *h, *c;
    /*!stags:re2c format = 'const char *@@;'; */
loop:
    /*!re2c
        re2c:define:YYCTYPE = char;
        re2c:yyfill:enable = 0;

        end  = "\x00";
        eol  = "\n";
        sep  = [:];
        char = [^] \ (end | eol | sep);
        user = char+;
        pass = char*;
        uid  = [0-9]+;
        gid  = [0-9]+;
        info = char*;
        home = "/" char*;
        cmd  = "/" char*;

        *   { printf("error\n"); return 1; }
        end { return 0; }

        @n user sep
        @p pass sep
        @u uid  sep
        @g gid  sep
        @i info sep
        @h home sep
        @c cmd  eol {
            printf("user:     %.*s\n", (int)(p - n) - 1, n);
            printf("password: %.*s\n", (int)(u - p) - 1, p);
            printf("UID:      %.*s\n", (int)(g - u) - 1, u);
            printf("GID:      %.*s\n", (int)(i - g) - 1, g);
            printf("info:     %.*s\n", (int)(h - i) - 1, i);
            printf("home:     %.*s\n", (int)(c - h) - 1, h);
            printf("command:  %.*s\n", (int)(YYCURSOR - c - 1), c);
            printf("\n");
            goto loop;
        }
    */
}

int main(int argc, char **argv)
{
    if (argc < 2) {
        fprintf(stderr, "no input files\n");
        return 1;
    }

    FILE *file = fopen(argv[1], "r");

    fseek(file, 0, SEEK_END);
    const size_t fsize = (size_t) ftell(file);
    fseek(file, 0, SEEK_SET);

    char *buffer = (char*) malloc(fsize + 1);

    fread(buffer, 1, fsize, file);
    buffer[fsize] = 0;

    const int status = lex(buffer);

    fclose(file);
    free(buffer);

    return status;
}

Compile:

$ re2c --tags -o etc_passwd.cc etc_passwd.re
$ g++ -o etc_passwd etc_passwd.cc

Run:

$ ./etc_passwd /etc/passwd
user:     root
password: x
UID:      0
GID:      0
info:     root
home:     /root
command:  /bin/bash

user:     bin
password: x
UID:      1
GID:      1
info:     bin
home:     /bin
command:  /bin/false

user:     portage
password: x
UID:      250
GID:      250
info:     portage
home:     /var/tmp/portage
command:  /bin/false