/*
 * simple test program for libexec
 *
 * (c) 2024 Dario Rodriguez <antartica@whereismybit.com>
 * This file is in the public domain.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <sys/select.h>
#include "libexec.h"

volatile int flag_sigint;
volatile int flag_sigchld;
void sigchld(int sig);
void sigint(int sig);


int
main(int argc, char *argv[], char *envp[])
{
        struct timeval tv;
        exec_t *dateexec,*echoexec,*catexec;
        exec_t *exec;
        fd_set readset,writeset;
        flag_sigchld=flag_sigint=0;
        int maxfd;
        int i;
        int queued,nread;
        int fd;
        char *fdname;
        time_t curtimet,lasttimet;
        executil_installsignal(SIGINT,sigint);
        executil_installsignal(SIGCHLD,sigchld);
        dateexec=exec_init("date","/bin/sh -c \"while true ; do sleep 1 ; date ; echo . >&2 ; done\"",envp);
        echoexec=exec_init("echo","/bin/echo \"%s\"",envp);
        catexec=exec_init("cat","/bin/cat",envp);
        exec_open(dateexec,NULL);
        exec_open(catexec,NULL);
        lasttimet=0;
        while(flag_sigint==0) {
                int *readfds[]={
                  &(dateexec->fdout),
                  &(dateexec->fderr),
                  &(echoexec->fdout),
                  &(echoexec->fderr),
                  &(catexec->fdout),
                  &(catexec->fderr),
                };
                if(flag_sigchld) {
                        exec_t *execs[]={dateexec,echoexec,catexec};
                        flag_sigchld=0;
                        exec_reap(dateexec,echoexec,catexec,NULL);
                        for(i=0;i<(sizeof(execs)/sizeof(execs[0]));i++) {
                                exec=execs[i];
                                if(exec->laststatus!=-1)
                                        fprintf(stderr,"%s: exited with status %i\n",exec->name,exec->laststatus),exec->laststatus=-1;
                        }
                }
                tv.tv_sec=1,tv.tv_usec=0;
                maxfd=0;
                FD_ZERO(&readset);
                for(i=0;i<(sizeof(readfds)/sizeof(readfds[0]));i++) {
                        if(*(readfds[i])==-1)
                                continue;
                        FD_SET(*(readfds[i]),&readset);
                        maxfd=(maxfd<*(readfds[i]))?*(readfds[i]):maxfd;
                }
                FD_ZERO(&writeset);
                curtimet=time(NULL);
                if(catexec->fdin!=-1 && curtimet!=lasttimet) {
                        FD_SET(catexec->fdin,&writeset);
                        maxfd=(maxfd<catexec->fdin)?catexec->fdin:maxfd;
                }
                select(maxfd+1,&readset,&writeset,NULL,&tv);
#if 1
fprintf(stderr,"ITERATION\n");
#endif
                for(i=0;i<(sizeof(readfds)/sizeof(readfds[0]));i++) {
                        if(*(readfds[i])==-1 || !FD_ISSET(*(readfds[i]),&readset) || (exec=executil_fd2exec(*(readfds[i]),dateexec,echoexec,catexec,NULL))==NULL)
                                continue;
                        fd=*(readfds[i]);
                        fdname=(fd==exec->fdout)?"stdout":"stderr";
                        queued=executil_queued(fd);
                        if(queued<=0) {
                                /* remote closed connection */
                                fprintf(stderr,"%s:%s: remote closed connection (queued:%i)\n",exec->name,fdname,queued);
                                exec_close(exec);
                                continue;
                        } else {
                                char buf[1024];
                                queued=(queued>(sizeof(buf)-1))?(sizeof(buf)-1):queued;
                                if((nread=read(fd,buf,queued))<queued) {
                                        fprintf(stderr,"%s:%s short read (%i<%i)\n",exec->name,fdname,nread,queued);
                                        exec_close(exec);
                                }
                                buf[nread]='\0';
                                fprintf(stderr,"%s:%s: read \"",exec->name,fdname);
                                fwrite(buf,1,nread,stderr);
                                fprintf(stderr,"\"\n");
                        }
                }
                if(catexec->fdin!=-1 && FD_ISSET(catexec->fdin,&writeset)) {
                        char msg[32];
                        snprintf(msg,sizeof(msg),"%li\n",(long)curtimet);
                        msg[sizeof(msg)-1]='\0';
                        write(catexec->fdin,msg,strlen(msg));
                        lasttimet=curtimet;
                }
                if((time(NULL)%5)==0) {
                        exec_open(echoexec,"multi 5s");
                }
        }
        return(0);
}

void
sigint(int sig)
{
        flag_sigint++;
}

void
sigchld(int sig)
{
        flag_sigchld++;
}