aboutsummaryrefslogtreecommitdiff
path: root/src/core/io_linux.c
blob: aaf6a181d3f3fb58df85fb8a49da0c08aaf1faac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#else
#include <unistd.h>
#include <poll.h>
#endif

#if !defined(_WIN32) && !defined(__wasm__)
#define VM_TLS _Thread_local
#else
#define VM_TLS
#endif
VM_TLS int J;

#ifdef _WIN32
static int pk(void){int c=getchar();ungetc(c,stdin);return c==EOF;}
char Q(void){int c=getchar();J=pk();return c;}
#else
/* input is read here, not through stdio, so the end-of-input flag J never blocks.
   a client that keeps the pipe open (an editor talking to the language server) sends
   one message and waits for the answer: peeking for the next byte after the last
   one would wait for a message that comes only after the answer. so J is 1 only
   when the end is known, and 0 when more may come. the output is flushed before
   any read that can wait, for the same reason. */
static VM_TLS unsigned char ib[65536];
static VM_TLS int ip, in, ieof;
/* make a byte available. wait is 0 to look without waiting. returns 1 when one is ready */
static int fill(int wait)
{
	int n;
	if (ip < in) return 1;
	if (ieof) return 0;
	if (!wait) {
		struct pollfd f; f.fd = 0; f.events = POLLIN; f.revents = 0;
		if (poll(&f, 1, 0) <= 0) return 0;	/* nothing yet: not the end, not a byte */
	} else fflush(stdout);
	n = (int)read(0, ib, sizeof ib);
	if (n <= 0) { ieof = 1; return 0; }
	ip = 0; in = n;
	return 1;
}
static int pk(void) { if (ip < in) return 0; if (ieof) return 1; fill(0); return ieof; }
char Q(void)
{
	int c;
	if (!fill(1)) { J = 1; return (char)-1; }
	c = ib[ip++];
	J = pk();
	return (char)c;
}
#endif
/* 1 when a byte can be read without waiting: buffered, or already on the pipe */
int input_pending(void)
{
#ifdef _WIN32
	return 0;
#else
	return fill(0);
#endif
}
#ifndef _WIN32
struct IoSnapshot { unsigned char bytes[65536]; int position, count, ended, flag; };
size_t io_context_size(void) { return sizeof(struct IoSnapshot); }
void io_context_snapshot(void *destination) {
 struct IoSnapshot *snapshot = destination;
 memcpy(snapshot->bytes, ib, sizeof ib); snapshot->position = ip; snapshot->count = in; snapshot->ended = ieof; snapshot->flag = J;
}
void io_context_restore(const void *source) {
 const struct IoSnapshot *snapshot = source;
 memcpy(ib, snapshot->bytes, sizeof ib); ip = snapshot->position; in = snapshot->count; ieof = snapshot->ended; J = snapshot->flag;
}
#endif
void G(char c){putchar(c);}

static void init_io(void) {
#ifdef _WIN32
	_setmode(_fileno(stdin), _O_BINARY);
	_setmode(_fileno(stdout), _O_BINARY);
	J = pk();
#else
	J = pk();
#endif
}

#if defined(__GNUC__) || defined(__clang__)
__attribute__((constructor)) static void init(void) { init_io(); }
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU", read)
static void __cdecl msc_init(void) { init_io(); }
__declspec(allocate(".CRT$XCU")) static void (__cdecl *msc_init_fn)(void) = msc_init;
#else
static void init(void) { init_io(); }
#endif