Posted to tcl by guest4 at Thu Nov 11 08:19:30 GMT 2021view pretty

################################################################################
# Tcl extension

// redirecttcl.c: redirect stdout to systemd journal.

#include <sys/types.h>

#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal.h>

#include <tcl.h>

//----------------------------------------------------------------------

#ifndef UNUSED
#  define UNUSED(x) (void)(x)
#endif

#if !defined(INT2PTR)
#  define INT2PTR(p) ((void*)(intptr_t)(p))
#endif

static int RedirectCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) {
    UNUSED(clientData);
    UNUSED(objc);
    UNUSED(objv);

    int fd = sd_journal_stream_fd("STDOUT-REDIRECTED", LOG_NOTICE, 0);
fprintf(stderr, "-- %s: fd=%d\n", __func__, fd);
fprintf(stderr, "-- %s: isatty=%d\n", __func__, isatty(fd));
    if (fd < 0) {
        Tcl_SetObjResult(interp, Tcl_ObjPrintf("failed to get journal fd: %s", Tcl_PosixError(interp)));
        return TCL_ERROR;
    }

    Tcl_Channel chan = Tcl_MakeFileChannel(INT2PTR(fd), TCL_WRITABLE);

    Tcl_SetStdChannel(chan, TCL_STDOUT);

    Tcl_RegisterChannel(0, chan);

    if (1) {
        int rc = Tcl_SetChannelOption(0, chan, "-buffering", "none");
        fprintf(stderr, "-- %s: Tcl_SetChannelOption -buffering none=%d\n", __func__, rc);
        Tcl_SetChannelOption(0, chan, "-translation", "auto crlf");
        fprintf(stderr, "-- %s: Tcl_SetChannelOption -translation auto crlf=%d\n", __func__, rc);
    }

    return TCL_OK;
}


DLLEXPORT int Redirecttcl_Init(Tcl_Interp * interp) {
    if (!Tcl_InitStubs(interp, "8.6", 0))
        return TCL_ERROR;

    Tcl_CreateObjCommand(interp, "redirect", RedirectCmd, 0, NULL);

    if (Tcl_PkgProvide(interp, "redirect", "0.1") != TCL_OK)
        return TCL_ERROR;

    return TCL_OK;
}

################################################################################
# Tcl driver:

puts PID=[pid]
puts ""

proc demo {} {
    for {set i 0} {$i < 10} {incr i} {
        puts "round $i"
        after 1000
    }
}

try {
    load redirecttcl.so
    puts "CHANNELS BEFORE: [chan names]"
    redirect
    puts "CHANNELS AFTER: [chan names]"
    demo
} on ok {} {
    puts "DONE!"
} on error {err opt} {
    catch {puts stderr "ERROR: $err"}
    catch {puts stderr "OPTIONS: $opt"}
}

################################################################################
# output:

PID=2717

CHANNELS BEFORE: stdin stdout stderr
-- RedirectCmd: fd=3
-- RedirectCmd: isatty=0
-- RedirectCmd: Tcl_SetChannelOption -buffering none=0
-- RedirectCmd: Tcl_SetChannelOption -translation auto crlf=0
CHANNELS AFTER: stdin file1 stderr stdout
round 0
round 1
round 2
round 3
round 4
round 5
round 6
round 7
round 8
round 9
DONE!