• awk script for nodelists

    From Javier Sturman@4:900/733 to All on Wed Apr 22 17:03:38 2026

    Hello everybody!

    Based on ndl2binkd I (99% Gemini) created an awk script to generate the same output. It takes a nodelist as argument and it produces binkd expected node values. For sure it can be pefected.
    it assumes there are domains in binkd.conf named, fidonet, nixnet, fsxnet. Tested on FreeBSD.

    ---ndl.awk---
    #!/usr/bin/awk -f

    BEGIN {
    # 1. Argument Validation
    if (ARGC < 2) {
    print "Error: No input file provided." > "/dev/stderr"
    print "Usage: ./ndl.awk <nodelist_file>" > "/dev/stderr"
    print "Example: ./ndl.awk nodelist.360" > "/dev/stderr"
    exit 1
    }

    FS = ","
    current_zone = 1
    current_net = 0

    # Set DEBUG=1 via command line to see the parsing process:
    # awk -v DEBUG=1 -f ndl.awk <file>
    if (DEBUG == "") DEBUG = 0
    }

    # 2. Dynamic Domain Detection (based on filename)
    FNR == 1 {
    fname = toupper(FILENAME);
    if (fname ~ /NODELIST\./) dom = "fidonet";
    else if (fname ~ /NIXLIST\./) dom = "nixnet";
    else if (fname ~ /FSXNET\./) dom = "fsxnet";
    else dom = "fidonet";

    if (DEBUG) print "--- Debug: Processing file " FILENAME " as domain @" dom " ---" > "/dev/stderr"
    }

    # Skip comments and empty lines
    /^;/ || !NF { next }

    {
    gsub(/\r/, "", $0);

    # Normalize keyword to lowercase for robust matching
    keyword = tolower($1);
    number = $2;
    sysname = $3;
    sysop = $5;

    # 3. Filter DOWN and HOLD states
    if (keyword == "down" || keyword == "hold") {
    if (DEBUG) printf "--- Debug: Skipping node %d:%d/%d (Status: %s) ---\n", current_zone, current_net, number, keyword > "/dev/stderr"
    next;
    }

    # 4. Hierarchy Logic (Pascal Style)
    if (keyword == "zone") {
    current_zone = number; current_net = number; node_num = 0;
    }
    else if (keyword == "host" || keyword == "region") {
    current_net = number; node_num = 0;
    }
    else {
    node_num = number;
    }

    host_ip = "";
    port = "";
    # Priority tracking: 0=none, 1=ITN (Telnet), 2=IBN/INA (BinkP/Mail)
    p_priority = 0;

    # 5. Technical Flag Scanning (Case-Insensitive)
    for (i = 7; i <= NF; i++) {
    field_data = tolower($i);

    if (field_data ~ /^(ina|ibn|ifc|itn):/) {
    # Use original field $i for splitting to preserve Host casing
    n_sub = split($i, parts, ":");
    tag = tolower(parts[1]);

    # Capture Hostname (INA/IBN have preference)
    if (n_sub >= 2 && parts[2] ~ /[A-Za-z\.]/ && host_ip == "") {
    host_ip = parts[2];
    }

    # Port Priority Logic
    # According to FTSC, IBN is the primary BinkP mail port.
    # ITN (Telnet) should not overwrite it.
    current_tag_priority = (tag == "itn") ? 1 : 2;

    # Check for port in sub-part 2 (e.g., IBN:24555 or ITN:60177)
    if (n_sub >= 2 && parts[2] ~ /^[0-9]+$/) {
    if (current_tag_priority >= p_priority) {
    port = parts[2];
    p_priority = current_tag_priority;
    if (DEBUG) printf " [Debug] Port %s set by %s (Priority %d)\n", port, tag, p_priority > "/dev/stderr"
    }
    }
    # Check for port in sub-part 3 (e.g., IBN:host:24555)
    if (n_sub >= 3 && parts[3] ~ /^[0-9]+$/) {
    if (current_tag_priority >= p_priority) {
    port = parts[3];
    p_priority = current_tag_priority;
    if (DEBUG) printf " [Debug] Port %s set by %s (Priority %d)\n", port, tag, p_priority > "/dev/stderr"
    }
    }
    }
    }

    # 6. Final Output Generation
    if (host_ip != "") {
    gsub(/_/, " ", sysop);
    gsub(/_/, " ", sysname);

    full_dest = (port != "") ? host_ip ":" port : host_ip;
    gsub(/[[:space:]]+$/, "", full_dest);

    printf "# %s | %s\n", sysop, sysname;
    printf "node %d:%d/%d@%s -nd %s\n\n", current_zone, current_net, node_num, dom, full_dest;
    }
    }


    Javier


    --- GoldED+/BSD 1.1.5-b20170303-b20170303 + HPT 1.9.0 + Binkd 1.1a-115
    * Origin: FIDONODO DE JAS | ¯\_(O,O)_/¯ (4:900/733)