15.7 Namespace Example

The following example is a revised version of the suite of routines developed in Reading the User Database. See there for an explanation of how the code works.

The formulation here, due mainly to Andrew Schorr, is rather elegant. All of the implementation functions and variables are in the passwd namespace, whereas the main interface functions are defined in the awk namespace.

# ns_passwd.awk --- access password file information

@namespace "passwd"

BEGIN {
    # tailor this to suit your system
    Awklib = "/usr/local/libexec/awk/"
}

function Init(    oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat)
{
    if (Inited)
        return

    oldfs = FS
    oldrs = RS
    olddol0 = $0
    using_fw = (PROCINFO["FS"] == "FIELDWIDTHS")
    using_fpat = (PROCINFO["FS"] == "FPAT")
    FS = ":"
    RS = "\n"

    pwcat = Awklib "pwcat"
    while ((pwcat | getline) > 0) {
        Byname[$1] = $0
        Byuid[$3] = $0
        Bycount[++Total] = $0
    }
    close(pwcat)
    Count = 0
    Inited = 1
    FS = oldfs
    if (using_fw)
        FIELDWIDTHS = FIELDWIDTHS
    else if (using_fpat)
        FPAT = FPAT
    RS = oldrs
    $0 = olddol0
}

function awk::getpwnam(name)
{
    Init()
    return Byname[name]
}

function awk::getpwuid(uid)
{
    Init()
    return Byuid[uid]
}

function awk::getpwent()
{
    Init()
    if (Count < Total)
        return Bycount[++Count]
    return ""
}

function awk::endpwent()
{
    Count = 0
}

As you can see, this version also follows the convention mentioned in Naming Library Function Global Variables, whereby global variable and function names start with a capital letter.

Here is a simple test program. Since it’s in a separate file, unadorned identifiers are sought for in the awk namespace:

BEGIN {
    while ((p = getpwent()) != "")
        print p
}

Here’s what happens when it’s run:

$ gawk -f ns_passwd.awk -f testpasswd.awk
-| root:x:0:0:root:/root:/bin/bash
-| daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
-| bin:x:2:2:bin:/bin:/usr/sbin/nologin
-| sys:x:3:3:sys:/dev:/usr/sbin/nologin
...