blob: 98362d933da30d87c595f04d71eb081da7e188b1 [file] [log] [blame]
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "fsatrace.h"
#include "emit.h"
static int write_fd;
static char bopts[256];
static const char *
mygetenv(const char *v)
{
const char *out = getenv(v);
if (!out) {
extern char **environ;
size_t l = strlen(v);
char **p = environ;
while (*p) {
char *s = *p;
if (0 == strncmp(s, v, l)) {
if (s[l] == '=') {
out = s + l + 1;
break;
}
}
p++;
}
}
#ifdef _WIN32
// Workaround, bash distributed with ghc 8.6.5 seems to discard most
// environment variables, pass environment variables as the first few
// PATH components.
if (!out) {
const char *path = getenv("PATH");
if (strcmp(v, ENVOUT) == 0) {
static char buf[PATH_MAX];
unsigned i = 0;
unsigned j = 0;
while (path[i] != ';')
buf[j++] = path[i++];
buf[j] = 0;
out = buf;
}
}
#endif
return out;
}
int
emitInit()
{
const char *fifo = mygetenv(ENV_FIFO_PATH);
assert(fifo);
if ((write_fd = open(fifo, O_CREAT | O_WRONLY)) < 0) {
fprintf(stderr, "emitInit failed to open %s: %s\n",
fifo, strerror(errno));
return -1;
}
const char *opts = mygetenv(ENV_OPTS);
memset(bopts, 0, sizeof(bopts));
while (*opts)
bopts[(unsigned char)*opts++] = 1;
return 0;
}
int
emitTerm()
{
return close(write_fd);
}
// Write |bufsize| bytes from |buffer| into |fd|.
// Return true on success, and false/errno on failure.
bool
do_full_write(int fd, const void *buffer, size_t bufsize)
{
const char *buf = (const char *)(buffer);
while (bufsize > 0) {
ssize_t ret = write(fd, buf, bufsize);
if (ret < 0) {
if (errno == EINTR)
continue;
return false; // a real error occurred.
}
buf += ret;
bufsize -= (size_t)(ret);
}
return true;
}
void
emitOp(int oc, const char *op1, const char *p2)
{
uint32_t sz;
uint32_t s1;
uint32_t s2;
char *p;
const char *p1;
int c;
if (!bopts[tolower(oc)])
return;
p1 = op1 ? op1 : "<unknown>";
c = op1 ? oc : toupper(oc);
s1 = strlen(p1);
sz = s1 + 3;
if (p2) {
s2 = strlen(p2);
sz += s2 + 1;
}
char buf[sz];
p = buf;
*p++ = c;
*p++ = '|';
memcpy(p, p1, s1);
p += s1;
if (p2) {
*p++ = '|';
memcpy(p, p2, s2);
p += s2;
}
*p++ = '\n';
if (!do_full_write(write_fd, buf, sz))
fprintf(stderr, "emitOp failed to write to fd %d: %s\n",
write_fd, strerror(errno));
}