Skip to content

Commit 00fc2b2

Browse files
committed
ignore /build
1 parent 37b6bda commit 00fc2b2

File tree

3 files changed

+254
-0
lines changed

3 files changed

+254
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
22
.idea
33
npm-debug.log
4+
/build
45
/node_modules

binding.gyp

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "hello",
5+
"sources": [ "hello.cc" ]
6+
}
7+
]
8+
}

src/pos.cc

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
#include <node.h>
2+
#include <v8.h>
3+
#include <stdio.h>
4+
#include <fcntl.h>
5+
#include <errno.h>
6+
#include <unistd.h>
7+
#include <termios.h>
8+
9+
10+
#define RD_EOF -1
11+
#define RD_EIO -2
12+
13+
14+
using namespace v8;
15+
16+
17+
static inline int rd(const int fd)
18+
{
19+
unsigned char buffer[4];
20+
ssize_t n;
21+
22+
while (1) {
23+
n = read(fd, buffer, 1);
24+
25+
if (n > (ssize_t)0)
26+
return buffer[0];
27+
28+
else if (n == (ssize_t)0)
29+
return RD_EOF;
30+
31+
else if (n != (ssize_t)-1)
32+
return RD_EIO;
33+
34+
else if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
35+
return RD_EIO;
36+
}
37+
}
38+
39+
static inline int wr(const int fd, const char *const data, const size_t bytes)
40+
{
41+
const char *head = data;
42+
const char *const tail = data + bytes;
43+
ssize_t n;
44+
45+
while (head < tail) {
46+
47+
n = write(fd, head, (size_t)(tail - head));
48+
49+
if (n > (ssize_t)0)
50+
head += n;
51+
52+
else if (n != (ssize_t)-1)
53+
return EIO;
54+
55+
else if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
56+
return errno;
57+
}
58+
59+
return 0;
60+
}
61+
62+
/* Return a new file descriptor to the current TTY. */
63+
int current_tty(void)
64+
{
65+
const char *dev;
66+
int fd;
67+
68+
dev = ttyname(STDIN_FILENO);
69+
70+
if (!dev)
71+
dev = ttyname(STDOUT_FILENO);
72+
73+
if (!dev)
74+
dev = ttyname(STDERR_FILENO);
75+
76+
if (!dev) {
77+
errno = ENOTTY;
78+
return -1;
79+
}
80+
81+
do {
82+
fd = open(dev, O_RDWR | O_NOCTTY);
83+
} while (fd == -1 && errno == EINTR);
84+
85+
if (fd == -1)
86+
return -1;
87+
88+
return fd;
89+
}
90+
91+
/* As the tty for current cursor position.
92+
* This function returns 0 if success, errno code otherwise.
93+
* Actual errno will be unchanged.
94+
*/
95+
int cursor_position(const int tty, int *const rowptr, int *const colptr)
96+
{
97+
struct termios saved, temporary;
98+
int retval, result, rows, cols, saved_errno;
99+
100+
/* Bad tty? */
101+
if (tty == -1)
102+
return ENOTTY;
103+
104+
saved_errno = errno;
105+
106+
/* Save current terminal settings. */
107+
do {
108+
result = tcgetattr(tty, &saved);
109+
} while (result == -1 && errno == EINTR);
110+
111+
if (result == -1) {
112+
retval = errno;
113+
errno = saved_errno;
114+
return retval;
115+
}
116+
117+
/* Get current terminal settings for basis, too. */
118+
do {
119+
result = tcgetattr(tty, &temporary);
120+
} while (result == -1 && errno == EINTR);
121+
122+
if (result == -1) {
123+
retval = errno;
124+
errno = saved_errno;
125+
return retval;
126+
}
127+
128+
129+
/* Disable ICANON, ECHO, and CREAD. */
130+
temporary.c_lflag &= ~ICANON;
131+
temporary.c_lflag &= ~ECHO;
132+
temporary.c_cflag &= ~CREAD;
133+
134+
/* This loop is only executed once. When broken out,
135+
* the terminal settings will be restored, and the function
136+
* will return retval to caller. It's better than goto.
137+
*/
138+
do {
139+
/* Set modified settings. */
140+
do {
141+
result = tcsetattr(tty, TCSANOW, &temporary);
142+
} while (result == -1 && errno == EINTR);
143+
144+
if (result == -1) {
145+
retval = errno;
146+
break;
147+
}
148+
149+
/* Request cursor coordinates from the terminal. */
150+
retval = wr(tty, "\033[6n", 4);
151+
if (retval)
152+
break;
153+
154+
/* Assume coordinate reponse parsing fails. */
155+
retval = EIO;
156+
157+
/* Expect an ESC. */
158+
result = rd(tty);
159+
if (result != 27)
160+
break;
161+
162+
/* Expect [ after the ESC. */
163+
result = rd(tty);
164+
if (result != '[')
165+
break;
166+
167+
/* Parse rows. */
168+
rows = 0;
169+
result = rd(tty);
170+
while (result >= '0' && result <= '9') {
171+
rows = 10 * rows + result - '0';
172+
result = rd(tty);
173+
}
174+
175+
if (result != ';')
176+
break;
177+
178+
/* Parse cols. */
179+
cols = 0;
180+
result = rd(tty);
181+
while (result >= '0' && result <= '9') {
182+
cols = 10 * cols + result - '0';
183+
result = rd(tty);
184+
}
185+
186+
if (result != 'R')
187+
break;
188+
189+
/* Success! */
190+
191+
if (rowptr)
192+
*rowptr = rows;
193+
194+
if (colptr)
195+
*colptr = cols;
196+
197+
retval = 0;
198+
199+
} while (0);
200+
201+
/* Restore saved terminal settings. */
202+
do {
203+
result = tcsetattr(tty, TCSANOW, &saved);
204+
} while (result == -1 && errno == EINTR);
205+
206+
if (result == -1 && !retval)
207+
retval = errno;
208+
209+
/* Done. */
210+
return retval;
211+
}
212+
213+
void Method(const v8::FunctionCallbackInfo<Value>& args) {
214+
Isolate* isolate = Isolate::GetCurrent();
215+
HandleScope scope(isolate);
216+
217+
int ret, fd, row, col;
218+
219+
ret = 0;
220+
row = 0;
221+
col = 0;
222+
223+
fd = current_tty();
224+
if (fd == -1)
225+
return;
226+
227+
if (cursor_position(fd, &row, &col))
228+
return;
229+
230+
if (row < 1 || col < 1)
231+
return;
232+
233+
Local<Object> pos = Object::New(isolate);
234+
pos->Set(String::NewFromUtf8(isolate, "row"), Number::New(isolate, row));
235+
pos->Set(String::NewFromUtf8(isolate, "col"), Number::New(isolate, col));
236+
args.GetReturnValue().Set(pos);
237+
}
238+
239+
void Init(Handle<Object> exports) {
240+
Isolate* isolate = Isolate::GetCurrent();
241+
exports->Set(String::NewFromUtf8(isolate, "hello"),
242+
FunctionTemplate::New(isolate, Method)->GetFunction());
243+
}
244+
245+
NODE_MODULE(hello, Init)

0 commit comments

Comments
 (0)