물어보면 돼 ㅎㅎ
러스트 빠돌이가 해봤는지
열등감 개쩔어
비꼬면서 나까는거 봐라
ㅎㅎ
gpt나 제미니나 똑같은 얘기한다.
고급 수준이라고
궁금하면 코드 올리고 물어봐
ㅆㅇㅆ, 러빨러
너네들은 온니 나 까는게 목적이잖아
ㅎㅎㅎ
코드 llm한테 올리고 물어보라고.
열등감 개쩔어서
프갤에서 허수아비 공격하지 말고
할짓거리 없으면
야간 택배나 뎅기던가 해라.
// -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*-
/*
nimf-cons.c
This file is part of Nimf.
Copyright (C) 2022-2025 Hodong Kim
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef __linux__
#define _XOPEN_SOURCE 600 // posix_openpt()
#define _DEFAULT_SOURCE // cfmakeraw()
#endif
#include <stdlib.h>
#include <fcntl.h>
#include <libintl.h>
#include "c-mem.h"
#include <unistd.h>
#include "c-log.h"
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/uio.h>
#include "nimf-ic.h"
#include "clair.h"
#include "c-settings.h"
#include "nimf-key-syms.h"
#include <ctype.h>
#include <xkbcommon/xkbcommon.h>
#include "c-str.h"
#include "c-spawn.h"
#include "c-unix.h"
#ifdef __FreeBSD__
#include <sys/consio.h>
#include <sys/kbio.h>
// https://cgit.freebsd.org/src/plain/sys/dev/evdev/evdev_utils.c
uint16_t evdev_scancode2key(int *state, int scancode);
#elif defined(__linux__)
#include <linux/vt.h>
#include <linux/kd.h>
#else
#error "This platform is not supported"
#endif
typedef struct _Keyval2Vt100 Keyval2Vt100;
struct _Keyval2Vt100
{
uint32_t keyval;
char* code;
};
static Keyval2Vt100 keyval2vt100[] = {
{ NIMF_KEY_BackSpace, "\010" }, // 0xff08
{ NIMF_KEY_Tab, "\011" }, // 0xff09
{ NIMF_KEY_Return, "\012" }, // 0xff0d
{ NIMF_KEY_Escape, "\033" }, // 0xff1b
{ NIMF_KEY_Home, "\033[1~" }, // 0xff50
{ NIMF_KEY_Left, "\033[D" },
{ NIMF_KEY_Up, "\033[A" },
{ NIMF_KEY_Right, "\033[C" },
{ NIMF_KEY_Down, "\033[B" },
{ NIMF_KEY_Page_Up, "\033[5~" },
{ NIMF_KEY_Page_Down, "\033[6~" },
{ NIMF_KEY_End, "\033[4~" }, // 0xff57
{ NIMF_KEY_Insert, "\033[2~" }, // 0xff63
{ NIMF_KEY_F1, "\033OP" }, // 0xffbe
{ NIMF_KEY_F2, "\033OQ" },
{ NIMF_KEY_F3, "\033OR" },
{ NIMF_KEY_F4, "\033OS" },
{ NIMF_KEY_F5, "\033[15~" },
{ NIMF_KEY_F6, "\033[17~" },
{ NIMF_KEY_F7, "\033[18~" },
{ NIMF_KEY_F8, "\033[19~" },
{ NIMF_KEY_F9, "\033[20~" },
{ NIMF_KEY_F10, "\033[21~" },
{ NIMF_KEY_F11, "\033[23~" },
{ NIMF_KEY_F12, "\033[24~" }, // 0xffc9
{ NIMF_KEY_Delete, "\033[3~" }, // 0xffff
};
typedef struct xkb_context XkbContext;
typedef struct xkb_keymap XkbKeymap;
typedef struct xkb_state XkbState;
extern char** environ;
static clair_event_loop_t* nimf_cons_loop;
typedef struct _NimfCons NimfCons;
struct _NimfCons {
int fd1;
pid_t pid;
struct termios attr;
struct winsize size;
bool attr_stored;
int kbmode;
CimIcHandle ic;
XkbContext* context;
XkbKeymap* keymap;
XkbState* state;
};
static void nimf_cons_restore (NimfCons* cons)
{
if (cons->kbmode > -1)
if (ioctl (STDIN_FILENO, KDSKBMODE, cons->kbmode) == -1)
c_log_critical ("KDSKBMODE failed: %s", strerror (errno));
if (cons->attr_stored)
if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &cons->attr) == -1)
c_log_critical ("tcsetattr failed: %s", strerror (errno));
}
static void nimf_cons_free (NimfCons* cons)
{
nimf_cons_restore (cons);
if (nimf_cons_loop)
{
clair_event_loop_destroy (nimf_cons_loop);
nimf_cons_loop = NULL;
}
if (cons->fd1 > -1)
close (cons->fd1);
if (cons->pid > 0)
waitpid (cons->pid, NULL, 0);
xkb_state_unref (cons->state);
xkb_keymap_unref (cons->keymap);
xkb_context_unref (cons->context);
if (cons->ic)
{
cim_ic_focus_out (cons->ic);
cim_ic_destroy (cons->ic);
}
free (cons);
}
static void cb_fd (clair_event_source_t* io,
clair_fd_t fd,
clair_event_mask_t events,
void* user_data)
{
if (events & (CLAIR_EVENT_ERROR | CLAIR_EVENT_HANG_UP))
{
clair_event_loop_remove (nimf_cons_loop, io);
clair_event_loop_quit (nimf_cons_loop);
return;
}
NimfCons* cons = (NimfCons*) user_data;
ssize_t n_read;
uint8_t buf[16];
n_read = c_read (fd, buf, sizeof buf);
if (n_read > 0)
{
if (c_write (STDOUT_FILENO, buf, n_read) != n_read)
c_log_critical ("write failed: %s", strerror (errno));
const CimPreedit* preedit = cim_ic_get_preedit (cons->ic);
if (preedit->text[0])
{
size_t len;
struct iovec iov[3];
iov[0].iov_base = "\033[s";
iov[0].iov_len = strlen (iov[0].iov_base);
iov[1].iov_base = preedit->text;
iov[1].iov_len = strlen (iov[1].iov_base);
iov[2].iov_base = "\033[u";
iov[2].iov_len = strlen (iov[2].iov_base);
len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
if (writev (STDOUT_FILENO, iov, 3) != len)
{
c_log_critical ("%s:", strerror (errno));
clair_event_loop_remove (nimf_cons_loop, io);
return;
}
}
}
}
static int cb_compare (const void* a, const void* b)
{
const int* keyval = a;
const Keyval2Vt100* key = b;
return (*keyval - key->keyval);
}
static void cb_stdin (clair_event_source_t* io,
clair_fd_t fd,
clair_event_mask_t events,
void* user_data)
{
if (events & (CLAIR_EVENT_ERROR | CLAIR_EVENT_HANG_UP))
{
clair_event_loop_remove (nimf_cons_loop, io);
clair_event_loop_quit (nimf_cons_loop);
return;
}
NimfCons* cons = (NimfCons*) user_data;
uint8_t scancode;
uint16_t keycode;
ssize_t n_read;
CimEvent event;
#ifdef __FreeBSD__
int state = 0;
do {
#endif
n_read = c_read (STDIN_FILENO, &scancode, sizeof (uint8_t));
if (n_read != sizeof (uint8_t))
{
c_log_critical ("read failed");
clair_event_loop_remove (nimf_cons_loop, io);
return;
}
if (scancode & 0x80)
event.type = CIM_EVENT_KEY_RELEASE;
else
event.type = CIM_EVENT_KEY_PRESS;
#ifdef __FreeBSD__
keycode = evdev_scancode2key (&state, scancode);
} while (state);
#elif defined __linux__
keycode = scancode & 0x7f;
#else
#error "This platform is not supported"
#endif
if (keycode)
event.keycode = keycode + 8;
event.keyval = xkb_state_key_get_one_sym (cons->state, event.keycode);
xkb_mod_mask_t mask;
mask = xkb_state_serialize_mods (cons->state,
XKB_STATE_MODS_DEPRESSED |
XKB_STATE_MODS_LATCHED);
event.state = mask;
if (event.type == CIM_EVENT_KEY_PRESS)
xkb_state_update_key (cons->state, event.keycode, XKB_KEY_DOWN);
else
xkb_state_update_key (cons->state, event.keycode, XKB_KEY_UP);
bool retval = cim_ic_filter_event (cons->ic, &event);
if (!retval && event.type == CIM_EVENT_KEY_PRESS)
{
char* text = NULL;
if (0x20 <= event.keyval && event.keyval <= 0x07e)
{
text = (char[]) { event.keyval, 0 };
}
else
{
const size_t len = C_N_ELEMENTS (keyval2vt100);
const Keyval2Vt100* key;
key = bsearch (&event.keyval, keyval2vt100, len,
sizeof (keyval2vt100[0]), cb_compare);
if (key)
text = key->code;
}
if (event.keyval >= NIMF_KEY_F1 && event.keyval <= NIMF_KEY_F12)
{
if (event.state & NIMF_MOD1_MASK) // alt
{
if (ioctl (STDIN_FILENO, VT_ACTIVATE,
event.keyval - NIMF_KEY_F1 + 1) == -1)
c_log_critical ("VT_ACTIVATE failed");
return;
}
}
else if (event.keyval >= NIMF_KEY_Switch_VT_1 &&
event.keyval <= NIMF_KEY_Switch_VT_12)
{
if (ioctl (STDIN_FILENO, VT_ACTIVATE,
event.keyval - NIMF_KEY_Switch_VT_1 + 1) == -1)
c_log_critical ("VT_ACTIVATE failed");
return;
}
if (text)
{
size_t n_bytes = strlen (text);
if (n_bytes == 1)
{
if (event.state & NIMF_CONTROL_MASK)
{
if (text[0] == 'c')
text[0] = 3; // ETX
else if (text[0] == 'd')
text[0] = 4; // EOT
}
}
if (n_bytes > 0)
{
if (c_write (cons->fd1, text, n_bytes) != n_bytes)
c_log_critical ("write failed");
}
}
}
}
static bool cons_save_term (NimfCons* cons)
{
if (tcgetattr (STDIN_FILENO, &cons->attr) == -1)
return false;
cons->attr_stored = true;
if (ioctl (STDIN_FILENO, TIOCGWINSZ, &cons->size) == -1 ||
ioctl (STDIN_FILENO, KDGKBMODE, &cons->kbmode) == -1)
return false;
return true;
}
static bool cons_set_term (NimfCons* cons)
{
struct termios attr;
attr = cons->attr;
cfmakeraw (&attr);
attr.c_iflag = IGNPAR | IGNBRK;
attr.c_oflag = OPOST | ONLCR;
attr.c_cflag = CREAD | CS8;
attr.c_lflag &= ~(ICANON | ECHO | ISIG);
attr.c_cc[VTIME] = 0;
attr.c_cc[VMIN] = 1;
if (tcsetattr (STDIN_FILENO, TCSANOW | TCSAFLUSH, &attr) == -1)
return false;
#ifdef __FreeBSD__
if (ioctl (STDIN_FILENO, KDSKBMODE, K_RAW) == -1)
return false;
#elif defined __linux__
if (ioctl (STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW) == -1)
return false;
#else
#error "This platform is not supported"
#endif
return true;
}
static void cb_preedit_changed (CimIcHandle ic,
const CimPreedit* preedit,
void* user_data)
{
size_t len;
struct iovec iov[3];
iov[0].iov_base = "\033[s";
iov[0].iov_len = strlen (iov[0].iov_base);
if (preedit->text[0])
iov[1].iov_base = preedit->text;
else
iov[1].iov_base = " ";
iov[1].iov_len = strlen (iov[1].iov_base);
iov[2].iov_base = "\033[u";
iov[2].iov_len = strlen (iov[2].iov_base);
len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
if (writev (STDOUT_FILENO, iov, 3) != len)
c_log_critical ("%s", strerror (errno));
}
static void cb_commit (CimIcHandle ic, const char* text, void* user_data)
{
size_t n_bytes = strlen (text);
NimfCons* cons = (NimfCons*) user_data;
if (c_write (cons->fd1, text, n_bytes) != n_bytes)
c_log_critical ("write failed: %s", strerror (errno));
}
const static CimCallbacks callbacks = {
.preedit_changed = cb_preedit_changed,
.commit = cb_commit
};
NimfCons* nimf_cons_new ()
{
NimfCons* cons;
cons = c_calloc (1, sizeof (NimfCons));
cons->kbmode = -1;
cons->fd1 = posix_openpt (O_RDWR | O_NOCTTY);
if (cons->fd1 == -1 ||
grantpt (cons->fd1) == -1 ||
unlockpt (cons->fd1) == -1 ||
!cons_save_term (cons) ||
!cons_set_term (cons))
{
c_log_critical ("%s", strerror (errno));
nimf_cons_free (cons);
return NULL;
}
return cons;
}
bool nimf_cons_fork (NimfCons* cons)
{
cons->pid = fork ();
if (cons->pid == 0) // child
{
const char* pts_name = ptsname (cons->fd1);
if (!pts_name)
{
c_log_critical ("ptsname failed: %s", strerror (errno));
exit (1);
}
int fd2 = open (pts_name, O_RDWR);
if (fd2 == -1)
{
c_log_critical ("open failed: %s", strerror (errno));
exit (1);
}
close (cons->fd1);
if (setsid () == -1 ||
ioctl (fd2, TIOCSCTTY, NULL) == -1 ||
ioctl (fd2, TIOCSWINSZ, &cons->size) == -1 ||
dup2 (fd2, 0) == -1 ||
dup2 (fd2, 1) == -1 ||
dup2 (fd2, 2) == -1)
{
c_log_critical ("%s", strerror (errno));
exit (1);
}
if (fd2 > 2)
close (fd2);
char* shell = getenv ("SHELL");
if (!shell)
shell = "/bin/sh";
char* args[] = { shell, NULL };
if (!getenv ("TERM"))
setenv ("TERM", "dumb", 1);
if (execve (args[0], args, environ) == -1)
{
c_log_critical ("execve failed: %s", strerror (errno));
exit (1);
}
}
else if (cons->pid > 0) // parent
{
struct xkb_rule_names rmlvo;
CSettings* settings;
char* conf_dir;
const char* layout;
const char* variant;
char** options;
if (!(cons->context = xkb_context_new (XKB_CONTEXT_NO_FLAGS)))
{
c_log_critical ("xkb_context_new failed");
return false;
}
conf_dir = nimf_get_config_dir ();
if (!conf_dir)
{
c_log_critical ("nimf_get_config_dir failed");
return false;
}
settings = c_settings_new (conf_dir, NIMF_SETTINGS_SCHEMA_DIR, "nimf.inputs.console");
layout = c_settings_get_string (settings, "layout");
variant = c_settings_get_string (settings, "variant");
options = c_settings_get_strv (settings, "options");
rmlvo.rules = "evdev";
rmlvo.model = "pc105";
rmlvo. layout = layout;
rmlvo.variant = variant;
rmlvo.options = c_strv_join ((const char**) options, ",");
cons->keymap = xkb_keymap_new_from_names (cons->context, &rmlvo, 0);
free (conf_dir);
c_strv_free (options);
c_settings_free (settings);
free ((char*) rmlvo.options);
if (cons->keymap == NULL)
{
c_log_critical ("xkb_keymap_new_from_names failed");
return false;
}
cons->state = xkb_state_new (cons->keymap);
char* path = cim_get_cim_so_path ();
if (access (path, F_OK))
{
if (symlink (IM_NIMF_SO_PATH, path))
c_log_warning ("symlink failed:", strerror (errno));
}
free (path);
cons->ic = cim_ic_create ();
cim_ic_set_callbacks (cons->ic, &callbacks, cons);
cim_ic_focus_in (cons->ic);
nimf_cons_loop = clair_event_loop_create ();
clair_event_loop_add_watch (nimf_cons_loop,
cons->fd1,
CLAIR_EVENT_INPUT,
cb_fd,
cons);
clair_event_loop_add_watch (nimf_cons_loop,
STDIN_FILENO,
CLAIR_EVENT_INPUT,
cb_stdin,
cons);
return true;
}
c_log_critical ("fork failed: %s", strerror (errno));
return false;
}
bool nimf_cons_run (NimfCons* cons)
{
if (nimf_cons_loop)
return clair_event_loop_run (nimf_cons_loop);
return true;
}
static void cb_signal (int signo)
{
if (nimf_cons_loop)
clair_event_loop_quit (nimf_cons_loop);
}
int main ()
{
NimfCons* cons = NULL;
#ifdef __FreeBSD__
bool font_loaded = false;
#endif
const char* warning = gettext (
"\033[7mWARNING\033[0m Nimf Console Input Method is an alpha version.\n"
"This software is provided to demonstrate multilingual input on the console.\n"
"\033[92mThis software has not been fully tested and may crash your terminal.\033[0m\n"
"Would you like to run it anyway? [y/N]: ");
printf ("%s", warning);
int retval = 1;
char buf[3];
if (!fgets (buf, 3, stdin))
goto finally;
c_str_chomp (buf);
if (strlen (buf) != 1 || (buf[0] != 'y' && buf[0] != 'Y'))
goto finally;
setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, NIMF_LOCALE_DIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
if (!isatty (STDIN_FILENO))
goto finally;
#ifdef __FreeBSD__
int status;
if (c_spawn (&status, "/usr/sbin/vidcontrol", "-f",
"/usr/share/vt/fonts/duos.fnt", NULL))
{
if (!status)
{
font_loaded = true;
c_spawn (NULL, "/usr/bin/clear", NULL);
}
else
{
c_log_warning ("duos.fnt is not loaded");
}
}
#endif
cons = nimf_cons_new ();
if (!cons)
goto finally;
struct sigaction action;
action.sa_flags = 0;
action.sa_handler = cb_signal;
sigemptyset (&action.sa_mask);
// Can't catch SIGKILL and SIGSTOP
int signals[] = {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS,
SIGSEGV, SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGTSTP, SIGCHLD, SIGTTIN,
SIGTTOU, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGUSR1, SIGUSR2,
#ifdef SIGEMT
SIGEMT,
#endif
#ifdef SIGTHR
SIGTHR,
#endif
#ifdef SIGLIBRT
SIGLIBRT,
#endif
#ifdef SIGPOLL
SIGPOLL
#endif
};
for (int i = 0; i < C_N_ELEMENTS (signals); i++)
sigaction (signals[i], &action, NULL);
if (nimf_cons_fork (cons))
{
puts ("\033[7mNimf Console Input Method started\033[0m");
retval = !nimf_cons_run (cons);
}
else
{
c_log_critical ("nimf_cons_fork failed");
}
finally:
#ifdef __FreeBSD__
if (font_loaded)
{
c_spawn (NULL, "/usr/sbin/vidcontrol", "-f", NULL);
c_spawn (NULL, "/usr/bin/clear", NULL);
}
#endif
if (cons)
nimf_cons_free (cons);
if (errno && errno != EINTR)
perror ("nimf-cons only works on the console");
if (!retval)
puts ("\033[7mNimf Console Input Method exits\033[0m");
return retval;
}
댓글 0