Regex works now

added branding in a seperate file and a config.h
	replace_rules count in branding does not work as of now

way better replace functions that actually work
This commit is contained in:
Stephen Toth 2023-09-30 12:26:00 -04:00
parent f4f877148c
commit 62c15ab976
18 changed files with 505 additions and 182 deletions

3
.gitignore vendored
View File

@ -10,7 +10,8 @@ bin/*
# Ignore temp editor files # Ignore temp editor files
*.swp *.swp
*.tmp
.vscode .vscode/*
!.gitkeep !.gitkeep

View File

@ -3,8 +3,7 @@
{ {
"name": "Linux", "name": "Linux",
"includePath": [ "includePath": [
"${workspaceFolder}/**", "${workspaceFolder}/**"
"${workspaceFolder}/include"
], ],
"defines": [], "defines": [],
"compilerPath": "/bin/gcc", "compilerPath": "/bin/gcc",

34
.vscode/launch.json vendored
View File

@ -1,34 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Attach",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceFolder}/bin/cterm",
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
},
{
"name": "colorwrap",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/cterm",
"args": ["/bin/sh"],
"cwd": "${workspaceFolder}/"
}]
}

17
.vscode/tasks.json vendored
View File

@ -1,20 +1,5 @@
{ {
"tasks": [ "tasks": [
{
"type": "cppbuild",
"label": "Make Build",
"command": "make",
"args": [
"--directory=${workspaceFolder}"
],
"options": {
"cwd": "${workspaceFolder}"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{ {
"type": "cppbuild", "type": "cppbuild",
"label": "C/C++: gcc build active file", "label": "C/C++: gcc build active file",
@ -34,7 +19,7 @@
], ],
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": false "isDefault": true
}, },
"detail": "Task generated by Debugger." "detail": "Task generated by Debugger."
} }

View File

@ -10,7 +10,10 @@ CFLAGS := -lreadline
LIB := -L lib -lutil -lreadline LIB := -L lib -lutil -lreadline
INC := -I include INC := -I include
$(TARGET): $(OBJECTS) $(TARGET): $(OBJECTS)
@echo " Incrementing Build #"; make/genbuildno.sh
@echo "Build number: $(shell grep BUILD include/config.h | cut -d' ' -f 3)"
@echo " Linking..." @echo " Linking..."
@echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB) -O3 @echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB) -O3
@echo " Done!" @echo " Done!"
@ -23,9 +26,11 @@ $(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
clean: clean:
@echo " Cleaning..."; @echo " Cleaning...";
@echo " cat /dev/null > $(TESTDIR)/trace.lp"; cat /dev/null > $(TESTDIR)/trace.lp; @echo " cat /dev/null > $(TESTDIR)/trace.lp"; cat /dev/null > $(TESTDIR)/trace.lp;
@echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET) @echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR)/* $(TARGET);
debug: CFLAGS += -ggdb -O0 -Wall -Wextra -pedantic -D"DEBUG=1" #debug: clean
debug: CFLAGS += -ggdb -O0 -Wall -Wextra -pedantic -Wno-unused-variable -Wno-unused-parameter
debug: CFLAGS += -D"DEBUG=1" -DGITBRANCH=\"$(shell git branch --show-current)\"
debug: $(TARGET) debug: $(TARGET)
test: test:

View File

@ -1 +0,0 @@
.

11
include/branding.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _BRANDING_H
#define _BRANDING_H
#if !defined(GITBRANCH)
#define GITBRANCH ""
#endif
void printbranding();
#endif

40
include/config.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef _CONFIG_H
#define _CONFIG_H
// Project global information
#define PROJECT_NAME "cterm"
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_HOTFIX 0
#define VERSION_BUILD 350
//#define DEFAULT_CMD "/bin/sh"
#define CONF_DO_CMD_ACK 1
#define DEBG_DO_EOL_MARK 1
//EOLMARK defined in parsebuffer()
// Color codes
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#define BKRED "\x1B[41m"
#define BKGRN "\x1B[42m"
#define BKYEL "\x1B[43m"
#define BKBLU "\x1B[44m"
#define BKMAG "\x1B[45m"
#define BKCYN "\x1B[46m"
#define BKWHT "\x1B[47m"
//child stdout read buffer size
#define BUFCHUNKSIZE 4096
#define BUFSAFEPAD 8 //shut it, ik its useless
#endif

View File

@ -1,8 +1,17 @@
#ifndef _DEBUG_H #ifndef _DEBUG_H
#define _DEBUG_H #define _DEBUG_H
#include <stdio.h>
#if defined(DEBUG) && DEBUG > 0 #if defined(DEBUG) && DEBUG > 0
#define DEBUG_PRINT(fmt, ...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \ #define _DEBUG_H_DRED "\x1B[31m"
#define _DEBUG_H_DNRM "\x1B[0m"
#define DEBUG_PRINT(fmt, ...) fprintf(stderr, "[-] %s:%d:%s(): " fmt, \
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define DDEBUG_PRINT(fmt, ...) fprintf(stderr, "[_] %s:%d:%s(): " fmt, \
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define DEBUG_ERROR(fmt, ...) fprintf(stderr, "\n"_DEBUG_H_DRED"[!]"_DEBUG_H_DNRM" %s:%d:%s(): E.%d " fmt, \
__FILE__, __LINE__, __func__, ##__VA_ARGS__) __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define COLORTEST() fprintf(stderr, "Color Palate:\n" \ #define COLORTEST() fprintf(stderr, "Color Palate:\n" \
KRED"KRED"KGRN"KGRN"KYEL"KYEL"KBLU"KBLU"KMAG"KMAG"KCYN"KCYN"KWHT"KWHT"KNRM"\n" \ KRED"KRED"KGRN"KGRN"KYEL"KYEL"KBLU"KBLU"KMAG"KMAG"KCYN"KCYN"KWHT"KWHT"KNRM"\n" \
@ -11,7 +20,10 @@
BKRED"KRED"BKGRN"KGRN"BKYEL"KYEL"BKBLU"KBLU"BKMAG"KMAG"BKCYN"KCYN"BKWHT"KWHT"KNRM"\n" ) BKRED"KRED"BKGRN"KGRN"BKYEL"KYEL"BKBLU"KBLU"BKMAG"KMAG"BKCYN"KCYN"BKWHT"KWHT"KNRM"\n" )
#else #else
#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */ #define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
#define DDEBUG_PRINT(fmt, args...)
#define DEBUG_ERROR(fmt, args...)
#define COLORTEST() #define COLORTEST()
#endif #endif
#endif #endif

12
include/linework.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _LINEWORK_H
#define _LINEWORK_H
#include <structdef.h>
#include <regex.h>
int line_regex_replace(ct_line *line, regex_t *regex, int replace_group, char *with, int max_instances);
int line_regex_wrap_match(ct_line *line, regex_t *regex, int target_capture_group, char *left, char *right, int max_instances);
#endif

View File

@ -4,5 +4,7 @@
// You must free the result if result is non-NULL. // You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with); char *str_replace(char *orig, char *rep, char *with);
//char *str_index_replace(char *orig, int rep_s, int rep_e, char *with);
#endif #endif

View File

@ -1,5 +1,16 @@
#ifndef _STRUCTDEF_H #ifndef _STRUCTDEF_H
#define _STRUCTDEF_H #define _STRUCTDEF_H
typedef struct {
char* match_regex;
int match_cflags;
int replace_group; //if no regex groups (()), should be 0
char* replace_with;
} ct_match;
typedef struct {
char* line_str; //pointer to first char in string
int need_free; //tracks if buffer is on the stack or in heap
} ct_line;
#endif #endif

3
make/genbuildno.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
sed -i "s/BUILD .*/BUILD $(($(grep BUILD include/config.h | cut -d' ' -f3) + 1 ))/g" include/config.h

60
src/branding.c Normal file
View File

@ -0,0 +1,60 @@
#include <branding.h>
#include <stdio.h>
#include <string.h>
#include <config.h>
#include <debug.h>
// c macros to clean up lines later
#define b_lenofarr(axx) (sizeof(axx)/sizeof(axx[0]))
#define b_roundup(x) ((x)+1) & ~1
void printbranding(){
//compile change config
int min_content_padding = 4;
char *box_pad_char = "----------"; // this is repeated to be in the horrror later; printf ugh;
int box_top_width = 3; // --- text ---
int box_side_width = 2; // -- text --
char pre_print_lines[10][100] = {0}; //these are not end-user affectable so 100 chars should be fine for now.
sprintf(pre_print_lines[0], "%s v%d.%d.%d" , PROJECT_NAME, VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD);
//sprintf(pre_print_lines[0], "%s v%d.%d.%d.%d" , PROJECT_NAME, VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX, VERSION_BUILD);
sprintf(pre_print_lines[1], "(c) never");
sprintf(pre_print_lines[2], "%d rules loaded", 9); //TODO: actually use the number of rules loaded
if (GITBRANCH) sprintf(pre_print_lines[3], "%s", GITBRANCH);
int max_used_line_length = 0;
int used_lines = 0; //the number of lines actually used above
for (int i = b_lenofarr(pre_print_lines)-1; i >= 0; i-- ){ //reverse loop from 9->0
if (pre_print_lines[i][0] == 0) continue; //not set, dont care
used_lines++;
int line_length = strlen(pre_print_lines[i]);
if (line_length > max_used_line_length) max_used_line_length = b_roundup(line_length);
if (line_length % 2 != 0) { //also going to use this (convienent) loop to pad the end of odd number length strings
pre_print_lines[i][line_length]=' ';
pre_print_lines[i][line_length+1]='\0'; //bad for user defined strings, but not in this case since its not
}
}
//DDEBUG_PRINT("max_used_line_length=%d; used_lines=%d\n", max_used_line_length, used_lines);
int output_line_length = b_roundup(max_used_line_length+min_content_padding*2+box_top_width);
//DDEBUG_PRINT("output_line_length=%d\n", output_line_length);
for (int i = 0; i<used_lines; i++){
int box_pad = box_side_width;
int content_len = strlen(pre_print_lines[i]);
if (i == 0 || i == used_lines-1) box_pad = box_top_width;
//DDEBUG_PRINT("box_pad=%d\n", box_pad);
int half_content_pad = ((output_line_length-content_len-box_pad)/2);
//DDEBUG_PRINT("half_content_pad=%d\n", half_content_pad);
printf("%.*s%*s%s%*s%.*s\n", box_pad, box_pad_char, half_content_pad, "", pre_print_lines[i], half_content_pad, "", box_pad, box_pad_char);
}
printf("\n");
}

161
src/linework.c Normal file
View File

@ -0,0 +1,161 @@
#include <linework.h>
#include <structdef.h>
#include <debug.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
char *str_index_replace(const char *orig, const char *with, const int start_index, const int end_index){
//no error checking on the args
//will always call malloc
char *result;
char *tmp; //temporary pointer for replace process later
int len_with = strlen(with); //doesnt change with loop repetitions
int len_replace = end_index - start_index;
int len_delta = len_with - len_replace; //how many chars are we changing the buffer by?
result = tmp = malloc(strlen(orig) + len_delta + 1);
if (!result) return NULL;
int len_front = start_index;
tmp = strncpy(tmp, orig, len_front) + len_front; //fill front end of buffer with already processed stuff
tmp = strcpy(tmp, with) + len_with;
strcpy(tmp, (orig + len_front + len_replace)); //writes the nice good \0 at the end
/* reference: 0___1___2______4
* fL...B
* result: 0___1-----2_______4
* fL.....B
*/
return result;
}
/// @brief
/// You could probably break this function if you really wanted to. fortunately, the regex is done at start time, not dynamically; yet :'(
/// @param line mutates
/// @param regex compiled regex
/// @param target_capture_group int of the capture group to replace. 0=everything
/// @param with
/// @param max_instances 0=all instances
/// @return 0 if no match; 1 if match and replace; -1 for error
int line_regex_replace(ct_line *line, regex_t *regex, int target_capture_group, char *with, int max_instances){
//TODO: logic for max_instances being 0
if (target_capture_group > (int)regex->re_nsub){
DEBUG_ERROR("[target_capture_group bigger than number of subexpressions in regex]\n", 26);
return -1;
}
//TODO: more failure conditions
/* References:
* https://www.gnu.org/software/libc/manual/html_node/Matching-POSIX-Regexps.html
* https://www.ibm.com/docs/en/i/7.2?topic=functions-regexec-execute-compiled-regular-expression
*/
int num_instances = 0;
size_t nmatch = target_capture_group+1; //number of capture groups we care about
regmatch_t pmatch[nmatch+1]; //0=everything, else is capture groups +1 for "safety"
char *search_start_point = line->line_str;
int match_result = regexec(regex, search_start_point, nmatch, pmatch, 0);
if (match_result==REG_NOMATCH) return 0;
//DEBUG_PRINT("fresh:%s\n", line->line_str);
do {
num_instances++;
if (pmatch[target_capture_group].rm_so == -1) { DEBUG_ERROR("[Subexpression did not participate in an otherwise successful match]\n", 40); continue; }
if (pmatch[target_capture_group].rm_eo < pmatch[target_capture_group].rm_so) { DEBUG_ERROR("[End offset < Start Offset] wtf???? now how did you manage that?\n", 41); continue; }
int front_delta = (search_start_point - line->line_str); //how far are we into the string?
int start_index = pmatch[target_capture_group].rm_so + front_delta; //normalize indicies to be from real start
int end_index = pmatch[target_capture_group].rm_eo + front_delta;
//with
//do the replace
char *result = str_index_replace(line->line_str, with, start_index, end_index); //nice good pointer to the new and improved string
if (!result) {
DEBUG_ERROR("[replace error] idk\n", 85);
return -1;
}
//clean up previous line memory and sub in the new pointer
if(line->need_free) free(line->line_str);
line->line_str = result;
line->need_free = 1;
search_start_point = line->line_str + start_index + strlen(with); //its *back but recalculated for the new string
//DEBUG_PRINT("new set:%s\n", line->line_str);
//DEBUG_PRINT("new search space:%s\n", search_start_point);
match_result = regexec(regex, search_start_point, nmatch, pmatch, REG_NOTBOL);
} while(match_result==0 && num_instances<=max_instances);
return 1;
}
int line_regex_wrap_match(ct_line *line, regex_t *regex, int target_capture_group, char *left, char *right, int max_instances){
//TODO: logic for max_instances being 0
if (target_capture_group > (int)regex->re_nsub){
DEBUG_ERROR("[target_capture_group bigger than number of subexpressions in regex] MAYBE: fallback?\n", 26);
return -1;
}
//TODO: more failure conditions
/* References:
* https://www.gnu.org/software/libc/manual/html_node/Matching-POSIX-Regexps.html
* https://www.ibm.com/docs/en/i/7.2?topic=functions-regexec-execute-compiled-regular-expression
*/
int num_instances = 0;
size_t nmatch = target_capture_group+1; //number of capture groups we care about
regmatch_t pmatch[nmatch+1]; //0=everything, else is capture groups +1 for "safety"
char *search_start_point = line->line_str;
int match_result = regexec(regex, search_start_point, nmatch, pmatch, 0);
if (match_result==REG_NOMATCH) return 0;
do {
num_instances++;
if (pmatch[target_capture_group].rm_so == -1) { DEBUG_ERROR("[Subexpression did not participate in an otherwise successful match]\n", 40); continue; }
if (pmatch[target_capture_group].rm_eo < pmatch[target_capture_group].rm_so) { DEBUG_ERROR("[End offset < Start Offset] wtf???? now how did you manage that?\n", 41); continue; }
char *match_start = search_start_point + pmatch[target_capture_group].rm_so;
int len_match = pmatch[target_capture_group].rm_eo - pmatch[target_capture_group].rm_so;
int len_wrap = strlen(left) + strlen(right);
char with[len_match + len_wrap + 1];
strcpy(with, left);
strncat(with, match_start, len_match);
strcat(with, right);
int front_delta = (search_start_point - line->line_str); //how far are we into the string?
int start_index = pmatch[target_capture_group].rm_so + front_delta; //normalize indicies to be from real start
int end_index = pmatch[target_capture_group].rm_eo + front_delta;
//do the replace
char *result = str_index_replace(line->line_str, with, start_index, end_index); //nice good pointer to the new and improved string
if (!result) {
DEBUG_ERROR("[replace error] idk\n", 85);
return -1;
}
//clean up previous line memory and sub in the new pointer
if(line->need_free) free(line->line_str);
line->line_str = result;
line->need_free = 1;
search_start_point = line->line_str + start_index + strlen(with); //its *back but recalculated for the new string
//DEBUG_PRINT("new set:%s\n", line->line_str);
//DEBUG_PRINT("new search space:%s\n", search_start_point);
match_result = regexec(regex, search_start_point, nmatch, pmatch, REG_NOTBOL);
} while(match_result==0 && num_instances<=max_instances);
return 1;
}

View File

@ -10,158 +10,165 @@
#include <fcntl.h> #include <fcntl.h>
#include <readline/readline.h> #include <readline/readline.h>
//#include <readline/history.h> //#include <readline/history.h>
//regex branch init
#include <regex.h>
// Custom debug include for some debug macros and functions // Custom debug include for some debug macros and functions
#include <config.h>
#include <debug.h> #include <debug.h>
#include <structdef.h>
#include <branding.h>
#include <linework.h>
#include <notmine.h> #include <notmine.h>
#define VERSIONSTRING "0.2"
#define BUFCHUNKSIZE 4096
#define BUFSAFEPAD 8
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#define BKRED "\x1B[41m"
#define BKGRN "\x1B[42m"
#define BKYEL "\x1B[43m"
#define BKBLU "\x1B[44m"
#define BKMAG "\x1B[45m"
#define BKCYN "\x1B[46m"
#define BKWHT "\x1B[47m"
//temporary //temporary
char *replace_rules[][2] = { ct_match replace_rules[]= {
{ "r--", KGRN"r--"KNRM }, { "alpine", 0, 0, KMAG"alpine"KNRM },
{ "rw-", KRED"rw-"KNRM }, { "r--", 0, 0, KGRN"r--"KNRM },
{ "alpine", KMAG"alpine"KNRM }, { "rw-", 0, 0, KRED"rw-"KNRM },
{ " ..$", KBLU" .."KNRM"$" }, { " ..$", 0, 0, KBLU" .."KNRM },
{ " .$", KBLU" ."KNRM"$" }, { " .$", 0, 0, KBLU" ."KNRM },
{ "^d", "^"KMAG"d"KNRM }, { "^d", 0, 0, KMAG"d"KNRM },
{ "z9Da0Da1", KRED"z9Da0Da1"KNRM }, { "z9Da0Da1", 0, 0, KRED"z9Da0Da1"KNRM },
}; };
char ps1[] = KGRN"~>"KNRM; char ps1[] = KGRN"~>"KNRM;
char ps1_ack[] = KBLU"1~"KNRM; char ps1_ack[] = KBLU"1~"KNRM;
ct_line processline(ct_line current_line){
int rules_length = (sizeof(replace_rules)/sizeof(replace_rules[0]));
for (int i=0; i<rules_length; i++) {
regex_t comp_regex;
int match1_comp_result = regcomp(&comp_regex, replace_rules[i].match_regex, replace_rules[i].match_cflags); //unused but needed
int regex_result = line_regex_replace(&current_line, &comp_regex, replace_rules[i].replace_group, replace_rules[i].replace_with, 255);
}
return current_line;
}
void parsebuffer(char *roll_buffer, size_t read_length, int buffer_read_count) {
#if !DEBG_DO_EOL_MARK
char endstring[] = KNRM"\n";
#else
char endstring[] = KYEL"&"KNRM"\n";
#endif
//dog garn dynamic memory allocation making me track it manually in a struct
int line_number = 0; //true
if (buffer_read_count != 0) line_number=1;
char *found_char = strtok(roll_buffer, "\r\n"); //basically replace "\r\n" with NULL
while(found_char != NULL){
ct_line current_line = {found_char, 0};
ct_line post_processed_line = processline(current_line);
if (CONF_DO_CMD_ACK && line_number==0) write(STDOUT_FILENO, ps1_ack, strlen(ps1_ack));
write(STDOUT_FILENO, post_processed_line.line_str, strlen(post_processed_line.line_str));
write(STDOUT_FILENO, endstring, strlen(endstring));
if (post_processed_line.need_free == 1) free(post_processed_line.line_str);
line_number++;
found_char = strtok(NULL, "\r\n"); // I really do not like this repetition
}
//no more lines in buffer
}
void supervise(int master_fd, int child_pid){
fcntl(master_fd, F_SETFL, O_NONBLOCK);
usleep(300*1000); //wait for child shell to init; bad practice, but it works for now
char *child_out_roll_buffer = (char*) malloc(sizeof(char) * (BUFCHUNKSIZE+BUFSAFEPAD+1));
char *parent_in_buffer = (char*) malloc(sizeof(char) * (BUFCHUNKSIZE+BUFSAFEPAD+1));
while(1){
//read child stdout to child_out_roll_buffer
//send to processing & output
int read_loop_no = 0;
while(1){ //continuely read until none left
memset(child_out_roll_buffer, 0, BUFCHUNKSIZE+BUFSAFEPAD);
errno = 0; //force reset errno
ssize_t read_size = read(master_fd, &child_out_roll_buffer[0], BUFCHUNKSIZE - 0);
if (read_size > 0) {
parsebuffer(child_out_roll_buffer, read_size, read_loop_no);
read_loop_no++;
continue;
}
if (read_size == -1 && errno == EAGAIN) break; //read would block (no more data and buffer contents are already processed)
//fallthrough read_size == 0
DEBUG_PRINT("read_size=0: EOF\n");
printf("Reached EOF. child exit? exiting...\n");
exit(0);
}
//read stdin
//send to child
memset(parent_in_buffer, 0, BUFCHUNKSIZE);
strncpy(parent_in_buffer, readline(ps1), BUFCHUNKSIZE-1);
write(master_fd, parent_in_buffer, strlen(parent_in_buffer));
write(master_fd, "\n", 1);
usleep(100*1000);
}
free(child_out_roll_buffer);
free(parent_in_buffer);
}
void child_process(char *argv[]){ void child_process(char *argv[]){
execl(argv[1], argv[1], NULL); execl(argv[1], argv[1], NULL);
} }
void processline(const char *line, int first_line){
size_t line_length = strlen(line);
char copyline[line_length+3];
copyline[0] = '^';
strncpy(&copyline[1], line, line_length); //yes, I know this is "jank" its fine tho. (see next)
// 1. line *should* always be NULL terminated
// 2. line is ALWAYS < 4097
copyline[line_length+1] = '$';
copyline[line_length+2] = '\0';
//strncat(copyline, "$", 2);
char *newline = (char *)&copyline;
char endstring[] = KNRM"\n";
//if (first_line) newline = str_replace(newline, "^", "^User Input: ");
if (first_line) write(STDOUT_FILENO, ps1_ack, strlen(ps1_ack));
for(unsigned int i = 0; i<(sizeof(replace_rules)/sizeof(replace_rules[0])); i++){
newline = str_replace(newline, replace_rules[i][0], replace_rules[i][1]);
//write(STDOUT_FILENO, debugstring, strlen(debugstring));
if (newline == NULL) {
newline = copyline;
}
}
write(STDOUT_FILENO, newline+1, strlen(newline)-2);
if (newline != NULL) free(newline);
write(STDOUT_FILENO, endstring, strlen(endstring));
}
void processbuffer(char *roll_buffer, size_t read_length, int first_read) {
//this is where some optimization could come in with using malloc and then freeing subset of memory; dog garn dynamic memory allocation
//int found_index;
char *found_char = strtok(roll_buffer, "\r\n");
int first_line = 1;
while(found_char != NULL){
processline(found_char, first_line&&first_read);
first_line = 0;
found_char = strtok(NULL, "\r\n");
}
//no more instances
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
printf(" --- cterm v%s ---\n" , VERSIONSTRING); printbranding();
printf(" -- %d replace rules loaded --\n", (int *)(sizeof(replace_rules)/sizeof(replace_rules[0]))); COLORTEST(); //macro for testing
printf(" --- ---\n");
printf("\n");
COLORTEST();
int master;
pid_t child_pid;
//struct winsize win = {
// .ws_col = 80, .ws_row = 24,
// .ws_xpixel = 480, .ws_ypixel = 192,
//};
// sanity checking
if (argc < 2) { if (argc < 2) {
printf("Usage: %s cmd [args...]\n", argv[0]); printf("Usage: %s cmd [args...]\n", argv[0]);
exit(EX_USAGE); exit(EX_USAGE);
} }
child_pid = forkpty(&master, NULL, NULL, NULL);
if (child_pid == -1) {
int master_fd;
pid_t child_pid;
//if the pty window size is to be assigned. shoudnt be a concern since only used by tui programs
/*struct winsize win = {
.ws_col = 80, .ws_row = 24,
.ws_xpixel = 480, .ws_ypixel = 192,
};*/
child_pid = forkpty(&master_fd, NULL, NULL, NULL);
//TODO: Better error checking
if (child_pid == -3) {
perror("forkpty failed"); perror("forkpty failed");
exit(EX_OSERR); exit(EX_OSERR);
} }
if (child_pid == 0) { if (child_pid == 0) {
child_process(argv); child_process(argv);
exit(0); exit(0);
} }
//remainder is main is the parent process for processing input and shit supervise(master_fd, child_pid);
fcntl(master, F_SETFL, O_NONBLOCK); exit(0);
char *child_out_roll_buffer = (char*) malloc(sizeof(char) * (BUFCHUNKSIZE+BUFSAFEPAD+1)); }
char *parent_in_buffer = (char*) malloc(sizeof(char) * (BUFCHUNKSIZE+BUFSAFEPAD+1));
usleep(300*1000); //wait for child shell to init; bad practice, but it works for now
while(1){
// ideally I would want to read from the pipe and buffer the output, rewriting the line on change
// whenever it sees a newline, it should send it to the processor and print to stdout, with that newline
//CHILD OUTPUT HANDLING
// treating the buffer as kind of a FIFO stack thing
// strip lines from top and then move leftover to top,
// then start reading where we left off
// Later on: it kinda has that behavior, I cant confirm rn, but it "works"
int first_read = 1;
while(1){
memset(child_out_roll_buffer, 0, BUFCHUNKSIZE+BUFSAFEPAD);
ssize_t read_count = read(master, &child_out_roll_buffer[0], BUFCHUNKSIZE - 0);
if (read_count == 0 ) {
DEBUG_PRINT("EOF\n");
exit(0);
}
if (read_count == -1){
if(errno == EAGAIN){ //errored because read would block io
break;
} else {
DEBUG_PRINT("I/O \"Error\" (Child Exited?) %d\n", errno);
exit(0);
}
}
//process da block then write it
processbuffer(child_out_roll_buffer, read_count, first_read);
first_read = 0;
}
//INPUT HANDLING
memset(parent_in_buffer, 0, BUFCHUNKSIZE);
strncpy(parent_in_buffer, readline(ps1), BUFCHUNKSIZE-1);
write(master, parent_in_buffer, strlen(parent_in_buffer));
write(master, "\n", 1);
usleep(100*1000);
}
}

View File

@ -2,6 +2,9 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <debug.h>
//https://stackoverflow.com/a/779960/8229149 //https://stackoverflow.com/a/779960/8229149
char *str_replace(char *orig, char *rep, char *with) { char *str_replace(char *orig, char *rep, char *with) {
char *result; // the return string char *result; // the return string
@ -24,7 +27,7 @@ char *str_replace(char *orig, char *rep, char *with) {
// count the number of replacements needed // count the number of replacements needed
ins = orig; ins = orig;
for (count = 0; tmp = strstr(ins, rep); ++count) { for (count = 0; (tmp = strstr(ins, rep)); ++count) {
ins = tmp + len_rep; ins = tmp + len_rep;
} }
@ -47,4 +50,50 @@ char *str_replace(char *orig, char *rep, char *with) {
} }
strcpy(tmp, orig); strcpy(tmp, orig);
return result; return result;
} }
/* char *str_index_replace(char *orig, int rep_s, int rep_e, char *with) {
// Ugh, Re-worked the preceding str_replace function to work with indexes
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
int len_rep; // length of rep (the string to remove)
int len_with; // length of with (the string to replace rep with)
int len_front; // distance between rep and end of last rep
// sanity checks and initialization
if (!orig || !rep_e){
DEBUG_ERROR("[orig or rep_e is false] *orig=%p; rep_s=%d, rep_e=%d\n", 67, orig, rep_s, rep_e);
return NULL;
}
len_rep = rep_e - rep_s;
if (len_rep == 0){
DEBUG_ERROR("[rep empty]\n", 72);
return NULL; // empty rep causes infinite loop during count
}
if (!with)
with = "";
len_with = strlen(with);
tmp = result = malloc(strlen(orig) + (len_with - len_rep) + 1);
if (!result) {
DEBUG_ERROR("[bad malloc]", 83);
return NULL;
}
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
ins = orig + rep_s;
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
strcpy(tmp, orig);
return result;
} */

0
testing/alpineA Normal file
View File