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:
parent
f4f877148c
commit
62c15ab976
|
|
@ -10,7 +10,8 @@ bin/*
|
||||||
|
|
||||||
# Ignore temp editor files
|
# Ignore temp editor files
|
||||||
*.swp
|
*.swp
|
||||||
|
*.tmp
|
||||||
|
|
||||||
.vscode
|
.vscode/*
|
||||||
|
|
||||||
!.gitkeep
|
!.gitkeep
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
{
|
{
|
||||||
"name": "Linux",
|
"name": "Linux",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/**",
|
"${workspaceFolder}/**"
|
||||||
"${workspaceFolder}/include"
|
|
||||||
],
|
],
|
||||||
"defines": [],
|
"defines": [],
|
||||||
"compilerPath": "/bin/gcc",
|
"compilerPath": "/bin/gcc",
|
||||||
|
|
|
||||||
|
|
@ -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}/"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
@ -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."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
Makefile
9
Makefile
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
.
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _BRANDING_H
|
||||||
|
#define _BRANDING_H
|
||||||
|
|
||||||
|
#if !defined(GITBRANCH)
|
||||||
|
#define GITBRANCH ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void printbranding();
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
sed -i "s/BUILD .*/BUILD $(($(grep BUILD include/config.h | cut -d' ' -f3) + 1 ))/g" include/config.h
|
||||||
|
|
||||||
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
249
src/main.c
249
src/main.c
|
|
@ -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(¤t_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(©line[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 *)©line;
|
|
||||||
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);
|
|
||||||
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);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,3 +51,49 @@ 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;
|
||||||
|
} */
|
||||||
Loading…
Reference in New Issue