mistral gagnant

This commit is contained in:
Giorgio ar work
2026-02-04 16:16:36 +01:00
parent 87746f09ce
commit cce1ffa903
39 changed files with 12917 additions and 11802 deletions
+1
View File
@@ -87,4 +87,5 @@
(map-key "\"" editor-split-screen-vertical "user")
(map-key "o" editor-switch-next-pane "user")
(map-key "*" editor-unify-panes "user")
(map-key "t" editor-create-terminal "user")
+14
View File
@@ -55,4 +55,18 @@ int bufferSave(void);
*/
int bufferSaveAll(void);
/**
* @brief Creates a new terminal buffer
* @return Buffer ID on success, -1 on failure
*/
int bufferCreateTerminal(void);
/**
* @brief Executes a command in the terminal buffer
* @param buffer_id The terminal buffer ID
* @param command The command to execute
* @return 0 on success, -1 on failure
*/
int bufferExecuteTerminalCommand(int buffer_id, const char *command);
#endif
+4
View File
@@ -53,4 +53,8 @@ Lisp editorUnifiedPanes(Lisp args, LispError *e, LispContext ctx);
void free_structs(void);
// Terminal
Lisp editorCreateTerminal(Lisp args, LispError *e, LispContext ctx);
#endif
+12 -1
View File
@@ -2,9 +2,14 @@
#define DATA_H_
#include <stdio.h>
#include <termios.h>
#include <time.h>
#ifdef _WIN32
#include "termiWin.h"
#else
#include <termios.h>
#endif
#include "lisp.h"
/**
@@ -106,6 +111,12 @@ struct buffer_t {
int dirty; /**< Has this buffer been modified since last save */
int row_offset; /**< Scroll offset for rows in this buffer */
int col_offset; /**< Scroll offset for columns in this buffer */
// Terminal-specific data
char *terminal_command; /**< Current command being executed */
int terminal_pid; /**< Process ID of running terminal command */
char *terminal_output; /**< Captured terminal output */
int terminal_output_size; /**< Size of terminal output */
};
/**
+6 -4
View File
@@ -1527,7 +1527,7 @@ typedef enum
TOKEN_CHAR,
TOKEN_BOOL,
TOKEN_HASH_L_PAREN,
} TokenType;
} LispTokenType;
/* for debug
static const char* token_type_name[] = {
@@ -1541,7 +1541,7 @@ typedef struct
const char* token_start;
const char* token_end;
TokenType token;
LispTokenType token;
} Lexer;
static
@@ -2178,9 +2178,11 @@ Lisp lisp_read_path(const char *path, LispError* out_error, LispContext ctx)
return l;
#else
FILE* file = fopen(path);
FILE* file = fopen(path, "r");
if (file) {
lisp_read_file(file, out_error, ctx);
fclose(path);
fclose(file);
}
#endif
return lisp_eof();
}
+3 -2
View File
@@ -9,14 +9,15 @@
// Token types
typedef enum {
TOKEN_KEYWORD,
TOKEN_TYPE,
TOKEN_DATATYPE,
TOKEN_STRING,
TOKEN_COMMENT,
TOKEN_NUMBER,
TOKEN_OPERATOR,
TOKEN_DEFAULT
} TokenType;
} SyntaxTokenType;
const char *get_color(SyntaxTokenType type);
char *highlight_line(const char * line, int *length);
#endif
+217
View File
@@ -0,0 +1,217 @@
/* termiWin.h
*
* Copyright (C) 2017 Christian Visintin - christian.visintin1997@gmail.com
*
* This file is part of "termiWin: a termios porting for Windows"
*
* termiWin is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* termiWin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with termiWin. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#ifndef TERMIWIN_H_
#define TERMIWIN_H_
#define TERMIWIN_VERSION "1.2.0"
#define TERMIWIN_MAJOR_VERSION 1
#define TERMIWIN_MINOR_VERSION 2
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#ifdef _MSC_VER
#pragma comment(lib, "Ws2_32.lib")
#endif
/*Redefining functions from winsock to termiWin. This is very important since winsock2 defines functions such as close as closesocket we have to redefine it*/
#ifdef __MINGW32__
#define TERMIWIN_DONOTREDEFINE
#endif
#ifndef TERMIWIN_DONOTREDEFINE
#define read read_serial
#define write serial_write
#define open open_serial
#define close close_serial
#define select select_serial
#endif
#if !defined(SSIZE_MAX)
// ssize_t
#if SIZE_MAX == UINT_MAX
typedef int ssize_t; /* common 32 bit case */
#define SSIZE_MAX INT_MAX
#elif SIZE_MAX == ULONG_MAX
typedef long ssize_t; /* linux 64 bits */
#define SSIZE_MAX LONG_MAX
#elif SIZE_MAX == ULLONG_MAX
typedef long long ssize_t; /* windows 64 bits */
#define SSIZE_MAX LLONG_MAX
#endif
#endif
//Serial options - Linux -> Windows
/*setAttr flags - ~ in front of flags -> deny them*/
//iFlag
#define INPCK 0x00004000 /*If this bit is set, input parity checking is enabled. If it is not set, no checking at all is done for parity errors on input; the characters are simply passed through to the application.*/
#define IGNPAR 0x00001000 /*If this bit is set, any byte with a framing or parity error is ignored. This is only useful if INPCK is also set.*/
#define PARMRK 0x00040000 /*If this bit is set, input bytes with parity or framing errors are marked when passed to the program. This bit is meaningful only when INPCK is set and IGNPAR is not set.*/
#define ISTRIP 0x00008000 /*If this bit is set, valid input bytes are stripped to seven bits; otherwise, all eight bits are available for programs to read. */
#define IGNBRK 0x00000400 /*If this bit is set, break conditions are ignored. */
#define BRKINT 0x00000100 /*If this bit is set and IGNBRK is not set, a break condition clears the terminal input and output queues and raises a SIGINT signal for the foreground process group associated with the terminal. */
#define IGNCR 0x00000800 /*If this bit is set, carriage return characters ('\r') are discarded on input. Discarding carriage return may be useful on terminals that send both carriage return and linefeed when you type the RET key. */
#define ICRNL 0x00000200 /*If this bit is set and IGNCR is not set, carriage return characters ('\r') received as input are passed to the application as newline characters ('\n').*/
#define INLCR 0x00002000 /*If this bit is set, newline characters ('\n') received as input are passed to the application as carriage return characters ('\r').*/
#define IXOFF 0x00010000 /*If this bit is set, start/stop control on input is enabled. In other words, the computer sends STOP and START characters as necessary to prevent input from coming in faster than programs are reading it. The idea is that the actual terminal hardware that is generating the input data responds to a STOP character by suspending transmission, and to a START character by resuming transmission.*/
#define IXON 0x00020000 /*If this bit is set, start/stop control on output is enabled. In other words, if the computer receives a STOP character, it suspends output until a START character is received. In this case, the STOP and START characters are never passed to the application program. If this bit is not set, then START and STOP can be read as ordinary characters.*/
//lFlag
#define ICANON 0x00001000 /*This bit, if set, enables canonical input processing mode. Otherwise, input is processed in noncanonical mode. */
#define ECHO 0x00000100 /*If this bit is set, echoing of input characters back to the terminal is enabled.*/
#define ECHOE 0x00000200 /*If this bit is set, echoing indicates erasure of input with the ERASE character by erasing the last character in the current line from the screen. Otherwise, the character erased is re-echoed to show what has happened (suitable for a printing terminal). */
#define ECHOK 0x00000400 /*This bit enables special display of the KILL character by moving to a new line after echoing the KILL character normally. The behavior of ECHOKE (below) is nicer to look at.*/
#define ECHONL 0x00000800 /*If this bit is set and the ICANON bit is also set, then the newline ('\n') character is echoed even if the ECHO bit is not set. */
#define ISIG 0x00004000 /*This bit controls whether the INTR, QUIT, and SUSP characters are recognized. The functions associated with these characters are performed if and only if this bit is set. Being in canonical or noncanonical input mode has no effect on the interpretation of these characters. */
#define IEXTEN 0x00002000 /*On BSD systems and GNU/Linux and GNU/Hurd systems, it enables the LNEXT and DISCARD characters.*/
#define NOFLSH 0x00008000 /*Normally, the INTR, QUIT, and SUSP characters cause input and output queues for the terminal to be cleared. If this bit is set, the queues are not cleared. */
#define TOSTOP 0x00010000 /*If this bit is set and the system supports job control, then SIGTTOU signals are generated by background processes that attempt to write to the terminal.*/
//cFlag
#define CSTOPB 0x00001000 /*If this bit is set, two stop bits are used. Otherwise, only one stop bit is used. */
#define PARENB 0x00004000 /*If this bit is set, generation and detection of a parity bit are enabled*/
#define PARODD 0x00008000 /*This bit is only useful if PARENB is set. If PARODD is set, odd parity is used, otherwise even parity is used. */
#define CSIZE 0x00000c00 /*This is a mask for the number of bits per character. */
#define CS5 0x00000000 /*This specifies five bits per byte. */
#define CS6 0x00000400 /*This specifies six bits per byte. */
#define CS7 0x00000800 /*This specifies seven bits per byte. */
#define CS8 0x00000c00 /*This specifies eight bits per byte. */
#define CLOCAL 0x00000000 /*Ignore modem control lines -> ignore data carrier detected - not implementable in windows*/
#define CREAD 0x00000000 /*Enable receiver - if is not set no character will be received*/
//oFlag
#define OPOST 0x00000100 /*If this bit is set, output data is processed in some unspecified way so that it is displayed appropriately on the terminal device. This typically includes mapping newline characters ('\n') onto carriage return and linefeed pairs. */
//cc
#define VEOF 0
#define VEOL 1
#define VERASE 2
#define VINTR 3
#define VKILL 4
#define VMIN 5 /*If set to 0, serial communication is NOT-BLOCKING, otherwise is BLOCKING*/
#define VQUIT 6
#define VSTART 7
#define VSTOP 8
#define VSUSP 9
#define VTIME 10
//END OF setAttr flags
/*Controls*/
#define TIOMBIC DTR_CONTROL_DISABLE
#define TIOMBIS DTR_CONTROL_ENABLE
#define CRTSCTS RTS_CONTROL_ENABLE
/*Others*/
#define NCCS 11
//Baud speed
#define B110 CBR_110
#define B300 CBR_300
#define B600 CBR_600
#define B1200 CBR_2400
#define B2400 CBR_2400
#define B4800 CBR_4800
#define B9600 CBR_9600
#define B19200 CBR_19200
#define B38400 CBR_38400
#define B57600 CBR_57600
#define B115200 CBR_115200
/*Attributes optional_actions*/
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
/*TCFLUSH options*/
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
/*TCFLOW optons*/
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
//typdef
typedef unsigned tcflag_t; /*This is an unsigned integer type used to represent the various bit masks for terminal flags.*/
typedef unsigned cc_t; /*This is an unsigned integer type used to represent characters associated with various terminal control functions.*/
typedef unsigned speed_t; /*used for terminal baud rates*/
typedef struct termios
{
tcflag_t c_iflag; /*input modes*/
tcflag_t c_oflag; /*output modes*/
tcflag_t c_cflag; /*control modes*/
tcflag_t c_lflag; /*local modes*/
cc_t c_cc[NCCS]; /*special character*/
} termios;
//Serial configuration functions
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
int tcsendbreak(int fd, int duration);
int tcdrain(int fd);
int tcflush(int fd, int queue_selector);
int tcflow(int fd, int action);
void cfmakeraw(struct termios *termios_p);
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int cfsetspeed(struct termios * termios_p, speed_t speed);
//Write/Read/Open/Close/Select Functions
ssize_t read_serial(int fd, void* buffer, size_t count);
ssize_t write_serial(int fd, const void* buffer, size_t count);
int open_serial(const char* portname, int opt);
int close_serial(int fd);
int select_serial(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
//get Handle out of the COM structure
HANDLE getHandle();
#endif
#ifndef _WIN32
#pragma message("-Warning: termiWin requires a Windows system!")
#endif
#endif
+1 -2
View File
@@ -9,8 +9,7 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <termios.h>
// #include <sys/ioctl.h>
#include <unistd.h>
/**
+32
View File
@@ -0,0 +1,32 @@
/* termios.h
*
* Copyright (C) 2017 Christian Visintin - christian.visintin1997@gmail.com
*
* This file is part of "termiWin: a termios porting for Windows"
*
* termiWin is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* termiWin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with termiWin. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#ifdef _WIN32
#ifndef TERMIOS_H
#define TERMIOS_H
#include "termiWin.h"
#endif // TERMIOS_H
#endif // _WIN32
+5
View File
@@ -25,6 +25,11 @@ src_files = files(
'src/split_screen.c'
)
# Add termiWin.c for Windows builds
if host_machine.system() == 'windows'
src_files += files('src/termiWin.c')
endif
# Executable
executable('beluga',
src_files,
+100
View File
@@ -234,3 +234,103 @@ int bufferSaveAll(void) {
editorSetStatusMessage("Saved %d buffers (%d failed)", saved, failed);
return (failed == 0) ? 0 : -1;
}
/**
* @brief Creates a new terminal buffer
* @return Buffer ID on success, -1 on failure
*/
int bufferCreateTerminal(void) {
// Check if we have space for more buffers
if (E.number_of_buffer >= 64) {
editorSetStatusMessage("Error: maximum buffers reached (64)");
return -1;
}
// Initialize new terminal buffer
struct buffer_t *new_buf = &E.buffers[E.number_of_buffer];
new_buf->buffer_id = E.number_of_buffer;
new_buf->filename = strdup("[Terminal]");
new_buf->type = TERMINAL_BUFF;
new_buf->state = READ_AND_WRITE;
new_buf->x = 0;
new_buf->y = 0;
new_buf->row_offset = 0;
new_buf->col_offset = 0;
new_buf->dirty = 0;
new_buf->numrows = 0;
new_buf->row = NULL;
// Initialize terminal-specific data
new_buf->terminal_command = NULL;
new_buf->terminal_pid = -1;
new_buf->terminal_output = NULL;
new_buf->terminal_output_size = 0;
// Initialize terminal-specific data
new_buf->terminal_command = NULL;
new_buf->terminal_pid = -1;
new_buf->terminal_output = NULL;
new_buf->terminal_output_size = 0;
E.number_of_buffer++;
editorSetStatusMessage("Created terminal buffer %d", new_buf->buffer_id);
return new_buf->buffer_id;
}
/**
* @brief Executes a command in the terminal buffer
* @param buffer_id The terminal buffer ID
* @param command The command to execute
* @return 0 on success, -1 on failure
*/
int bufferExecuteTerminalCommand(int buffer_id, const char *command) {
struct buffer_t *buf = bufferFindById(buffer_id);
if (buf == NULL || buf->type != TERMINAL_BUFF) {
editorSetStatusMessage("Error: buffer is not a terminal buffer");
return -1;
}
// Free any existing terminal data
if (buf->terminal_command) {
free(buf->terminal_command);
}
if (buf->terminal_output) {
free(buf->terminal_output);
}
// Store the command
buf->terminal_command = strdup(command);
// For now, we'll simulate terminal output
// In a real implementation, this would fork a process and capture output
char output[256];
snprintf(output, sizeof(output), "$ %s\n[Command executed: %s]\n", command, command);
buf->terminal_output = strdup(output);
buf->terminal_output_size = strlen(output);
// Update the buffer content to show terminal output
// Clear existing rows
for (int i = 0; i < buf->numrows; ++i) {
free(buf->row[i].chars);
free(buf->row[i].render);
}
free(buf->row);
buf->row = NULL;
buf->numrows = 0;
// Add terminal output as rows
// Make a copy for parsing since strtok modifies the string
char *output_copy = strdup(buf->terminal_output);
char *line = strtok(output_copy, "\n");
while (line != NULL) {
bufferInsertRow(buf, buf->numrows, line, strlen(line));
line = strtok(NULL, "\n");
}
free(output_copy);
buf->dirty = 1;
editorSetStatusMessage("Executed: %s", command);
return 0;
}
+17
View File
@@ -78,6 +78,23 @@ Lisp mapKey(Lisp args, LispError *e, LispContext ctx) {
return lisp_null();
}
/**
* @brief Lisp function to create a new terminal buffer
* @details Creates a new terminal buffer and switches to it.
* @param args Lisp arguments (ignored)
* @param e Error pointer for Lisp error handling
* @param ctx Lisp context
* @return lisp_null()
* @note Updates global editor state E
*/
Lisp editorCreateTerminal(Lisp args, LispError *e, LispContext ctx) {
int buffer_id = bufferCreateTerminal();
if (buffer_id >= 0) {
bufferSwitch(buffer_id);
}
return lisp_null();
}
/**
* @brief Lisp function to move cursor in a specified direction
* @details Moves the editor cursor up, down, left, or right based on direction string.
+58
View File
@@ -19,6 +19,64 @@
#include <time.h>
#include <unistd.h>
// Windows compatibility for getline
#ifdef _WIN32
#include <io.h>
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
char *bufptr = NULL;
char *p = bufptr;
size_t size;
int c;
if (lineptr == NULL) {
return -1;
}
if (stream == NULL) {
return -1;
}
if (n == NULL) {
return -1;
}
bufptr = *lineptr;
size = *n;
c = fgetc(stream);
if (c == EOF) {
return -1;
}
if (bufptr == NULL) {
bufptr = malloc(128);
if (bufptr == NULL) {
return -1;
}
size = 128;
}
p = bufptr;
while(c != EOF) {
if ((p - bufptr) > (size - 1)) {
size = size + 128;
bufptr = realloc(bufptr, size);
if (bufptr == NULL) {
return -1;
}
}
*p++ = c;
if (c == '\n') {
break;
}
c = fgetc(stream);
}
*p++ = '\0';
*lineptr = bufptr;
*n = size;
return p - bufptr - 1;
}
#endif
extern char *strdup(const char *);
extern ssize_t getline(char **restrict lineptr, size_t *restrict n,
FILE *restrict stream);
+1
View File
@@ -44,6 +44,7 @@ void initBuiltins() {
registerBuiltin("editor-split-screen-vertical", l_editorSplitScreenVertical);
registerBuiltin("editor-switch-next-pane", editorSwitchNextPane);
registerBuiltin("editor-unify-panes", editorUnifiedPanes);
registerBuiltin("editor-create-terminal", editorCreateTerminal);
}
void initConfig() {
+54
View File
@@ -320,6 +320,55 @@ int executeKeyBind(char *key_sequence) {
return 0;
}
/**
* @brief Handles terminal-specific key processing
* @details Processes key presses for terminal buffers, handling command input
* and execution.
* @param c The key code
* @return 1 if key was handled, 0 otherwise
*/
int handleTerminalKeypress(int c) {
EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id);
if (buf == NULL || buf->type != TERMINAL_BUFF) {
return 0;
}
// Handle terminal-specific keys
if (c == '\r') { // Enter key - execute command
if (buf->terminal_command && strlen(buf->terminal_command) > 0) {
bufferExecuteTerminalCommand(buf->buffer_id, buf->terminal_command);
return 1;
}
} else if (c == BACKSPACE || c == CTRL_KEY('h')) { // Backspace
if (buf->terminal_command && strlen(buf->terminal_command) > 0) {
buf->terminal_command[strlen(buf->terminal_command) - 1] = '\0';
return 1;
}
} else if (c == CTRL_KEY('c')) { // Ctrl+C - clear command
if (buf->terminal_command) {
free(buf->terminal_command);
buf->terminal_command = NULL;
}
return 1;
} else if (!iscntrl(c) && c < 128) { // Regular character input
if (buf->terminal_command == NULL) {
buf->terminal_command = malloc(2);
buf->terminal_command[0] = c;
buf->terminal_command[1] = '\0';
} else {
int len = strlen(buf->terminal_command);
buf->terminal_command = realloc(buf->terminal_command, len + 2);
buf->terminal_command[len] = c;
buf->terminal_command[len + 1] = '\0';
}
return 1;
}
return 0;
}
/**
* @brief Processes a single keypress from the user
* @details Reads a key, checks if it matches any registered keybinding,
@@ -331,6 +380,11 @@ int executeKeyBind(char *key_sequence) {
void editorProcessKeypress() {
int c = editorReadKey();
// First try terminal-specific handling
if (handleTerminalKeypress(c)) {
return;
}
if (executeKeyBind(key_to_string(c))) {
return;
}
+32 -3
View File
@@ -50,8 +50,15 @@ static void editorDrawPane(struct abuf *ab, EditorPane *pane) {
// Empty line - show tilde
if (buf->numrows == 0 && y == pane->height / 3) {
char welcome[80];
int welcome_len =
snprintf(welcome, sizeof(welcome), "Buffer %d", pane->buffer_id);
int welcome_len;
// Different welcome message for terminal buffers
if (buf->type == TERMINAL_BUFF) {
welcome_len = snprintf(welcome, sizeof(welcome), "Terminal %d", pane->buffer_id);
} else {
welcome_len = snprintf(welcome, sizeof(welcome), "Buffer %d", pane->buffer_id);
}
if (welcome_len > pane->width)
welcome_len = pane->width;
@@ -80,7 +87,29 @@ static void editorDrawPane(struct abuf *ab, EditorPane *pane) {
if (visible_len > pane->width)
visible_len = pane->width;
if (buf->filename[strlen(buf->filename) - 1] == 'c') {
if (buf->type == TERMINAL_BUFF) {
// Terminal buffer - show prompt for input line
if (file_row == buf->numrows - 1) {
char prompt[16];
int prompt_len = snprintf(prompt, sizeof(prompt), "$ ");
abAppend(ab, prompt, prompt_len);
chars_printed += prompt_len;
// Show the command being typed (if any)
if (buf->terminal_command != NULL) {
int cmd_len = strlen(buf->terminal_command);
if (cmd_len > pane->width - prompt_len) {
cmd_len = pane->width - prompt_len;
}
abAppend(ab, buf->terminal_command, cmd_len);
chars_printed += cmd_len;
}
} else {
// Show terminal output
abAppend(ab, &buf->row[file_row].render[start_offset], visible_len);
chars_printed = visible_len;
}
} else if (buf->filename && strlen(buf->filename) > 0 && buf->filename[strlen(buf->filename) - 1] == 'c') {
int byte_len_to_print;
char *highlighted = highlight_line(
+4 -4
View File
@@ -43,11 +43,11 @@ int is_type(const char *word) {
}
// Get color code for token type
const char *get_color(TokenType type) {
const char *get_color(SyntaxTokenType type) {
switch (type) {
case TOKEN_KEYWORD:
return E.theme.COLOR_KEYWORD;
case TOKEN_TYPE:
case TOKEN_DATATYPE:
return E.theme.COLOR_TYPE;
case TOKEN_STRING:
return E.theme.COLOR_STRING;
@@ -174,11 +174,11 @@ char *highlight_line(const char *line, int *length) {
strncpy(word, &line[start], i - start);
word[i - start] = '\0';
TokenType type = TOKEN_DEFAULT;
SyntaxTokenType type = TOKEN_DEFAULT;
if (is_keyword(word))
type = TOKEN_KEYWORD;
else if (is_type(word))
type = TOKEN_TYPE;
type = TOKEN_DATATYPE;
result_pos += sprintf(&result[result_pos], "%s%s%s", get_color(type),
word, COLOR_RESET);
+556
View File
@@ -0,0 +1,556 @@
/* termiWin.c
*
* Copyright (C) 2017 Christian Visintin - christian.visintin1997@gmail.com
*
* This file is part of "termiWin: a termios porting for Windows"
*
* termiWin is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* termiWin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with termiWin. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "../include/termiWin.h"
#ifdef _WIN32
#ifdef __cplusplus > 201711L
#define TERMIWIN_MAYBE_UNUSED [[maybe_unused]]
#else
#ifdef __GNUC__
#define TERMIWIN_MAYBE_UNUSED __attribute__((unused))
#else
#define TERMIWIN_MAYBE_UNUSED
#endif
#endif
#include <fcntl.h>
#include <stdlib.h>
typedef struct COM {
HANDLE hComm;
int fd; //Actually it's completely useless
char port[128];
} COM;
DCB SerialParams = { 0 }; //Initializing DCB structure
struct COM com;
COMMTIMEOUTS timeouts = { 0 }; //Initializing COMMTIMEOUTS structure
//LOCAL functions
//nbyte 0->7
int getByte(tcflag_t flag, int nbyte, int nibble) {
int byte;
if (nibble == 1)
byte = (flag >> (8 * (nbyte)) & 0x0f);
else
byte = (flag >> (8 * (nbyte)) & 0xf0);
return byte;
}
//INPUT FUNCTIONS
enum{
i_IXOFF = 0x01,
i_IXON = 0x02,
i_IXOFF_IXON = 0x03,
i_PARMRK = 0x04,
i_PARMRK_IXOFF = 0x05,
i_PARMRK_IXON = 0x06,
i_PARMRK_IXON_IXOFF = 0x07
};
int getIXOptions(tcflag_t flag) {
int byte = getByte(flag, 1, 1);
return byte;
}
//LOCALOPT FUNCTIONS
enum{
l_NOECHO = 0x00,
l_ECHO = 0x01,
l_ECHO_ECHOE = 0x03,
l_ECHO_ECHOK = 0x05,
l_ECHO_ECHONL = 0x09,
l_ECHO_ECHOE_ECHOK = 0x07,
l_ECHO_ECHOE_ECHONL = 0x0b,
l_ECHO_ECHOE_ECHOK_ECHONL = 0x0f,
l_ECHO_ECHOK_ECHONL = 0x0d,
l_ECHOE = 0x02,
l_ECHOE_ECHOK = 0x06,
l_ECHOE_ECHONL = 0x0a,
l_ECHOE_ECHOK_ECHONL = 0x0e,
l_ECHOK = 0x04,
l_ECHOK_ECHONL = 0x0c,
l_ECHONL = 0x08
};
int getEchoOptions(tcflag_t flag) {
int byte = getByte(flag, 1, 1);
return byte;
}
enum{
l_ICANON = 0x10,
l_ICANON_ISIG = 0x50,
l_ICANON_IEXTEN = 0x30,
l_ICANON_NOFLSH = 0x90,
l_ICANON_ISIG_IEXTEN = 0x70,
l_ICANON_ISIG_NOFLSH = 0xd0,
l_ICANON_IEXTEN_NOFLSH = 0xb0,
l_ICANON_ISIG_IEXTEN_NOFLSH = 0xf0,
l_ISIG = 0x40,
l_ISIG_IEXTEN = 0x60,
l_ISIG_NOFLSH = 0xc0,
l_ISIG_IEXTEN_NOFLSH = 0xe0,
l_IEXTEN = 0x20,
l_IEXTEN_NOFLSH = 0xa0,
l_NOFLSH = 0x80,
};
int getLocalOptions(tcflag_t flag) {
int byte = getByte(flag, 1, 0);
return byte;
}
enum{
l_TOSTOP = 0x01
};
int getToStop(tcflag_t flag) {
int byte = getByte(flag, 1, 1);
return byte;
}
//CONTROLOPT FUNCTIONS
int getCharSet(tcflag_t flag) {
//FLAG IS MADE UP OF 8 BYTES, A FLAG IS MADE UP OF A NIBBLE -> 4 BITS, WE NEED TO EXTRACT THE SECOND NIBBLE (1st) FROM THE FIFTH BYTE (6th).
int byte = getByte(flag, 1, 1);
switch (byte) {
case 0X0:
return CS5;
break;
case 0X4:
return CS6;
break;
case 0X8:
return CS7;
break;
case 0Xc:
return CS8;
break;
default:
return CS8;
break;
}
}
enum{
c_ALL_ENABLED = 0xd0,
c_PAREVEN_CSTOPB = 0x50,
c_PAREVEN_NOCSTOPB = 0x40,
c_PARODD_NOCSTOPB = 0xc0,
c_NOPARENB_CSTOPB = 0x10,
c_ALL_DISABLED = 0x00,
};
int getControlOptions(tcflag_t flag) {
int byte = getByte(flag, 1, 0);
return byte;
}
//LIBFUNCTIONS
int tcgetattr(int fd, struct termios* TERMIWIN_MAYBE_UNUSED termios_p) {
if (fd != com.fd) return -1;
int TERMIWIN_MAYBE_UNUSED ret = 0;
ret = GetCommState(com.hComm, &SerialParams);
return 0;
}
int tcsetattr(int fd, int TERMIWIN_MAYBE_UNUSED optional_actions, const struct termios* termios_p) {
if (fd != com.fd) return -1;
int ret = 0;
//Store flags into local variables
tcflag_t iflag = termios_p->c_iflag;
tcflag_t lflag = termios_p->c_lflag;
tcflag_t cflag = termios_p->c_cflag;
tcflag_t TERMIWIN_MAYBE_UNUSED oflag = termios_p->c_oflag;
//iflag
int IX = getIXOptions(iflag);
if ((IX == i_IXOFF_IXON) || (IX == i_PARMRK_IXON_IXOFF)) {
SerialParams.fOutX = TRUE;
SerialParams.fInX = TRUE;
SerialParams.fTXContinueOnXoff = TRUE;
}
//lflag
int TERMIWIN_MAYBE_UNUSED EchoOpt = getEchoOptions(lflag);
int TERMIWIN_MAYBE_UNUSED l_opt = getLocalOptions(lflag);
int TERMIWIN_MAYBE_UNUSED tostop = getToStop(lflag);
//Missing parameters...
//cflags
int CharSet = getCharSet(cflag);
int c_opt = getControlOptions(cflag);
switch (CharSet) {
case CS5:
SerialParams.ByteSize = 5;
break;
case CS6:
SerialParams.ByteSize = 6;
break;
case CS7:
SerialParams.ByteSize = 7;
break;
case CS8:
SerialParams.ByteSize = 8;
break;
}
switch (c_opt) {
case c_ALL_ENABLED:
SerialParams.Parity = ODDPARITY;
SerialParams.StopBits = TWOSTOPBITS;
break;
case c_ALL_DISABLED:
SerialParams.Parity = NOPARITY;
SerialParams.StopBits = ONESTOPBIT;
break;
case c_PAREVEN_CSTOPB:
SerialParams.Parity = EVENPARITY;
SerialParams.StopBits = TWOSTOPBITS;
break;
case c_PAREVEN_NOCSTOPB:
SerialParams.Parity = EVENPARITY;
SerialParams.StopBits = ONESTOPBIT;
break;
case c_PARODD_NOCSTOPB:
SerialParams.Parity = ODDPARITY;
SerialParams.StopBits = ONESTOPBIT;
break;
case c_NOPARENB_CSTOPB:
SerialParams.Parity = NOPARITY;
SerialParams.StopBits = TWOSTOPBITS;
break;
}
//aflags
/*
int OP;
if(oflag == OPOST)
else ...
*/
//Missing parameters...
//special characters
if (termios_p->c_cc[VEOF] != 0) SerialParams.EofChar = (char)termios_p->c_cc[VEOF];
if (termios_p->c_cc[VINTR] != 0) SerialParams.EvtChar = (char)termios_p->c_cc[VINTR];
if (termios_p->c_cc[VMIN] == 1) { //Blocking
timeouts.ReadIntervalTimeout = 0; // in milliseconds
timeouts.ReadTotalTimeoutConstant = 0; // in milliseconds
timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds
timeouts.WriteTotalTimeoutConstant = 0; // in milliseconds
timeouts.WriteTotalTimeoutMultiplier = 0; // in milliseconds
} else { //Non blocking
timeouts.ReadIntervalTimeout = termios_p->c_cc[VTIME] * 100; // in milliseconds
timeouts.ReadTotalTimeoutConstant = termios_p->c_cc[VTIME] * 100; // in milliseconds
timeouts.ReadTotalTimeoutMultiplier = termios_p->c_cc[VTIME] * 100; // in milliseconds
timeouts.WriteTotalTimeoutConstant = termios_p->c_cc[VTIME] * 100; // in milliseconds
timeouts.WriteTotalTimeoutMultiplier = termios_p->c_cc[VTIME] * 100; // in milliseconds
}
SetCommTimeouts(com.hComm, &timeouts);
//EOF
ret = SetCommState(com.hComm, &SerialParams);
if (ret != 0)
return 0;
else
return -1;
}
int tcsendbreak(int fd, int TERMIWIN_MAYBE_UNUSED duration) {
if (fd != com.fd) return -1;
int ret = 0;
ret = TransmitCommChar(com.hComm, '\x00');
if (ret != 0)
return 0;
else
return -1;
}
int tcdrain(int fd) {
if (fd != com.fd) return -1;
return FlushFileBuffers(com.hComm);
}
int tcflush(int fd, int queue_selector) {
if (fd != com.fd) return -1;
int rc = 0;
switch (queue_selector) {
case TCIFLUSH:
rc = PurgeComm(com.hComm, PURGE_RXCLEAR);
break;
case TCOFLUSH:
rc = PurgeComm(com.hComm, PURGE_TXCLEAR);
break;
case TCIOFLUSH:
rc = PurgeComm(com.hComm, PURGE_RXCLEAR);
rc *= PurgeComm(com.hComm, PURGE_TXCLEAR);
break;
default:
rc = 0;
break;
}
if (rc != 0)
return 0;
else
return -1;
}
int tcflow(int fd, int action) {
if (fd != com.fd) return -1;
int rc = 0;
switch (action) {
case TCOOFF:
rc = PurgeComm(com.hComm, PURGE_TXABORT);
break;
case TCOON:
rc = ClearCommBreak(com.hComm);
break;
case TCIOFF:
rc = PurgeComm(com.hComm, PURGE_RXABORT);
break;
case TCION:
rc = ClearCommBreak(com.hComm);
break;
default:
rc = 0;
break;
}
if (rc != 0)
return 0;
else
return -1;
}
void cfmakeraw(struct termios* TERMIWIN_MAYBE_UNUSED termios_p) {
SerialParams.ByteSize = 8;
SerialParams.StopBits = ONESTOPBIT;
SerialParams.Parity = NOPARITY;
}
speed_t cfgetispeed(const struct termios* TERMIWIN_MAYBE_UNUSED termios_p) {
return SerialParams.BaudRate;
}
speed_t cfgetospeed(const struct termios* TERMIWIN_MAYBE_UNUSED termios_p) {
return SerialParams.BaudRate;
}
int cfsetispeed(struct termios* TERMIWIN_MAYBE_UNUSED termios_p, speed_t speed) {
SerialParams.BaudRate = speed;
return 0;
}
int cfsetospeed(struct termios* TERMIWIN_MAYBE_UNUSED termios_p, speed_t speed) {
SerialParams.BaudRate = speed;
return 0;
}
int cfsetspeed(struct termios* TERMIWIN_MAYBE_UNUSED termios_p, speed_t speed) {
SerialParams.BaudRate = speed;
return 0;
}
ssize_t read_serial(int fd, void* buffer, size_t count) {
if (fd != com.fd) return -1;
int rc = 0;
int ret;
ret = ReadFile(com.hComm, buffer, count, &rc, NULL);
if (ret == 0)
return -1;
else
return rc;
}
ssize_t write_serial(int fd, const void* buffer, size_t count) {
if (fd != com.fd) return -1;
int rc = 0;
int ret;
ret = WriteFile(com.hComm, buffer, count, &rc, NULL);
if (ret == 0)
return -1;
else
return rc;
}
int open_serial(const char* portname, int opt) {
if (strlen(portname) < 4) return -1;
// Set to zero
memset(com.port, 0x00, 128);
//COMxx
size_t portSize = 0;
if (strlen(portname) > 4) {
portSize = sizeof(char) * strlen("\\\\.\\COM10") + 1;
#ifdef _MSC_VER
strncat_s(com.port, portSize, "\\\\.\\", strlen("\\\\.\\"));
#else
strncat(com.port, "\\\\.\\", strlen("\\\\.\\"));
#endif
}
//COMx
else {
portSize = sizeof(char) * 5;
}
#ifdef _MSC_VER
strncat_s(com.port, portSize, portname, 4);
#else
strncat(com.port, portname, 4);
#endif
com.port[portSize] = 0x00;
switch (opt) {
case O_RDWR:
com.hComm = CreateFile(com.port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
break;
case O_RDONLY:
com.hComm = CreateFile(com.port, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
break;
case O_WRONLY:
com.hComm = CreateFile(com.port, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
break;
}
if (com.hComm == INVALID_HANDLE_VALUE) {
return -1;
}
com.fd = atoi(portname + 3); // COMx and COMxx
SerialParams.DCBlength = sizeof(SerialParams);
return com.fd;
}
int close_serial(int TERMIWIN_MAYBE_UNUSED fd) {
int ret = CloseHandle(com.hComm);
if (ret != 0)
return 0;
else
return -1;
}
int select_serial(int TERMIWIN_MAYBE_UNUSED nfds, fd_set* readfds, fd_set* TERMIWIN_MAYBE_UNUSED writefds, fd_set* TERMIWIN_MAYBE_UNUSED exceptfds, struct timeval* TERMIWIN_MAYBE_UNUSED timeout) {
SetCommMask(com.hComm, EV_RXCHAR);
DWORD dwEventMask;
if (WaitCommEvent(com.hComm, &dwEventMask, NULL) == 0) {
return -1; // Return -1 if failed
}
if (dwEventMask == EV_RXCHAR) {
return com.fd;
} else {
if (readfds) {
// Clear file descriptor if event is not RXCHAR
FD_CLR(com.fd, readfds);
}
}
// NOTE: write event not detectable!
// NOTE: no timeout
return 0; // No data
}
//Returns hComm from the COM structure
HANDLE getHandle() {
return com.hComm;
}
#endif
+14
View File
@@ -3,6 +3,10 @@
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#endif
void die(const char *s) {
write(STDOUT_FILENO, "\x1b[2J", 4);
write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3);
@@ -134,6 +138,15 @@ int getCursorPosition(int *rows, int *cols) {
}
int getWindowSize(int *rows, int *cols) {
#ifdef _WIN32
// Windows implementation
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
*cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
*rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
return 0;
#else
// Unix implementation
struct winsize ws;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
@@ -146,4 +159,5 @@ int getWindowSize(int *rows, int *cols) {
*rows = ws.ws_row;
return 0;
}
#endif
}