Full Code of velorek1/c-edit for AI

master 253369833412 cached
32 files
163.4 KB
48.0k tokens
129 symbols
1 requests
Download .txt
Repository: velorek1/c-edit
Branch: master
Commit: 253369833412
Files: 32
Total size: 163.4 KB

Directory structure:
gitextract_9g946023/

├── LICENSE
├── README.md
├── TODO
├── TODO.md
└── src/
    ├── Makefile
    ├── TODO.md
    ├── edbuf.c
    ├── edbuf.h
    ├── editor.c
    ├── editor.h
    ├── fileb.c
    ├── fileb.h
    ├── global.c
    ├── global.h
    ├── keyb.c
    ├── keyb.h
    ├── listbox.c
    ├── listbox.h
    ├── main.c
    ├── menu.c
    ├── menu.h
    ├── opfile.c
    ├── opfile.h
    ├── rterm.c
    ├── rterm.h
    ├── scbuf.c
    ├── scbuf.h
    ├── t.txt
    ├── tm.c
    ├── tm.h
    ├── ui.c
    └── ui.h

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Velorek1

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
C-EDIT Project in C language (NO NCURSES)
=========================================
C-EDIT for linux - ALPHA - A linux text editor in the style of the MSDOS EDIT - WITHOUT USING NCURSES
Works well with Termux! :)
* WARNING: DO NOT EDIT YOUR PRECIOUS FILES WITH THIS EDITOR!!


Contact me at: velorek1@gmail.com

**NEW: AUGUST 2025**
- Fixed flickering issues in status bar
- Added pageup/down home/end keys

History:
- 2024 -> Dynamyc buffer added (vector of lineS)
- 2023 -> Previous demo version kept in https://github.com/velorek1/C-editold
- 2022 -> I have rewritten the screenbuffer and fixed polling issues (lynx: https://github.com/velorek1/lynx). 
Ideally, a keyboard library abstraction would be nice to expand the editor's possibilities.**
- 2018 -> Start of the project; basic demo concepts developed (https://oldstuff286.blogspot.com/2018/03/c-edit-in-progress.html)

TO INSTALL:  

    * Download or clone repository.
    * Type "cd src", "make" and "./cedit" to execute.
    
So far I have implemented:

* A very simple Double Screen Buffer with a simple linked list in memory for greater display control. 
* Rudimentary Text User Interface with Windows, Textbox, Keyboard handling, Color schemes, etc.
* Automatic display resizing.
* Open file dialog with a Listbox and SCROLL capabilities to navigate and find the file to open.
* Rudimentary Edit buffer with vertical and horizontal scroll (vector of lines). 
* A millisecond timer for animations.
* Timers and kbhit with no polling for optimate CPU usage.
* Greater modularity than Demo version
* Rudimentary syntax highlighting

Files in /src/:
===============
* rterm.c -> code for the library that handles output with Ansi Functions and kbhit() in linux console (with its header file)
* listbox.c -> code for the circular linked list responsible for handling menus 
* scbuf.c -> code for controlling display with a double screen buffer (with its header file)
* keyb.c -> module to control keyboard input.
* opfile.c -> module that list files with scroll capabilities to select the file to open.
* ui.c -> module with user interface widgets: alert windows, confirmation windows, textbox, etc.
* fileb.c -> module for single file operations.
* tm.c -> module for a millisecond timer for animations (C11)
* main.c -> Editor in C in the style of MSDOS EDIT (In progress).
* global.c -> Global variables and main animation
* menu.c -> Drop-down menu
* editor.c -> Code for the editor section
* edbuf.c -> Buffer - vector of lines


As a screen buffer I have implemented a dynamic structure in memory that allows to save the current screen so that you can display new things on top and then go back to the previous (saved) screen. (simple linked list)

TO-DO:
* Clean code
* Complete menus / dialogs 
* READ MODE
* FULL UTF 8! - SUPPORT change from char to win_t/wchar in editor buffer
* Copy/Paste/Cut routines / Highlight text
* Create Keyboard abstraction to make it more portable (bottom-up fashion!)
* Address glitches/bugs

![Alt text](cedit3.jpg?raw=true "Demo")
![Alt text](cedit4.jpg?raw=true "Demo")


================================================
FILE: TODO
================================================
* Top Priority:
Check https://github.com/velorek1/ceditbuf/ for latest development implementations (2024(

- Code a more backward compatible timer : tm.c (done!)
- Create Keyboard abstraction to make it more portable (bottom-up fashion!)
- Rewrite screen buffer (in progress).
- Rewrite and merge listbox with openfiledialog and menus.
- Turn fw into a library to display long text with scroll.
- Change editBuffer from static array to dynamic structure (in progress)
- Expand behaviour of ENTER and BACKSPACE and REAL TAB SUPPORT! (in progress)
- Add horizontal scroll (in progress)


* Less Priority:
- Highlight text and copy/paste function
- Find text
- Full UTF8 support?




================================================
FILE: TODO.md
================================================
* Top Priority: (2025)
- Complete menus / dialogs 
- READ MODE
- FULL UTF 8 - SUPPORT change char to win_t/wchar in editor buffer
- Copy/Paste/Cut routines / Highlight text
- Create Keyboard abstraction to make it more portable (bottom-up fashion!)
- Address glitches/bugs


================================================
FILE: src/Makefile
================================================
.POSIX:
TARGET = cedit
CC     = cc
CFLAGS = -Wall -Wextra -fsigned-char   
LDFLAGS =
LDLIBS  =

# The list of object files.
OBJS =  main.o rterm.o listbox.o scbuf.o
OBJS += ui.o fileb.o global.o menu.o editor.o 
OBJS += keyb.o tm.o edbuf.o opfile.o 

# the list of files to clean
TOCLEAN = cedit $(OBJS)

RM ?= rm -f

all: $(TARGET)
clean:
	$(RM) $(TOCLEAN)

cedit: $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

# INCLUDE DEPENDENCIES to compile depending on which
# source has been touched.
main.o: main.c rterm.h listbox.h scbuf.h keyb.h ui.h fileb.h tm.h 
fileb.o: fileb.c fileb.h
keyb.o: keyb.c rterm.h keyb.h
listbox.o: listbox.c scbuf.h keyb.h
editor.o: scbuf.h keyb.h rterm.h
rterm.o: rterm.c 
menu.o: listbox.c scbuf.h ui.h keyb.h rterm.h
tm.o: tm.c tm.h
global.o: global.c global.h
scbuf.o: scbuf.c rterm.h keyb.h scbuf.h
ui.o: ui.c scbuf.h rterm.h keyb.h
opfile.o: opfile.c scbuf.h rterm.h listbox.h keyb.h tm.h global.h ui.h 


================================================
FILE: src/TODO.md
================================================
# ceditbuf
C-edit with dynamic buffer (in development)


================================================
FILE: src/edbuf.c
================================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "edbuf.h"


// create new list element of type VLINES from the supplied text string
VLINES *_newline(VLINES temp)
{
	VLINES *newp;
	newp = (VLINES *) malloc (sizeof(VLINES));
	newp->index = temp.index;
	memcpy(newp->linea,temp.linea,sizeof(temp.linea)+1);
        newp->next = NULL;
	return newp;
}

// Delete first element on list whose item field matches the given text
// NOTE!! delete requests for elements not in the list are silently ignored :-)
void _RemoveThing(VLINES **head, int index)
{
	BOOL present = FALSE;
	VLINES *old;
	VLINES **tracer = head;
	if ((*tracer)->index==index) present=TRUE;
	while((*tracer) && !(present)){
		if ((*tracer)->index==index) present=TRUE;
		tracer = &(*tracer)->next;
	}

	if(present)
	{
		old = *tracer;
		*tracer = (*tracer)->next;
		free(old); // free up remainder of list element 
	}
}
void _hardupdateLINE(VLINES **head, int index, VLINES temp)
{
	int i=0;
	BOOL present = FALSE;
	VLINES **tracer = head;
	if ((*tracer)->index==index) present=TRUE;
	while((*tracer) && !(present)){
		if ((*tracer)->index==index) {present=TRUE; break;}
		tracer = &(*tracer)->next;
	}

	if(present)
	{
                for (i=0; i<MAX_LINE_SIZE; i++)
                {
                  (*tracer)->linea[i].ch = temp.linea[i].ch;
                  (*tracer)->linea[i].attrib = temp.linea[i].attrib;
                  (*tracer)->linea[i].specialChar = temp.linea[i].specialChar;
                }

	}
}
void _deletetheList(VLINES **head) 
{ 
   /* deref head_ref to get the real head */
   VLINES *current = *head; 
   VLINES *next = NULL;
   VLINES **tracer=head; 
   while (current != NULL)  
   { 
       next = current->next; 
       free(current);
       current = next; 
   } 
    
   /* deref head_ref to affect the real head back 
      in the caller. */

   *tracer = NULL;
} 


// updatelement: remove from list the first instance of an element 
VLINES *_update(VLINES *head, int index, VLINES temp)
{
	VLINES *p;
	for (p = head; p != NULL; p = p -> next) {
            if (p -> index == index) {
		break;
	   }
	}
	 p-> index = temp.index;	
	 return head;
	
}

// getObject 
VLINES *_getObject(VLINES *head, int index)
{
	VLINES *p;
	for (p = head; p != NULL; p = p -> next) {
            if (p -> index == index) {
		break;
	   }
	}
	 //p-> index = temp.index;	
	 return p;
	
}
// deleteline: remove from list the first instance of an element 
// containing a given text string
// NOTE!! delete requests for elements not in the list are silently ignored 
VLINES *_deleteline(VLINES *head, int index)
{
	VLINES *p, *prev;
	prev = NULL;
	for (p = head; p != NULL; p = p -> next) {
            if (p -> index == index) {
		if(prev == NULL)
		   head = p-> next;
		else
		   prev -> next = p -> next;
		free(p);	// remove rest of VLINES
		return head;
	   }
	   prev = p;	
	}
  return NULL;
}
/* addfront: add new VLINES to front of list  */
/* example usage: start = (addfront(start, newelement("burgers")); */

VLINES *_addfront(VLINES *head, VLINES *newp)
{
	newp -> next = head;
	return newp;
}

/* addend: add new VLINES to the end of a list  */
/* usage example: start = (addend(start, newelement("wine")); */

VLINES *_addatend (VLINES *head, VLINES *newp)
{
	VLINES *p2; 	
	if (head == NULL)
		return newp;
// now find the end of list
	for (p2 = head; p2 -> next != NULL; p2 = p2 -> next)
		;
	p2 -> next = newp;
	return head;
}

void _printlist(VLINES **head)
// this routine uses pointer-to-pointer techniques :-)
{
	VLINES **tracer = head;
	int index=0, i = 0;
	  while ((*tracer) != NULL) {
		index = (*tracer)->index;
		printf("LINE %d | ", index);
		for (i=0; i < MAX_LINE_SIZE; i++)
		      printf("%c",(*tracer)->linea[i].ch);
		printf("\n");
		tracer = &(*tracer)->next;
	  }  
}

int _length(VLINES **head)
// this routine uses pointer-to-pointer techniques :-)
{

	int count=0;
	VLINES **tracer = head;
	if (*head == NULL) return -1;
	while ((*tracer) != NULL) {
		count = count +1;	
		tracer = &(*tracer)->next;
	}
       return count;
}
void _reindex(VLINES **head)
{
	int count=0;	
	VLINES *p=NULL;
	VLINES **tracer = head;
	while ((*tracer) != NULL) {
		p = *tracer;
		p->index=count;
		count = count +1;
		tracer = &(*tracer)->next;
	}           
}

void _deleteObject(VLINES **head,int index, BOOL sort){
   VLINES *p=*head;
  if (index == 0 || _length(head) <=1 || p->index == index )
    _RemoveThing(head,index);
  else 
    _deleteline(*head,index);
  if (sort == TRUE) _reindex(head); 
}

int _dumpLine(VLINES *head, long index, VLINES *line){
//Dumps contents of desired line from buffer into temporary line
   int i=-1; char ch=0; char attrib = 0; char specialChar = 0;
   VLINES *aux = NULL; //auxiliary pointer
   aux = _getObject(head, index);
   memset(line, '\0',sizeof(&line)); //Clear memory for temporary line
   //Does the line exist?
   if (aux != NULL) { 
     for (i=0; i<MAX_LINE_SIZE; i++)
     {
       ch = aux->linea[i].ch;
       attrib = aux->linea[i].attrib;
       specialChar = aux->linea[i].specialChar;
       line->linea[i].ch = ch;
       line->linea[i].attrib = attrib;
       line->linea[i].specialChar = specialChar;
     }
     i = aux->index;
  }
  return i;
}
int _updateLine(VLINES *head, long index, VLINES *line){
//Copies contents of desired line from temporary line to buffer
   int i=0; char ch=0; char specialChar = 0; 
   char attrib = 0;
   VLINES *aux = NULL; //auxiliary pointer
   aux = _getObject(head, index);
   //Does the line exist?
   if (aux != NULL) { 
     for (i=0; i<MAX_LINE_SIZE-1; i++)
     {
       ch = line->linea[i].ch;
       specialChar = line->linea[i].specialChar;
       attrib = line->linea[i].attrib;
       aux->linea[i].ch = ch;
       aux->linea[i].specialChar = specialChar;
       aux->linea[i].attrib = attrib;
      }
     i = aux->index;
  } 
  return i;
}

CHARBUF _getSingleChar(VLINES *head, long X, long Y ){
//Dumps contents of desired line from buffer into temporary line
   char ch=0; char attrib = 0; char specialChar = 0;
   CHARBUF retvalues;
   VLINES *aux = NULL; //auxiliary pointer
   aux = _getObject(head, Y);
   //Does the line exist?
   if (aux != NULL) { 
       ch = aux->linea[X].ch;
       specialChar = aux->linea[X].specialChar;
       attrib = aux->linea[X].attrib;

     } else
  {
       ch = '\0';
       specialChar = '\0';
       attrib = '\0';
  }
  retvalues.ch = ch;
  retvalues.attrib = attrib;
  retvalues.specialChar = specialChar;
  return retvalues;
}

int findEndline(VLINES line) {
  char    ch = 0;
  int     i=0;
  int     result = 0;

  do {
    ch = line.linea[i].ch;
    //write_ch(i,1,ch,F_RED,B_WHITE);
    if(ch == 0x00 || ch == 0x10 || ch == 0x0A) //ch = 00
      break;
    i++;
  } while(i < MAX_LINE_SIZE);
  result = i;
  ch = 0;
  return result;
}

BOOL isLineTerminated(VLINES line) {
  BOOL flag=FALSE;
  char ch=0;
  int i = 0;
  for (i=0; i< MAX_LINE_SIZE; i++){
    ch = line.linea[i].ch;
    if(ch == 0x10 || ch == 0x0A)
      flag = TRUE;
  }
  return flag;
}




================================================
FILE: src/edbuf.h
================================================
#ifndef _EDBUF_H_
#define _EDBUF_H_

#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE_SIZE 512
#define TRUE 1
#define FALSE 0
typedef int BOOL;

typedef struct _charbuf
{
    char ch;
    char specialChar;
    char attrib;    
}CHARBUF;

typedef struct _vlines 
{ 
	int  index;
   	CHARBUF linea[MAX_LINE_SIZE];
	struct _vlines *next;
} VLINES;

/* Adapted from Kernighan and Pike's "The Practice of Programming"  pp.46 et 
seq. (Addison-Wesley 1999) */

// create new list element of type VLINES from the supplied text string
VLINES *_newline(VLINES temp);
VLINES *_addfront(VLINES *head, VLINES *newp);
VLINES *_addatend (VLINES *head, VLINES *newp);
VLINES *_addmiddle (VLINES *head, VLINES *newp);
VLINES *_update(VLINES *head, int index, VLINES temp);
VLINES *_getObject(VLINES *head, int index);
void _hardupdateLINE(VLINES **head, int index, VLINES temp);
void _RemoveThing(VLINES **head, int index);
void _deletetheList(VLINES **head);
VLINES *_deleteline(VLINES *head, int index);
void _deleteObject(VLINES **head,int index, BOOL sort);
int _length(VLINES **head);
void _printlist(VLINES **head);
void _reindex(VLINES **head);
int _dumpLine(VLINES *head, long index, VLINES *line);
int _updateLine(VLINES *head, long index, VLINES *line);
CHARBUF _getSingleChar(VLINES *head, long X, long Y );
int findEndline(VLINES line);
BOOL isLineTerminated(VLINES line);
#endif


================================================
FILE: src/editor.c
================================================
/* Main editor section C·edit 
 * for a Text User Interface
 * Last modified: 6/04/2024
 * @author:velorek
 */
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>
#include "rterm.h"
#include "scbuf.h"
#include "ui.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
#include "editor.h"
#include "fileb.h"
#include "edbuf.h"
int oldEndLine= 0;

wchar_t convertChar(char c1, char c2) {

    // Combine the bytes into a single string
    char temp[3];
    temp[0] = c1;
    temp[1] = c2;
    temp[2] = '\0';

    wchar_t wchar;

    mbstowcs(&wchar, temp, 1);

    return wchar;
}
void linetoScreenRAW(long whereY, VLINES tempLine){
//dump temporary Line to screen buffer - RAW MODE
   int i=0;
   int attrib = EDIT_FORECOLOR;
   int tempEndLine = findEndline(tempLine);
   //if (tempEndLine <0) return;
   for (i=0; i<tempEndLine; i++){
	   attrib = tempLine.linea[i+shiftH].attrib;  
         //don't print beyond display!

	 if (i+START_CURSOR_X < new_columns-1){
	  if(tempLine.linea[i+shiftH].specialChar!= 0) {
	    //Special char ? print the two values to screen buffer.
            gotoxy(i+START_CURSOR_X+1, whereY+1);
            outputcolor(attrib, EDITAREACOL);
            printf("%c%c", tempLine.linea[i+shiftH].specialChar,tempLine.linea[i+shiftH].ch);
	  } else {
	    gotoxy(i+START_CURSOR_X+1, whereY+1);
            outputcolor(attrib, EDITAREACOL);
            printf("%c", tempLine.linea[i+shiftH].ch);
  	  }
       }
   } 
}

void linetoScreen(long whereY, VLINES tempLine){
//dump temporary Line to screen buffer - RAW MODE
   int i=0;
   int attrib = EDIT_FORECOLOR;
   wchar_t temp='0';
   int tempEndLine = findEndline(tempLine);
   for (i=0; i<tempEndLine; i++){
	   attrib = tempLine.linea[i+shiftH].attrib;  
         //don't print beyond display!
	 if (i+START_CURSOR_X < new_columns-1){
	  if(tempLine.linea[i].specialChar != 0) {
	    //Special char ? print the two values to screen buffer.
            //write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);
            temp = convertChar(tempLine.linea[i+shiftH].specialChar, tempLine.linea[i+shiftH].ch);         // Second char
            //if (temp<1 ) {temp = FILL_CHAR; attrib =F_BLUE;}
            if ((temp<1 || temp =='\0' || temp==END_LINE_CHAR)) {temp = FILL_CHAR; attrib =F_BLUE;}
            write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);
	    
            //rintf("%c%c", tempLine.linea[i].specialChar,tempLine.linea[i].ch);
	  } else {
            //write_ch(screen1,i+START_CURSOR_X, whereY+1,tempLine.linea[i].ch,attrib,EDITAREACOL,0);
            temp = tempLine.linea[i+shiftH].ch;
            //if (temp<1 ) temp = FILL_CHAR; 
            if ((temp<1 || temp =='\0' || temp==END_LINE_CHAR)) {temp = FILL_CHAR; attrib =F_BLUE;}
            write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);
            //printf("%c", tempLine.linea[i].ch);
  	  }
       }
   }

}


void cleanScreenLine(long whereY)
{
   int i=0;
   for (i=0; i<new_columns-2; i++){
	 	gotoxy(i+START_CURSOR_X+1, whereY+1);
         	outputcolor(EDIT_FORECOLOR, EDITAREACOL);
          	printf("%c", FILL_CHAR);
	}
    resetAnsi(0);
   
}

void cleanSection(long whereY, long start, int amount)
{
   int i=0;
   for (i=start; i<start+amount; i++){
	   if (i<new_columns-2){
	 	gotoxy(i+START_CURSOR_X+1, whereY+1);
        	outputcolor(EDIT_FORECOLOR, EDITAREACOL);
          	printf("%c", FILL_CHAR);
	   }
	}
    resetAnsi(0);
   
}



void buffertoScreen(BOOL raw){
   long j=0;
   if (raw == 0) flush_editarea(0);
   for (j=0; j<vdisplayArea; j++){
	  _dumpLine(edBuf1, j+currentLine , &tempLine);
 	  if (raw==TRUE){ 
	      cleanScreenLine(j+START_CURSOR_Y);
	      linetoScreenRAW(j+START_CURSOR_Y, tempLine);
	  }else{ 
	      //cleanScreenLine(j+START_CURSOR_Y);
              linetoScreen(j+START_CURSOR_Y, tempLine);
	  }
	}
//restore tempLine to active line
     memset(&tempLine, '\0',sizeof(tempLine));
    _dumpLine(edBuf1, currentLine, &tempLine);
    resetAnsi(0);
}

void buffertoFile(char *fileName){
  long j=0,i=0; 
  wchar_t tempLongChar = 0;
  openFile(&filePointer, fileName, "w");
  if (filePointer != NULL){
  for (j=0; j<_length(&edBuf1); j++){
       //tempLine = {0};
      _dumpLine(edBuf1, j, &tempLine);
      for (i=0; i<findEndline(tempLine); i++){

	  if(tempLine.linea[i].specialChar != 0) {
            tempLongChar = convertChar(tempLine.linea[i].specialChar, tempLine.linea[i].ch);         // Special character
            fprintf(filePointer, "%lc", tempLongChar); 
	  }else{		 
            //regular ASCII char
            fprintf(filePointer, "%c", tempLine.linea[i].ch); 
	  }
      }
      fprintf(filePointer,"%c" , END_LINE_CHAR);
  }
  closeFile(filePointer);

	   fileModified = FILE_UNMODIFIED;
  }
};

int editor_section(char ch){
char accentchar[2];
int insertMode=0;
VLINES *aux = NULL;
VLINES splitLine = {0};
int i,j=0;
int attrib=EDIT_FORECOLOR;
char newch=0;
int endLine=0;
       
       if (fileModified==FILE_UNMODIFIED) fileModified= FILE_MODIFIED;
       //Check whether we are on Readmode
       // if (fileModified != FILE_READMODE) {
       //if ((ch > 31 && ch < 127) || ch < 0) {

       // A KEY IS PRESSED AND ADDED TO EDIT BUFFER
       // FIRST check for negative chars and special characters
        newch=ch;
        accentchar[0] = 0;
        accentchar[1] = newch;
       //Check whether we are on Readmode
       // if (fileModified != FILE_READMODE) {
     //Process normal printable chars first
     if (ch == 27) return 0;

     if ((ch > 31 && ch < 127) || ch < 0) {
	if (ch < 0) {
	    read_accent(&newch, accentchar);
	    newch = accentchar[1];
      }
      //if ((posBufX != endLine) && (shiftH>0)) return 0;
      //check if we are at the limit of our display to print chars
      if (cursorX < new_columns-2) cursorX++;
      if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {shiftH++;}
      //write_num(screen1,20,2,currentLine,B_CYAN,F_WHITE,1);
      //SYNTAX HIGHLIGHTING DEMO
      //Highlight numbers in GREEN
      if ((accentchar[1] >= 48) && (accentchar[1] <=57)) attrib = FH_GREEN; 
      //Highlight special characters in CYAN
      
      if ((accentchar[1] >= 33) && (accentchar[1] <=47)) attrib = FH_CYAN; 
      aux = _getObject(edBuf1, posBufY);
      if ((accentchar[1] >= 58) && (accentchar[1] <=64)) attrib = FH_CYAN; 
      aux = _getObject(edBuf1, posBufY);
      if ((accentchar[1] >= 91) && (accentchar[1] <=96)) attrib = FH_CYAN; 
      aux = _getObject(edBuf1, posBufY); 
      if ((accentchar[1] >= 123) && (accentchar[1] <=126)) attrib = FH_CYAN; 
      aux = _getObject(edBuf1, posBufY);

      //FIRST TIME -> CREATE LINES IN BUFFER
      if (aux == NULL) {
	//FIRST CHAR - if not we create a new line in buffer

      	tempLine.index = posBufY;
	//Add spaces if cursor is not at (0,0)
 	if (posBufX != 0) {
		for (i=0; i<posBufX; i++) {
			tempLine.linea[i].ch = FILL_CHAR;
        		tempLine.linea[i].specialChar = 0;
			tempLine.linea[i].attrib = EDIT_FORECOLOR;
		}
	}	
	tempLine.linea[posBufX].ch = accentchar[1];
        tempLine.linea[posBufX].specialChar = accentchar[0];
        tempLine.linea[posBufX].attrib = attrib;
	//add end_line_char to line
	posBufX = posBufX + 1;
	tempLine.linea[posBufX].ch = END_LINE_CHAR;
        tempLine.linea[posBufX].specialChar = 0;
        tempLine.linea[posBufX].attrib = attrib;
	edBuf1 = _addatend(edBuf1, _newline(tempLine));
	linetoScreenRAW(cursorY,tempLine);          

     } else
	//LINE ALREADY EXISTS
	{
	//Locate the end of the line
	endLine = findEndline(tempLine);

	//Insert characters in the middle of other characters
	if (endLine > posBufX) {

	   tempLine.index = posBufY; //with every line index is incremented
	   if (insertMode == FALSE){
	     for (i=endLine; i>=posBufX; i--){ 
                 tempLine.linea[i+1].ch = tempLine.linea[i].ch;
                 tempLine.linea[i+1].specialChar = tempLine.linea[i].specialChar;
                 tempLine.linea[i+1].attrib = tempLine.linea[i].attrib;
              }
	    }
             tempLine.linea[posBufX].ch = accentchar[1];
             tempLine.linea[posBufX].specialChar = accentchar[0];
             tempLine.linea[posBufX].attrib = attrib;
              posBufX = posBufX + 1;
             _updateLine(edBuf1, posBufY, &tempLine);
	     linetoScreenRAW(cursorY,tempLine);	
	     	
	}
          	
	else {
	  // POSBUFX >= ENDLINE: Cursor is at the end or further away from latest text
          //ADD SPACES IF CURSOR IS NOT AT THE END OF THE LINE AND LINE ALREADY EXISTS
	  if(posBufX > endLine) {	  
	    for(i = endLine; i < posBufX; i++) {
	     tempLine.linea[i].ch = FILL_CHAR;
             tempLine.linea[i].specialChar = 0;
	     tempLine.linea[i].attrib = EDIT_FORECOLOR;
	   } 
          }
	  tempLine.linea[posBufX].ch = accentchar[1];
          tempLine.linea[posBufX].specialChar = accentchar[0];
          tempLine.linea[posBufX].attrib = attrib;
	   posBufX = posBufX + 1;
	  tempLine.linea[posBufX].ch = END_LINE_CHAR;
          tempLine.linea[posBufX].specialChar = 0;
          tempLine.linea[posBufX].attrib = attrib;
	  _updateLine(edBuf1, posBufY, &tempLine);  
	  linetoScreenRAW(cursorY,tempLine);
	  //the cursor returns to its place when scrolling horizontally
          if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {cursorX--;}
         }
      }
	if (shiftH>0){
		buffertoScreen(1);
	}

    }
    //record previous values
    old_cursorX = cursorX;
    old_cursorY = cursorY;
    oldposBufX = posBufX;
    oldposBufY = posBufY;
    oldEndLine = endLine;
   //HANDLE ENTER KEY 

   if (ch == K_ENTER) {
    // ENTER key
    update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL);

    // Move cursor down if not at the bottom of the screen
    if (cursorY < new_rows - 3) {
        cursorY++;
    }
    cursorX = START_CURSOR_X;

    // If the buffer pointer is at the end, create a new empty line
    if (_length(&edBuf1) <= posBufY) {
        // Create a new line without characters in the current line in the edit buffer
        memset(&tempLine, '\0', sizeof(tempLine));
        tempLine.index = _length(&edBuf1);
        tempLine.linea[0].ch = END_LINE_CHAR;
        tempLine.linea[0].specialChar = 0;
        tempLine.linea[0].attrib = 0;
        edBuf1 = _addatend(edBuf1, _newline(tempLine));
    } else {
        // SPLIT LINE INTO TWO
        _dumpLine(edBuf1, posBufY, &tempLine);
        endLine = findEndline(tempLine);

        // Create a new line to insert the split content
        memset(&splitLine, '\0', sizeof(splitLine));
        memset(&tempLine, '\0', sizeof(tempLine));
        tempLine.index = _length(&edBuf1);
        edBuf1 = _addatend(edBuf1, _newline(tempLine));

        // Move lines below the current line down by one
        for (j = _length(&edBuf1) - 1; j > posBufY; j--) {
            _dumpLine(edBuf1, j, &tempLine);
            _updateLine(edBuf1, j + 1, &tempLine);
            if (j + START_CURSOR_Y < new_rows - 3) {
                cleanSection(j + START_CURSOR_Y, 0, findEndline(tempLine));
            }
        }

        // Split the current line at the cursor position
        _dumpLine(edBuf1, posBufY, &tempLine);
        memset(&splitLine, '\0', sizeof(splitLine));

        // Copy characters before the cursor to the current line
        for (i = 0; i < posBufX; i++) {
            splitLine.linea[i].ch = tempLine.linea[i].ch;
            splitLine.linea[i].specialChar = tempLine.linea[i].specialChar;
            splitLine.linea[i].attrib = tempLine.linea[i].attrib;
        }
        if (isLineTerminated(splitLine) == FALSE) {
            splitLine.linea[i].ch = END_LINE_CHAR;
        }
        _updateLine(edBuf1, posBufY, &splitLine);

        // Move characters after the cursor to the next line
        memset(&splitLine, '\0', sizeof(splitLine));
        j = 0;
        for (i = posBufX; i < endLine; i++) {
            splitLine.linea[j].ch = tempLine.linea[i].ch;
            splitLine.linea[j].specialChar = tempLine.linea[i].specialChar;
            splitLine.linea[j].attrib = tempLine.linea[i].attrib;
            j++;
        }
        if (isLineTerminated(splitLine) == FALSE) {
            splitLine.linea[j].ch = END_LINE_CHAR;
        }

        // Update the new line with the split content
        _updateLine(edBuf1, posBufY + 1, &splitLine);

        // Clean the screen for the current line and refresh the buffer
        cleanSection(cursorY - 1, 0, findEndline(tempLine));
        buffertoScreen(TRUE);
    }

    // Scroll if needed when cursor is at the bottom of the screen
    if (_length(&edBuf1) > vdisplayArea && cursorY == new_rows - 3) {
        buffertoScreen(1);
        currentLine++;
    }

    // Move buffer pointer positions
    posBufY++;
    posBufX = 0;
}

if(ch == K_BACKSPACE) {
    // BACKSPACE key
    update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL);

    if (posBufX == findEndline(tempLine)) {
        // Cursor is at the end of the line
        tempLine.linea[posBufX-1].ch = 0;
        tempLine.linea[posBufX-1].specialChar = 0;
        tempLine.linea[posBufX-1].attrib = 0;
    } else {
        // Shift characters to the left if we are not at the end of the line
        if (posBufX != 0) {
            for(i = posBufX - 1; i < findEndline(tempLine) - 1; i++) {
                tempLine.linea[i].ch = tempLine.linea[i + 1].ch;
                tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar;
                tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib;
            }
            // Clear the last character in the line
            tempLine.linea[i].ch = 0;
            tempLine.linea[i].specialChar = 0;
            tempLine.linea[i].attrib = 0;
        }
    }

    // Remove line if we continue pressing backspace at the beginning of a line
    if(cursorX == START_CURSOR_X && cursorY > START_CURSOR_Y) {
        if (posBufY > 0) {
            memset(&tempLine, '\0', sizeof(tempLine));
            memset(&splitLine, '\0', sizeof(splitLine));
            _dumpLine(edBuf1, posBufY - 1, &tempLine);

            if (findEndline(tempLine) < 1) {
                // Previous line is empty, remove it
                for (j = posBufY - 1; j < _length(&edBuf1) - 1; j++) {
                    _dumpLine(edBuf1, j + 1, &tempLine);
                    _hardupdateLINE(&edBuf1, j, tempLine);
                }
                _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);
            } else {
                // Merge two lines
                endLine = findEndline(tempLine);
                _dumpLine(edBuf1, posBufY, &splitLine);
                
                for (i = 0; i < findEndline(splitLine); i++) {
                    tempLine.linea[endLine + i].ch = splitLine.linea[i].ch;
                    tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib;
                    tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar;
                }
                tempLine.linea[endLine + i].ch = END_LINE_CHAR;

                _hardupdateLINE(&edBuf1, posBufY - 1, tempLine);

                // Update subsequent lines
                for (j = posBufY; j < _length(&edBuf1) - 1; j++) {
                    _dumpLine(edBuf1, j + 1, &tempLine);
                    _hardupdateLINE(&edBuf1, j, tempLine);
                }
                _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);
            }

            posBufY--;
            cursorY--;
            if (cursorY == new_rows - 3 && currentLine > 0) currentLine--;
            buffertoScreen(1);
            _dumpLine(edBuf1, posBufY, &tempLine);

            // Adjust cursor position after merging lines
            if (findEndline(splitLine) != 0 && findEndline(splitLine) != findEndline(tempLine)) {
                posBufX = findEndline(tempLine) + 1;
                cursorX = posBufX + START_CURSOR_X;
            } else {
                if (endLine != findEndline(tempLine)) {
                    cursorX = START_CURSOR_X;
                    posBufX = cursorX - 1;
                } else {
                    posBufX = findEndline(tempLine) + 1;
                    cursorX = posBufX + START_CURSOR_X;
                }
            }
        }
    }

    // Normal backspace within a line
    if(cursorX > START_CURSOR_X) {     
        cursorX--;
        posBufX--;
        _updateLine(edBuf1, posBufY, &tempLine);
    }

    // Clean up and refresh the line on screen
    cleanSection(cursorY, findEndline(tempLine), 2);
    linetoScreenRAW(cursorY, tempLine);
}

if (deleteKeyPressed == 1) {
    deleteKeyPressed = 0;         	    
    // DEL key
    if (posBufX == findEndline(tempLine)) {
        // Cursor is at the end of the line
        if (posBufY < _length(&edBuf1) - 1) {
            // If there is a next line, merge it with the current line
            _dumpLine(edBuf1, posBufY + 1, &splitLine);
            endLine = findEndline(tempLine);
            
            // Copy the characters from the next line to the end of the current line
            for (i = 0; i < findEndline(splitLine); i++) {
                tempLine.linea[endLine + i].ch = splitLine.linea[i].ch;
                tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib;
                tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar;
            }
            tempLine.linea[endLine + i].ch = END_LINE_CHAR;
            
            // Update the buffer with the modified line
            _hardupdateLINE(&edBuf1, posBufY, tempLine);
            
            // Remove the next line from the buffer
            for (j = posBufY + 1; j < _length(&edBuf1); j++) {
                _dumpLine(edBuf1, j + 1, &tempLine);
                _hardupdateLINE(&edBuf1, j, tempLine);
            }
            _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);
            
            // Update the screen
            buffertoScreen(1);
        }
    } else {
        // Cursor is in the middle of the line, so delete the character at the cursor position
        for (i = posBufX; i < findEndline(tempLine); i++) {
            tempLine.linea[i].ch = tempLine.linea[i + 1].ch;
            tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar;
            tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib;
        }
        tempLine.linea[i].ch = 0; // Nullify the last character

        // Update the buffer with the modified line
        _updateLine(edBuf1, posBufY, &tempLine);

        // Update the screen
        cleanSection(cursorY, findEndline(tempLine), 2);
        linetoScreenRAW(cursorY, tempLine);
    }
}

    if(ch == K_TAB) {
      //TAB key sends spaces for convenience
      	      for (i=posBufX; i<posBufX+TAB_SPACES; i++)

		{
	            tempLine.linea[i].ch = FILL_CHAR;
                    tempLine.linea[i].specialChar = 0;
                    tempLine.linea[i].attrib = EDIT_FORECOLOR;
	      }      
	      posBufX=posBufX + TAB_SPACES;
	      if (cursorX < new_columns-8) {
                      for (i=0; i<TAB_SPACES; i++) update_ch(cursorX+i, cursorY, ' ', EDITAREACOL, EDITAREACOL);
		      cursorX = cursorX + TAB_SPACES;
	      }
        _updateLine(edBuf1, posBufY, &tempLine);    
     }

   return 0; 
}

/*------------------------------*/
/* Open file and dump to buffer */
/*------------------------------*/

int filetoBuffer(char *fileName) { //EDBUF*
  long     inlineChar = 0, lineCounter = 0;
  //wchar_t tempLongChar = 0;
  char    ch;
  int attrib = EDIT_FORECOLOR;
  fileModified = FILE_UNMODIFIED;
  
  openFile(&filePointer, fileName, "r");
  memset(&tempLine, '\0',sizeof(tempLine));
  tempLine.index = 0;
  if (edBuf1 != NULL) _deletetheList(&edBuf1);
  edBuf1 = _addatend(edBuf1, _newline(tempLine));

  //Check if pointer is valid
  if(filePointer != NULL) {
    rewind(filePointer);        //Make sure we are at the beginning
    ch = getc(filePointer);     //Peek ahead in the file
    while(!feof(filePointer)) {
      if(ch != '\0') {
    //Temporary restrictions until scroll is implemented.
    //if(lineCounter == rows - 4)
    //  break;

    if(ch == SPECIAL_CHARS_SET1 || ch == SPECIAL_CHARS_SET2) {
      tempLine.linea[inlineChar].specialChar = ch;
      //Read accents
      ch = getc(filePointer);
      tempLine.linea[inlineChar].ch = ch;
    } else {
      if(ch > 0)
       tempLine.linea[inlineChar].ch = ch;
    }
       //SYNTAX HIGHLIGHTING DEMO
      //Highlight numbers in GREEN
      attrib = EDIT_FORECOLOR;
      if ((ch >= 48) && (ch <=57)) attrib = FH_GREEN; 
      //Highlight special characters in CYAN
      
      if ((ch >= 33) && (ch <=47)) attrib = FH_CYAN; 
      if ((ch >= 58) && (ch <=64)) attrib = FH_CYAN; 
      if ((ch >= 91) && (ch <=96)) attrib = FH_CYAN; 
      if ((ch >= 123) && (ch <=126)) attrib = FH_CYAN; 

   
     tempLine.linea[inlineChar].attrib = attrib;
        //TABs are converted into spaces
      /*  if(ch == K_TAB) {
        for (tabcount=0;tabcount<TAB_DISTANCE;tabcount++){
          ch = FILL_CHAR;
          writetoBuffer(editBuffer, inlineChar, lineCounter, ch);
          inlineChar++;
        }*/

    inlineChar++; //NEXT CHARACTER

    if(ch == END_LINE_CHAR) {
      inlineChar = 0;
      ch = 0;
      _updateLine(edBuf1, lineCounter, &tempLine);
      lineCounter++;
      memset(&tempLine, '\0',sizeof(tempLine));
      tempLine.index = _length(&edBuf1);
      edBuf1 = _addatend(edBuf1, _newline(tempLine));
    }
       if (lineCounter == MAX_LINES) {
           //open as readMode
           fileModified = FILE_READMODE;
           break;
       }
       //If file is bigger than buffer
      //break loop at last allowed line.
      }
      ch = getc(filePointer);
    }
  }
  closeFile(filePointer);
  return 1;
}

void flush_editarea(int force_update) {
int i;
  //Paint blue edit area
  //draw_screen();
  screen_color(screen1, EDITAREACOL, EDITAREACOL, FILL_CHAR);
  //Draw upper and lower bars
    for(i = 0; i < old_columns; i++) {
     write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0);
    }

  for(i = 0; i < old_columns; i++) {
    write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1);
  }
  // Text messages
  write_str(screen1, 0, 1, "File  Options  Help", MENU_PANEL, MENU_FOREGROUND0,0);
  write_str(screen1, 0, 1, "F", MENU_PANEL, F_RED,0);
  write_str(screen1, 7, 1, "p", MENU_PANEL, F_RED,0);
  write_str(screen1, 15, 1, "H", MENU_PANEL, F_RED,0);
  write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0);

  /* Frames */
  //window appearance and scroll bar
  for(i = 2; i < old_rows; i++) {
    write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0);	//Scroll bar
    write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//upper vertical line box-like char 
  }
  for(i = 0; i < old_columns; i++) {
    write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//horizontal line box-like char
    write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0);
  }
  write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//upper-left box-like char
  //horizontal scroll bar
  for(i = 0; i < old_columns; i++) {
    write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0);
  }
  //Window-appearance
  write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//right window corner
  write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK,
	   EDITWINDOW_FORE,0);
  write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK,
	   EDITWINDOW_FORE,0);

  //Scroll symbols
  write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
  write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
  write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  if (strlen(fileName) == 0) strcpy(fileName,"UNTITLED");
  write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName,
        MENU_PANEL, MENU_FOREGROUND0,0);
 if (force_update) dump_screen(screen1);
}


================================================
FILE: src/editor.h
================================================
/*
========================================================================
- HEADER -
Module with main editor in C·edit
@author : Velorek
@version : 1.0
Last modified: 06/04/2024
========================================================================
*/

#ifndef _EDITOR_H_
#define _EDITOR_H_

#include "scbuf.h"
#include "global.h"
#include "edbuf.h"
#include <stdio.h>
int process_input(char ch);
int special_keys();
int control_keys(char ch);
void linetoScreen(long whereY, VLINES tempLine);
void linetoScreenRAW(long whereY, VLINES tempLine);
void cleanScreenLine(long whereY);
void cleanSection(long whereY, long start, int amount);
void buffertoScreen(BOOL raw);
int editor_section(char ch);
wchar_t convertChar(char c1, char c2);
//int filetoBuffer(FILE * filePtr);
void buffertoFile(char *fileName);
int filetoBuffer(char *fileName);
void flush_editarea(int force_update);
#endif




================================================
FILE: src/fileb.c
================================================
/* 
======================================================================
Module to describe basic file operations.

@author : Velorek
@version : 1.0
 
LAST MODIFIED : 14/04/2019 - Rename headers 
======================================================================
*/

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <stdio.h>
#include "global.h"
#include "fileb.h"
/*====================================================================*/
/* FUNCTIONS - CODE                                                   */
/*====================================================================*/

/*----------------------*/
/* Check if file exists */
/*----------------------*/

int file_exists(char *fileName) {
  int     ok=0;
  if(access(fileName, F_OK) != -1) {
    ok = 1;			//File exists
  } else {
    ok = 0;
  }
  return ok;
}

/*---------------*/
/* Get file size */
/*---------------*/

long getfileSize(FILE * filePtr) {
  long    sz=0;
  if(filePtr != NULL) {
    fseek(filePtr, 0L, SEEK_END);
    sz = ftell(filePtr);
    rewind(filePtr);
  }

  return sz;
}

/*---------------------*/
/* Count lines in File */
/*---------------------*/

long countLinesFile(FILE * filePtr) {
  char    ch=0;
  long    counterA = 0;
  if(filePtr != NULL) {
    rewind(filePtr);		//Make sure we are at the beginning

    ch = getc(filePtr);		//Peek ahead in the file
    while(!feof(filePtr)) {
      if(ch == END_LINE_CHAR) {
	counterA++;
      }
      ch = getc(filePtr);
    }
  }
  return counterA;
}

/*-----------------*/
/* Check file type */
/*-----------------*/


long checkFile(FILE * filePtr) {
  char    ch=0;
  long    counterA = 0;
  if(filePtr != NULL) {
    rewind(filePtr);		//Make sure we are at the beginning

    ch = getc(filePtr);		//Peek ahead in the file
    while(!feof(filePtr)) {
      if(ch < 9) {
	//discard accents
	if(ch > -60)
	  counterA++;
      }
      ch = getc(filePtr);
    }
  }
  return counterA;
}

//check whether the file is a text file
int openandcheckFile(char *fileName) {
  unsigned char    ch=0;
  long    counterA = 0;
  FILE *fp;

  openFile(&fp, fileName, "r");
  if(fp != NULL) {
    rewind(fp);		//Make sure we are at the beginning

    ch = getc(fp);		//Peek ahead in the file
    while(!feof(fp)) {
 
      if (ch == 0x00) {closeFile(fp); fp = NULL; return 1;}
      if(ch < 9) {
	//discard accents
	if(ch > 196)
	  counterA++;
      }
      ch = getc(fp);
    }
  }
  //If there are more strange characters than half the size of the file probably a binary file
  if (counterA > (getfileSize(fp)/2)) {
     if (fp != NULL) closeFile(fp); 
     fp = NULL;
  return 1;
  }
   if (fp != NULL) closeFile(fp);
    fp = NULL; 
  return 0;
}
/*-----------*/
/* Open file */
/*-----------*/

int openFile(FILE ** filePtr, char fileName[], char *mode)
/* 
Open file.
@return ok = 1 ? 0 Success! 
*/
{
  int     ok = 0;
  *filePtr = fopen(fileName, mode);

  if(*filePtr != NULL) {
    //File opened correctly.
    ok = 1;
  } else {
    //Error
    ok = 0;
  }
  return ok;
}

/*------------*/
/* Close file */
/*------------*/

int closeFile(FILE * filePtr) {
/* 
   Close file
@return ok: 
*/
  int     ok=0;

  if(filePtr != NULL) {
    ok = fclose(filePtr);
  }

  return ok;
}



================================================
FILE: src/fileb.h
================================================
/*
========================================================================
- HEADER - 
Module to handle basic file operations
@author : Velorek
@version : 1.0  
Last modified: 31/08/2025 Open and check file                                                           
========================================================================
*/

#ifndef _FILEB_H_
#define _FILEB_H_

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <stdio.h>
#include "scbuf.h"

/*====================================================================*/
/* CONSTANTS                                                          */
/*====================================================================*/
#define CONFIGFILE "cedit.cfg"

/*====================================================================*/
/* FUNCTION PROTOTYPES                                                */
/*====================================================================*/

int     openFile(FILE ** filePtr, char fileName[], char *mode);
int     closeFile(FILE * filePtr);
long    getfileSize(FILE * filePtr);
long    countLinesFile(FILE * filePtr);
long    checkFile(FILE * filePtr);
int     openandcheckFile(char *fileName);
int     file_exists(char *fileName);

#endif


================================================
FILE: src/global.c
================================================
#include "global.h"
#include "rterm.h"
#include "time.h"

// GLOBALS : SCREEN1 : ANIMATED | SCREEN2 : BASE SCREEN
LISTCHOICE *listBox1 = NULL;
SCREENCELL *screen1=NULL;
SCREENCELL *screen2=NULL;
SCREENCELL *screen3=NULL;
NTIMER cursor_timer1;
NTIMER timer2;
NTIMER timer3;
//NTIMER timer4;
SCROLLDATA scrollData;
VLINES *edBuf1=NULL; //Buffer vector of lines(1022 chars)
VLINES tempLine;

//C-Edit Theme
int EDITAREACOL= B_BLUE;
int EDIT_FORECOLOR=FH_WHITE;
int STATUSBAR =B_BLACK;
int STATUSMSG =F_WHITE;
int MENU_PANEL =B_WHITE;
int MENU2_PANEL = B_BLACK;
int MENU_SELECTOR =B_RED;
int MENU_FOREGROUND0 =F_BLACK;
int MENU2_FOREGROUND0 = F_WHITE;
int MENU_FOREGROUND1= FH_WHITE;
int EDITWINDOW_BACK= B_BLUE;
int EDITWINDOW_FORE= F_WHITE;
int SCROLLBAR_BACK= B_WHITE;
int SCROLLBAR_FORE= FH_WHITE;
int SCROLLBAR_SEL= B_CYAN;
int SCROLLBAR_ARR= B_BLACK;
int WINDOW_TITLEB = B_BLACK; 
int WINDOW_TITLEF = F_WHITE;

int new_rows = 0, new_columns = 0, old_rows = 0, old_columns = 0;	// Terminal dimensions
int cursorX = START_CURSOR_X, cursorY = START_CURSOR_Y;
int old_cursorX = START_CURSOR_X, old_cursorY = START_CURSOR_Y;
long posBufX = 0, posBufY = 0;
long oldposBufX = 0, oldposBufY = 0;
long shiftH = 0;
int unwantedChars = 0; //try to avoid printing unwanted characgters from cursor chars counter
		
//TEXT BUFFER POINTERS
int  hdisplayLimit=0; //horizontal scroll, last char position in line that allows scroll
int  currentColumn=0; //horizontal scroll, pointer to current char position in line
long linesinFile=0; //vertical scroll
long vdisplayLimit=0; //vertical scroll, last line that allows scroll
int vdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes 
int hdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes 
long currentLine=0; //verticall scroll, pointer to current top line in scroll
int vscrollActive=0; //vertical scroll, vertical scroll is posible
//extern int hscrollActive; //horizontal scroll, horizontal scroll is posible
int     programStatus = 0; //signal for overall program Status
char fileName[MAXFILENAME]; 
char fullPath[MAXFILENAME]; 

FILE *filePointer;
int fileModified=FILE_UNMODIFIED;
int deleteKeyPressed = 0;         	    

char aboutMSG[7][MAXLINE] = {ABOUT_ASC_0,ABOUT_ASC_1,ABOUT_ASC_2,ABOUT_ASC_3,ABOUT_ASC_4,ABOUT_ASC_5};
char help[HELPLINES][MAXLINE] = { HELP0,
	HELP1, HELP2, HELP3,
	HELP4, HELP5, HELP6,
	HELP7, HELP8, HELP9,
	HELP10, HELP11, HELP12,
	HELP13, HELP14, HELP15,
	HELP16, HELP17, HELP18,
	HELP19, HELP20
};
int initCEDIT(){
   get_terminal_dimensions(&new_rows,&new_columns);
   //Init timer
   init_timer(&cursor_timer1,TIMER_SPEED);
   init_timer(&timer2,TIMER_SPEED2);
   init_timer(&timer3,TIMER_SPEED3);
   //init_timer(&timer4,ABOUT_SPEED);
   timer2.ticks=0;
   timer3.ticks=-1;
   //timer4.ticks=0;
   cursor_timer1.ticks=0;
   //Init Text buffer
   VLINES tempLine = {0};
  
   memset(&fileName, '\0',sizeof(fileName)); //Clear fileName
   memset(&tempLine, '\0',sizeof(tempLine)); //Clear memory for temporary line
   //Create one screen in memory
   if (screen1 != NULL) deleteList(&screen1);
   if (screen2 != NULL) deleteList(&screen2);
     //Init 2 : Create 2 Screens for a double buffer  approach  
   old_rows=new_rows;
   old_columns=new_columns;
   create_screen(&screen1);
   create_screen(&screen2);
   //how many lines are vertical display area consists of
   vdisplayArea = new_rows - 4;
   hdisplayArea = new_columns - 2;	
   shiftH=0; 
   return 0;
}	

int _animation(){ 
/* Timer for animations - Display time and clean cursor */
  time_t  mytime = time(NULL);
  char   *time_str = ctime(&mytime);
  char    temp[4];

  temp[0] = '[';
  temp[1] = ANIMATION[timer2.ticks];
  temp[2] = ']';
  temp[3] = '\0';
    get_terminal_dimensions(&new_rows,&new_columns);
    resetAnsi(0);
    time_str[strlen(time_str) - 1] = '\0';
    //display system time
    update_str(new_columns - strlen(time_str) - 1, 0, time_str, MENU_PANEL,
          MENU_FOREGROUND0);
    update_str(new_columns - strlen(time_str) - 5, 0, temp, MENU_PANEL,
          MENU_FOREGROUND0);
    printf("\n");
    //update only the screen bits that change
    if(timer2.ticks > 6)
      timer2.ticks = 0;
    //return a signal if screen size changes
     if (new_rows != old_rows || new_columns != old_columns)
		return -1;
	else
		return 0;
   
    

}




================================================
FILE: src/global.h
================================================
/*
 * Global variables are intented to be placed here
 * Last modified: 9/7/2022
 * @author: velorek
 *
 */
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#include "scbuf.h"
#include "tm.h"
#include "edbuf.h" 
#include "listbox.h" 

#define TIMER_SPEED 100 //animation
#define TIMER_SPEED2 30 //cursor
#define TIMER_SPEED3 100 //temporary messages
//#define ABOUT_SPEED 300 //about animation
#define END_LINE_CHAR 0x0A
#define FILL_CHAR 0x20
#define ENDSIGNAL -1
#define ESC_KEY '\e'
#define ROWS_FAILSAFE 25
#define COLUMNS_FAILSAFE 80 
#define TRUE 1
#define FALSE 0
#define CURSOR_CHAR '|'
typedef int BOOL;

//USER-DEFINED MESSAGES
extern SCREENCELL *screen1;
extern SCREENCELL *screen2;
extern NTIMER cursor_timer1;
extern NTIMER timer2;
extern NTIMER timer3;
//extern NTIMER timer4;
extern size_t animation;
extern int centerX;
//extern LISTCHOICE listBox1;
extern SCROLLDATA scrollData;
extern VLINES *edBuf1; //Buffer vector of lines(512 chars)
extern VLINES tempLine;

//COLOR SCHEME
extern int EDITAREACOL;
extern int EDIT_FORECOLOR;
extern int STATUSBAR;
extern int STATUSMSG;
extern int MENU_PANEL;
extern int MENU2_PANEL;
extern int MENU_SELECTOR;
extern int MENU_FOREGROUND0;
extern int MENU2_FOREGROUND0;
extern int MENU_FOREGROUND1;
extern int EDITWINDOW_BACK;
extern int EDITWINDOW_FORE;
extern int SCROLLBAR_BACK;
extern int SCROLLBAR_FORE;
extern int SCROLLBAR_SEL;
extern int SCROLLBAR_ARR;
extern int WINDOW_TITLEB; // to be accessible from opfile.c
extern int WINDOW_TITLEF;

//GOODBYE MSG - ASCII ART
#define cedit_ascii_1 "  _____      ______    _ _ _   \n"
#define cedit_ascii_2 " / ____|    |  ____|  | (_) |  \n"
#define cedit_ascii_3 "| |   ______| |__   __| |_| |_ \n"
#define cedit_ascii_4 "| |  |______|  __| / _` | | __|\n"
#define cedit_ascii_5 "| |____     | |___| (_| | | |_ \n"
#define cedit_ascii_6 " \\_____|    |______\\__,_|_|\\__|\n"
#define TAB_SPACES 8

//ABOUT - ASCII ART
#define ABOUT_ASC_0 "______________________________"       
#define ABOUT_ASC_1 "        _   __                "
#define ABOUT_ASC_2 "       /  _|__ _|.___         "
#define ABOUT_ASC_3 "       \\_  |__(_]| |  v0.1   "       
#define ABOUT_ASC_4 "______________________________"       
#define ABOUT_ASC_5 "      Coded   by  V3l0rek     "
#define ANIMATION "||//--\\\\"

#define HELP0 "C-EDIT                                             \0"
#define HELP1 "=======                                            \0"
#define HELP2 "C-EDIT is a terminal TUI curses text editor.       \0"
#define HELP3 "It offers both vertical and horizontal scroll      \0"
#define HELP4 "for file buffer navigation. It also features a     \0"
#define HELP5 "variety of animations and has a built-in open file \0"
#define HELP6 "dialog to easily locate the files in directories.  \0"
#define HELP7 "___________________________________________________\0"
#define HELP8 "[F1] or [ALT + H] -> Display help                  \0"
#define HELP9 "[F2] or [CTRL + L] -> Activate menu                \0"
#define HELP10 "[Arrow Keys] -> Navigate file buffer              \0"
#define HELP11 "[CTRL + A] -> Quick Load  | CTRL + N -> New file  \0"
#define HELP12 "[ALT + O] -> Open file    |                       \0"
#define HELP13 "[ALT + S] -> Save file                             \0"
#define HELP14 "[ESC] or [CTRL + C] or [ALT+X] -> Exit program     \0"
#define HELP15 "[S] Hide/Show table | CTRL or ALT may be used.     \0"
#define HELP16 "___________________________________________________\0"
#define HELP17 "This program was coded in C & Vim from 2018-2024.  \0"
#define HELP18 "Some of the techniques used can be found in my     \0"
#define HELP19 "personal blog : oldstuff286.blogspot.com           \0"
#define HELP20 "Peace!  - by v3l0r3k                               \0"
#define HELPLINES 21

//USER-DEFINED MESSAGES
#define UNKNOWN "UNTITLED"
#define WINDOWMSG "DISPLAY IS TOO SMALL. PLEASE, RESIZE WINDOW"
#define STATUS_BAR_MSG1  " [C-Edit] | F2,CTRL+L: MENU | F1: HELP"
#define STATUS_BAR_MSG2 " [C-Edit] Press ESC to exit menu.             "
#define STATUS_BAR_MSG3 " ENTER: SELECT | <- -> ARROW KEYS             "
#define WLEAVE_MSG "\n       Are you sure\n    you want to quit?"
#define WSAVE_MSG ":\nFile saved successfully!"
#define WSAVELABEL_MSG "[-] File:"
#define WINFO_NOPEN "Error:\nThere isn't any file open!"
#define WINFO_SIZE "-File size: "
#define WINFO_SIZE2 "\n-No. of lines: "
#define WINFO_SIZE3 "\n-File name: "
#define WCHECKFILE2_MSG " File does not exist!  \n\n A new buffer will be created. \n"
#define WCHECKFILE_MSG " This file isn't a|text file. Program may crash.|Open anyway?"
#define WINFONOTYET_MSG "Not implemented yet!"
#define WCHECKLINES_MSG " File longer than 3000 \n lines. You'll view those \n lines as read Mode! "
#define WMODIFIED_MSG "File has been modified|Save current buffer?"
#define WFILEEXISTS_MSG " File exists. \n Overwrite?"
#define WFILEINREADMODE_MSG " File is on read mode. \n"

#define START_CURSOR_X 1
#define START_CURSOR_Y 2

//MENU CONSTANTS
#define HOR_MENU -1
#define FILE_MENU 0
#define OPT_MENU 1
#define HELP_MENU 2
#define YESNO_MENU 3
#define OK_MENU 4
#define MAX_FILENAME 255
#define MAX_LINES 100000
#define MAXLINE 255

//DROP-DOWN MENUS
#define OPTION_1 0
#define OPTION_2 1
#define OPTION_3 2
#define OPTION_4 3
#define OPTION_5 4
#define OPTION_6 5
#define OPTION_NIL -1		//Reset option
#define CONFIRMATION 1
#define K_LEFTMENU -1		//Left arrow key pressed while in menu
#define K_RIGHTMENU -2		//Right arrow key pressed while in menu
#define DONT_UPDATE -5
//MENU CONSTANTS
#define HOR_MENU -1
#define FILE_MENU 0
#define OPT_MENU 1
#define HELP_MENU 2
#define YESNO_MENU 3
#define OK_MENU 4
#define MAXFILENAME 100
#define OK_MENU2 5
#define COLORS_MENU 6

//FILE CONSTANTS
#define FILE_MODIFIED 1
#define FILE_UNMODIFIED 0
#define FILE_READMODE 2
extern char aboutMSG[7][MAXLINE];
extern char help[HELPLINES][MAXLINE];

extern int new_rows, new_columns, old_rows, old_columns;	// Terminal dimensions
extern int cursorX, cursorY; //position on screen X:[0, columns -2] Y:[0, rows-3]
extern int old_cursorX, old_cursorY;
extern long posBufX, posBufY; //position in the edit buffer X:[0,1022] Y:[0,13000]
extern long oldposBufX, oldposBufY; //position in the edit buffer X:[0,1022] Y:[0,13000]
extern long shiftH; //for horizontal scroll
extern int unwantedChars;
int _animation();
int initCEDIT(); 


//TEXT BUFFER POINTERS
extern VLINES *edBuf1; //Buffer vector of lines(1022 chars)
extern VLINES tempLine;

extern FILE *filePointer;
extern int vdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes 
extern int hdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes 
extern int  hdisplayLimit; //horizontal scroll, last char position in line that allows scroll
extern int  currentColumn; //horizontal scroll, pointer to current char position in line
extern long linesinFile; //vertical scroll
extern long vdisplayLimit; //vertical scroll, last line that allows scroll
extern long currentLine; //verticall scroll, pointer to current top line in scroll
extern int vscrollActive; //vertical scroll, vertical scroll is posible
extern int programStatus; //signal for overall program status
extern char fileName[MAXFILENAME]; 
extern char fullPath[MAXFILENAME]; 
extern int fileModified;
extern int deleteKeyPressed;         	    
//extern int hscrollActive; //horizontal scroll, horizontal scroll is posible




#endif


================================================
FILE: src/keyb.c
================================================
/*
======================================================================
Module to control keyboard input.

@author : Velorek
@version : 1.0

LAST MODIFIED : 14/04/2019 Rename headers
======================================================================
*/

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <stdio.h>
#include "rterm.h"
#include "keyb.h"

/*====================================================================*/
/* FUNCTIONS - CODE                                                   */
/*====================================================================*/

/*----------------------------------*/
/* Read ESC-key char with its trail */
/*----------------------------------*/

int read_keytrail(char chartrail[5]){
/*
   New implementation: Trail of chars found in keyboard.c
   If K_ESCAPE is captured read a trail up to 5 characters from the console.
   This is to control the fact that some keys may change
   according to the terminal and expand the editor's possibilities.
   Eg: F2 can be either 27 79 81 or 27 91 91 82.
*/
char ch;
int i;
   chartrail[0] = K_ESCAPE;
   for(i = 1; i < 5; i++) {
     if(kbhit(1) == 1) {
        ch=readch();
        chartrail[i] = ch;
     } else {
        chartrail[i] = 0;
     }
   }
   resetch();
   return 1;
}

/*----------------------------------*/
/* Read Accents and Special Chars   */
/*----------------------------------*/


int read_accent(char *ch, char accentchar[2])
{
/*
Input Ref: ch, accentchar
@return : 1 - SET 1 | 2 - SET 2 | 0 - NO ACCENT CHAR
*/
  int result;
  result = 0;
    //Accents and special chars
   accentchar[0] = 0;
   accentchar[1] = *ch;
    if(*ch == SPECIAL_CHARS_SET1) {
      accentchar[0] = SPECIAL_CHARS_SET1;   //Accents and special chars SET1
      accentchar[1] = readch();
      result = 1;
      resetch();
    }
    if(*ch == SPECIAL_CHARS_SET2) {
      accentchar[0] = SPECIAL_CHARS_SET2;   //Accents and special chars SET2
      accentchar[1] = readch();
      result = 2;
      resetch();
    }
    return result;
}


================================================
FILE: src/keyb.h
================================================
/*
========================================================================
- HEADER -
Module to handle keyboard input in Linux and create
a further layer of abstraction.
@author : Velorek
@version : 1.0
Last modified: 14/04/2019 Rename Headers
========================================================================
*/

#ifndef _KEYB_H_
#define _KEYB_H_

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <stdio.h>
#include "rterm.h"

/*====================================================================*/
/* KEYS - CONSTANTS                                                   */
/*====================================================================*/

#define K_ENTER 13
#define K_CAPS 91
#define K_BACKSPACE 127
#define K_TAB 9
#define K_ESCAPE 27

#define K_F1_TRAIL "\eOP\0\0"
#define K_F1_TRAIL2 "\e[[A\0"
#define K_F2_TRAIL "\eOQ\0\0"
#define K_F2_TRAIL2 "\e[[B\0"
#define K_F3_TRAIL "\eOR\0\0"
#define K_F3_TRAIL2 "\e[[C\0"
#define K_F4_TRAIL "\eOS\0\0"
#define K_F4_TRAIL2 "\e[[D\0"

#define K_UP_TRAIL "\e[A\0\0"
#define K_DOWN_TRAIL "\e[B\0\0"
#define K_RIGHT_TRAIL "\e[C\0\0"
#define K_LEFT_TRAIL "\e[D\0\0"

#define K_PAGEDOWN_TRAIL "\e[6~"
#define K_PAGEUP_TRAIL "\e[5~"
#define K_HOME_TRAIL "\e[H"
#define K_END_TRAIL "\e[F"
#define K_HOME_TRAIL2 "\e[1~"
#define K_END_TRAIL2 "\e[4~"


#define K_DELETE "\e[3~"

#define K_CTRL_A 0x01
#define K_CTRL_B 0x02
#define K_CTRL_C 0x03
#define K_CTRL_D 0x04
#define K_CTRL_E 0x05
#define K_CTRL_J 0x0A
#define K_CTRL_L 0x0C
#define K_CTRL_H 0x08
#define K_CTRL_M 0x0D
#define K_CTRL_N 0x0E
#define K_CTRL_O 0x0F
#define K_CTRL_S 0x14

#define K_ALT_X "\ex"
#define K_ALT_L "\el"
#define K_ALT_S "\es"
#define K_ALT_W "\ew"
#define K_ALT_H "\eh"
#define K_ALT_N "\en"
#define K_ALT_O "\eo"
#define K_ALT_W "\ew"
#define K_ALT_A "\ea"
#define K_ALT_I "\ei"
#define K_ALT_C "\ec"
#define K_ALT_F "\ef"
#define K_ALT_P "\ep"
#define K_ALT_S "\es"
#define K_ALT_V "\ev"
#define K_ALT_D "\ed"
#define ESC3X  "\e\e\e"
#define ESC2X  "\e\e"
#define SPECIAL_CHARS_SET1 -61
#define SPECIAL_CHARS_SET2 -62

/*====================================================================*/
/* FUNCTION PROTOTYPES                                                */
/*====================================================================*/

int     read_keytrail(char chartrail[5]);
int     read_accent(char *ch, char accentchar[2]);

#endif


================================================
FILE: src/listbox.c
================================================
/*====================================================================*/
/* +ListBox with double linked list and selection menu in C with
 * horizontal scroll.
   +Scroll function added. 
   Last modified : 01/04/2024 + Horizontal option implementation started
   			      + ESC_KEY added
			      + X,Y option added for different options
			      - Pending: horizontal scroll
   Coded by Velorek. Raw output
   Target OS: Linux.                                                  */
/*====================================================================*/

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rterm.h"
#include "listbox.h"
#include "keyb.h"
#include "tm.h"
#include "global.h"

/*====================================================================*/
/* CODE */
/*====================================================================*/
int double_escape=0;
int selectorLimit = 15; //by default selectoLimit is 15 when spaces are added
int newrows=0, newcolumns=0;
int listrows=0, listcolumns=0;
char KTRAIL0[5]={0};
char KTRAIL1[5]={0};

/* --------------------- */
/* Dynamic List routines */
/* --------------------- */

// create new list element of type LISTCHOICE from the supplied text string
LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor) {
  LISTCHOICE *newp;
  newp = (LISTCHOICE *) malloc(sizeof(LISTCHOICE));
  newp->item = (char *)malloc(strlen(text) + 1);
  strcpy(newp->item, text);
  newp->next = NULL;
  newp->back = NULL;
  newp->setX = setX;
  newp->setY = setY;
  newp->foreColor = foreColor;
  newp->backColor = backColor;
 
  return newp;
}

// deleleteList: remove list from memory
void removeList(LISTCHOICE ** head) {
  LISTCHOICE *aux = *head;
  LISTCHOICE *next = NULL;
  while(aux != NULL) {
    next = aux->next;
    free(aux->item);
    free(aux);			//remove item
    aux = next;
  }
  *head = NULL;
}

/* addatend: add new LISTCHOICE to the end of a list  */
/* usage example: listBox1 = (addatend(listBox1, newitem("Item")); */
LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp) {
  LISTCHOICE *p2;
  if(head == NULL) {
    newp->index = 0;
    newp->back = NULL;
    return newp;
  }
// now find the end of list
  for(p2 = head; p2->next != NULL; p2 = p2->next) ;
  p2->next = newp;
  newp->back = p2;
  newp->index = newp->back->index + 1;
  return head;
}

/* ---------------- */
/* Listbox routines */
/* ---------------- */

void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,
	       unsigned indexAt)
//Go to a specific location on the list.
{
  LISTCHOICE *aux2;
  unsigned counter = 0;
  *aux = listBox1;
  aux2 = *aux;
  while(counter != indexAt) {
    aux2 = aux2->next;
    counter++;
  }
  //Highlight current item

  displayItem(aux2, scrollData, SELECT_ITEM);

  //Update pointer
  *aux = aux2;
}
void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit) {
/*
Displays the items contained in the list with the properties specified
in scrollData.
*/

  LISTCHOICE *aux;
  unsigned wherey, counter = 0;

  aux = head;
  gotoIndex(&aux, scrollData, 0);
  /* Save values */
  //wherex = scrollData->wherex;
  wherey = scrollData->wherey;
  do {
    displayItem(aux, scrollData, UNSELECT_ITEM);
    aux = aux->next;
    counter++;
    scrollData->selector++;	// wherey++
  } while(counter != displayLimit);
  scrollData->selector = wherey;	//restore value
}


void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned indexAt) {
/*
Displays the items contained in the list with the properties specified
in scrollData.
*/

  LISTCHOICE *aux;
  unsigned wherey, counter = 0;

  aux = head;
  gotoIndex(&aux, scrollData, indexAt);
  /* Save values */
  //wherex = scrollData->wherex;
  wherey = scrollData->wherey;
  do {
    displayItem(aux, scrollData, UNSELECT_ITEM);
    aux = aux->next;
    counter++;
    scrollData->selector++;	// wherey++
  } while(counter != scrollData->displayLimit);
  scrollData->selector = wherey;	//restore value
}

int query_length(LISTCHOICE ** head) {
//Return no. items in a list.
  {
    LISTCHOICE *aux;

    unsigned itemCount = 0;
    aux = *head;
    while(aux->next != NULL) {
      aux = aux->next;
      itemCount++;
    }
    return itemCount;
  }

}

void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select)
//Select or unselect item animation
{
 size_t i=0;
 wchar_t newchar=0;
 resetAnsi(0);
  switch (select) {

    case SELECT_ITEM:
      if ((aux->setX == -1) || (aux->setY== -1 )) 	    
        gotoxy(scrollData->wherex, scrollData->selector);
      else
        gotoxy(aux-> setX, aux -> setY);

      if ((aux->foreColor == -1) || (aux->backColor== -1 )) 	    
        outputcolor(scrollData->foreColor1, scrollData->backColor1);
      else
        outputcolor(aux->foreColor, aux->backColor);

      //printf("%s\n", aux->item);
      
      for (i=0;i<scrollData->selectorLimit;i++) {
              if(i < strlen(aux->item)){
		  newchar=aux->item[i];
	          printf("%lc", newchar);
	      }
	      else
	        if (scrollData->addSpaces != 0) printf("%c", 0x20);
      }
     printf("\n");
     break;

    case UNSELECT_ITEM:
       if ((aux->setX == -1) || (aux->setY== -1 )) 	    
         gotoxy(scrollData->wherex, scrollData->selector);
       else
         gotoxy(aux -> setX, aux -> setY);

       outputcolor(scrollData->foreColor0, scrollData->backColor0);
      //printf("%s\n", aux->item);
      

      for (i=0;i<scrollData->selectorLimit;i++) { 
	      if(i < strlen(aux->item)){
		  newchar = aux->item[i];
	          printf("%lc", newchar);
	      }
	      else
	       if (scrollData->addSpaces != 0) printf("%c", 0x20);

      }
     printf("\n");
      break;
  }
}

int move_selector(LISTCHOICE ** selector, SCROLLDATA * scrollData) {
/* 
Creates animation by moving a selector highlighting next item and
unselecting previous item
*/

  LISTCHOICE *aux;
  unsigned scrollControl = 0, continueScroll = 0, circular =
      CIRCULAR_INACTIVE;

  //Auxiliary pointer points to selector.
  aux = *selector;

  //Circular list animation when not scrolling.
  if(aux->index == scrollData->listLength - 1
     && scrollData->scrollActive == SCROLL_INACTIVE
     && scrollData->scrollDirection == DOWN_SCROLL) {
    //After last item go back to the top.
    displayItem(aux, scrollData, UNSELECT_ITEM);
    scrollData->selector = scrollData->wherey;
    gotoIndex(&aux, scrollData, 0);
    *selector = aux;
    circular = CIRCULAR_ACTIVE;
  }

  if(aux->index == 0 && scrollData->scrollActive == SCROLL_INACTIVE
     && scrollData->scrollDirection == UP_SCROLL) {
    //Before first item go back to the bottom.
    displayItem(aux, scrollData, UNSELECT_ITEM);
    scrollData->selector = scrollData->wherey + scrollData->listLength - 1;
    gotoIndex(&aux, scrollData, scrollData->listLength - 1);
    *selector = aux;
    circular = CIRCULAR_ACTIVE;
  }
  //Check if we do the circular list animation.
  //If active, we skip the code one time.

  if(circular == CIRCULAR_INACTIVE) {

    //Check if we are within boundaries.
    if((aux->next != NULL && scrollData->scrollDirection == DOWN_SCROLL)
       || (aux->back != NULL && scrollData->scrollDirection == UP_SCROLL)) {

      //Unselect previous item
      displayItem(aux, scrollData, UNSELECT_ITEM);

      //Check whether we move UP or Down
      switch (scrollData->scrollDirection) {

	case UP_SCROLL:
	  //Calculate new top index if scroll is active 
	  //otherwise it defaults to 0 (top)
	  if(scrollData->scrollActive == SCROLL_ACTIVE)
	    scrollControl = scrollData->currentListIndex;
	  else
	    scrollControl = 0;

	  //Move selector
	  if(aux->back->index >= scrollControl) {
	    scrollData->selector--;	//whereY--
	    aux = aux->back;	//Go to previous item
	  } else {
	    if(scrollData->scrollActive == SCROLL_ACTIVE)
	      continueScroll = 1;
	    else
	      continueScroll = 0;
	  }
	  break;

	case DOWN_SCROLL:
	  //Calculate bottom index limit if scroll is ACTIVE
	  //Otherwise it defaults to scrollData->ListLength-1

	  if(scrollData->scrollActive == SCROLL_ACTIVE)
	    scrollControl =
		scrollData->currentListIndex + (scrollData->displayLimit -
						1);
	  else
	    scrollControl = scrollData->listLength - 1;

	  //Move selector
	  if(aux->next->index <= scrollControl) {
	    aux = aux->next;	//Go to next item
	    scrollData->selector++;	//whereY++;
	  } else {
	    if(scrollData->scrollActive == SCROLL_ACTIVE)
	      continueScroll = 1;
	    else
	      continueScroll = 0;
	  }
	  break;
      }

    /*  //Metrics
      gotoxy(6, 5);
      printf("Length:%d|Index:%d|Memory addr:%p",
	     scrollData->listLength, aux->index, aux);
      gotoxy(6, 6);
      printf("Scroll Limit: %d|IsScActive?:%d|ContinueScroll: %d",
	     scrollControl, scrollData->scrollActive, continueScroll);
*/
      //Highlight new item
      displayItem(aux, scrollData, SELECT_ITEM);
  //    update_screen(screen1);
      //Update selector pointer
      *selector = aux;
    }
  }
  //update_screen(screen1);
  circular = CIRCULAR_INACTIVE;
  return continueScroll;
}

char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData) {
  char    ch=0;
  int keypressed=0;
  int control = 0;
  int continueScroll=0;
  unsigned counter = 0;
  char chartrail[5];

  //Go to and select expected item at the beginning

  gotoIndex(&aux, scrollData, scrollData->currentListIndex);

  if(scrollData->scrollDirection == DOWN_SCROLL
     && scrollData->currentListIndex != 0) {
    //If we are going down we'll select the last item 
    //to create a better scrolling transition (animation)
    for(counter = 0; counter < scrollData->displayLimit; counter++) {
       scrollData->scrollDirection = DOWN_SCROLL;
        move_selector(&aux, scrollData);
     }
  } else {
    //Do nothing if we are going up. Selector is always at the top item.
  }

  //It break the loop everytime the boundaries are reached.
  //to reload a new list to show the scroll animation.
  while(control != CONTINUE_SCROLL) {
       if (timerC(&timer2) == TRUE){
	      //Animation in global.c
             if (_animation() == -1) {scrollData->itemIndex = -1;double_escape = 1; break;}
        }

    //check listbox orientation and change keys
    if (scrollData->orientation == VERTICAL || scrollData->orientation == VERTICALWITHBREAK){
	strcpy(KTRAIL0, K_UP_TRAIL);
	strcpy(KTRAIL1, K_DOWN_TRAIL);
     }
    else
    {
	strcpy(KTRAIL1, K_RIGHT_TRAIL);
	strcpy(KTRAIL0, K_LEFT_TRAIL);
    }

    keypressed = kbhit(1);
    if (keypressed == 1)
      ch = readch();
    else
      ch = 0;
    //if enter key pressed - break loop
    if(ch == K_ENTER)
      control = CONTINUE_SCROLL;	//Break the loop

     if (ch == 'x' || ch == K_BACKSPACE || ch == K_CTRL_C){
         double_escape=1;
	 scrollData->itemIndex = -1;
	  break;
     }
 

		if (ch == K_ESCAPE)	// escape key
		{
			strcpy(chartrail, "\0");
			read_keytrail(chartrail);
		        //If mode VERTICALWITHBREAK is selected; selector menu is interrupted when left/right arrow keys are pressed
		        if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_LEFT_TRAIL))==0)
			     return K_LEFTMENU;
		        if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_RIGHT_TRAIL))==0)
			     return K_RIGHTMENU;

			if (chartrail[0] == K_ESCAPE && chartrail[1] == 0) {
				double_escape = 1;
				scrollData->itemIndex = -1;
				break;
			}
			if (strcmp(chartrail, K_ALT_X) == 0) {
				break;
			}
			if (strcmp(chartrail, KTRAIL0) == 0) {
				// escape key + A => arrow key up
				//Move selector up
				scrollData->scrollDirection = UP_SCROLL;
				continueScroll =
				    move_selector(&aux, scrollData);
				//Break the loop if we are scrolling
				if (scrollData->scrollActive == SCROLL_ACTIVE
				    && continueScroll == 1) {
					control = CONTINUE_SCROLL;
					//Update data
					scrollData->currentListIndex =
					    scrollData->currentListIndex - 1;
					scrollData->selector =
					    scrollData->wherey;
					scrollData->item = aux->item;
					scrollData->itemIndex = aux->index;
					//Return value
					ch = control;
				}
			}
			// escape key + B => arrow key down
			if (strcmp(chartrail, KTRAIL1) == 0) {
				//Move selector down
				scrollData->scrollDirection = DOWN_SCROLL;
				continueScroll =
				    move_selector(&aux, scrollData);
				//Break the loop if we are scrolling
				if (scrollData->scrollActive == SCROLL_ACTIVE
				    && continueScroll == 1) {
					control = CONTINUE_SCROLL;
					//Update data
					scrollData->currentListIndex =
					    scrollData->currentListIndex + 1;
					scrollData->selector =
					    scrollData->wherey;
					scrollData->item = aux->item;
					scrollData->itemIndex = aux->index;
					scrollData->scrollDirection =
					    DOWN_SCROLL;
				}
				//Return value
				ch = control;
			}
                      
		}
	}

	if (ch == K_ENTER || ch == K_ENTER2)	// enter key
	{
		//Pass data of last item selected
		scrollData->item = aux->item;
		scrollData->itemIndex = aux->index;
	}
	return ch;
}
//method to change how wide the selector is
void setselectorLimit(int num){
   selectorLimit = num;
}
void resetScrollData(SCROLLDATA *scrollData)
{
	scrollData->scrollActive = 0;	//To know whether scroll is active or not.
	scrollData->scrollLimit = 0;	//Last index for scroll.
	scrollData->listLength = 0;	//Total no. of items in the list
	scrollData->currentListIndex = 0;	//Pointer to new sublist of items when scrolling.
	scrollData->displayLimit = 0;	//No. of elements to be displayed.
	scrollData->selectorLimit = selectorLimit;	//No. of chars per item display
	scrollData->scrollDirection = 0;	//To keep track of scrolling Direction.
	scrollData->selector = 0;	//Y++
	scrollData->wherex = 0;
	scrollData->wherey = 0;
	scrollData->backColor0 = 0;	//0 unselected; 1 selected
	scrollData->foreColor0 = 0;
	scrollData->backColor1 = 0;
	scrollData->foreColor1 = 0;
	scrollData->itemIndex = 0;
	scrollData->addSpaces = 0;
	scrollData->orientation = VERTICAL;
}
char listBox(LISTCHOICE * head,
	     unsigned whereX, unsigned whereY,
	     SCROLLDATA * scrollData, unsigned bColor0,
	     unsigned fColor0, unsigned bColor1, unsigned fColor1,
	     unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked) {

  unsigned list_length = 0;
  //unsigned currentIndex = 0;
  int     scrollLimit = 0;
  unsigned currentListIndex = 0;
  char    ch=0;
  LISTCHOICE *aux=NULL;
 //Init values
  double_escape=0;
  resetScrollData(scrollData);
  scrollData->orientation = listorientation;
 // Query size of the list
  list_length = query_length(&head) + 1;

  //Save calculations for SCROLL and store DATA
  scrollData->displayLimit = displayLimit;
  scrollLimit = list_length - scrollData->displayLimit;	//Careful with negative integers
  if(scrollLimit < 0 || displayLimit > list_length)
    scrollData->displayLimit = list_length;	//Failsafe for overboard values

  scrollData->scrollLimit = scrollLimit;
  scrollData->listLength = list_length;
  scrollData->wherex = whereX;
  scrollData->wherey = whereY;
  scrollData->selector = whereY;
  scrollData->backColor0 = bColor0;
  scrollData->backColor1 = bColor1;
  scrollData->foreColor0 = fColor0;
  scrollData->foreColor1 = fColor1;
  scrollData->addSpaces = addSpaces;

  get_terminal_dimensions(&listrows,&listcolumns);
  //Check whether we have to activate scroll or not 
  //and if we are within bounds. [1,list_length)
    ch=0;
    aux = head;
    printlist(aux, scrollData, scrollData->displayLimit);
if (locked == LOCKED) {    
  if(list_length > scrollData->displayLimit && scrollLimit > 0
     && displayLimit > 0) {
    //Scroll is possible  

    scrollData->scrollActive = SCROLL_ACTIVE;

    currentListIndex = 0;	//We listBox1 the scroll at the top index.
    scrollData->currentListIndex = currentListIndex;

    //Scroll loop animation. Finish with ENTER.
    loadlist(aux, scrollData, currentListIndex);
    do {
      currentListIndex = scrollData->currentListIndex;
      loadlist(aux, scrollData, currentListIndex);
      gotoIndex(&aux, scrollData, currentListIndex);
    /*  gotoxy(6, 4);
      printf("Current List Index: %d:%d\n", scrollData->currentListIndex,
	     aux->index); */
        ch = selectorMenu(aux, scrollData);
	if (double_escape == 1) {
	  scrollData->itemIndex = -1;
	  locked = FALSE;
	  ch= K_ESCAPE;
	  break;
	}
	if (_animation() == -1) {
	  scrollData->itemIndex = -1;
	  double_escape = 1;
	  ch = K_ESCAPE;
	  locked = FALSE;
	   break;
	}   
    } while(ch != K_ENTER);

  } else {
    //Scroll is not possible.
    //Display all the elements and create selector
    //
    scrollData->scrollActive = SCROLL_INACTIVE;
    scrollData->currentListIndex = 0;
    scrollData->displayLimit = list_length;	//Default to list_length
    loadlist(head, scrollData, 0);
     ch = selectorMenu(head, scrollData);
	if (double_escape == 1) {
	  scrollData->itemIndex = -1;
	  locked = FALSE;
	  ch= K_ESCAPE;
	  //break;
	}

  }
}
  return ch;
}




================================================
FILE: src/listbox.h
================================================
/*
========================================================================
- HEADER -
Module to implement a listBox integrated with LYNX.
@author : Velorek
@version : 1.0
Last modified: 26/12/2022
========================================================================
*/

#ifndef _LISTBOX_H_
#define _LISTBOX_H_

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <stdio.h>
#include "scbuf.h"
/*====================================================================*/
/* CONSTANTS */
/*====================================================================*/
//Scroll Control values.
#define SCROLL_ACTIVE 1
#define SCROLL_INACTIVE 0
#define CONTINUE_SCROLL -1
#define DOWN_SCROLL 1
#define UP_SCROLL 0
#define SELECT_ITEM 1
#define UNSELECT_ITEM 0
#define CIRCULAR_ACTIVE 1
#define CIRCULAR_INACTIVE 0
#define LOCKED 1
#define NOT_LOCKED 0
#define VERTICAL 0
#define HORIZONTAL 1
#define VERTICALWITHBREAK 2
/*====================================================================*/
/* TYPEDEF STRUCTS DEFINITIONS */
/*====================================================================*/

typedef struct _listchoice {
  unsigned index;		// Item number
  char   *item;			// Item string
  int setX;		//X,Y position
  int setY;		//-1 to ignore
  int foreColor;        //-1 to ignore
  int backColor;        //-1 to ignore
  struct _listchoice *next;	// Pointer to next item
  struct _listchoice *back;	// Pointer to previous item
} LISTCHOICE;

typedef struct _scrolldata {
  unsigned scrollActive;	//To know whether scroll is active or not.
  unsigned scrollLimit;		//Last index for scroll.
  unsigned listLength;		//Total no. of items in the list
  unsigned currentListIndex;	//Pointer to new sublist of items when scrolling.
  unsigned displayLimit;	//No. of elements to be displayed.
  unsigned selectorLimit;       //how many items of string item can be displayed
  unsigned scrollDirection;	//To keep track of scrolling Direction.
  unsigned wherex;
  unsigned wherey;
  unsigned selector;		//Y++
  unsigned backColor0;		//0 unselected; 1 selected
  unsigned foreColor0;
  unsigned backColor1;
  unsigned foreColor1;
  unsigned addSpaces;          //whether to add spaces or not
  unsigned orientation;
  unsigned displayMetrics;     //to show metrics on screen/reuse code for text viewing
  char   *item;
  int      itemIndex;          //-1 means ESC was pressed
  LISTCHOICE *head;		//store head of the list
} SCROLLDATA;

/*====================================================================*/
/* GLOBAL VARIABLES */
/*====================================================================*/
extern LISTCHOICE *listBox1;	//Head pointer.


/*====================================================================*/
/* PROTOTYPES OF FUNCTIONS                                            */
/*====================================================================*/

//DYNAMIC LINKED LIST FUNCTIONS
void    removeList(LISTCHOICE ** head);
LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp);
LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor);

//LISTBOX FUNCTIONS
//void    addItems(LISTCHOICE ** listBox1);
char    listBox(LISTCHOICE * selector, unsigned whereX, unsigned whereY,
		SCROLLDATA * scrollData, unsigned bColor0,
		unsigned fColor0, unsigned bColor1, unsigned fColor1,
		unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked);
void    loadlist(LISTCHOICE * head, SCROLLDATA * scrollData,
		 unsigned indexAt);

void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit);

void    gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,
		  unsigned indexAt);
int     query_length(LISTCHOICE ** head);
int     move_selector(LISTCHOICE ** head, SCROLLDATA * scrollData);
char    selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData);
void    displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select);
void    resetScrollData(SCROLLDATA *scrollData);
void 	setselectorLimit(int num);

/*====================================================================*/
/* FUNCTION PROTOTYPES                                                */
/*====================================================================*/

#endif


================================================
FILE: src/main.c
================================================
/* C-edit project
* Last updated - 29/8/2024
* New drop-down menu implementation
* Added more modularisation: editor.c menu.c
* Scrollbars added
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "listbox.h"
#include "scbuf.h"
#include "rterm.h"
#include "tm.h"
#include "global.h" 
#include "keyb.h"
#include "edbuf.h"
#include "ui.h"
#include "menu.h"
#include "editor.h"
#include "opfile.h"
#include "fileb.h"
//Prototypes
void draw_screen();
void cursor_tick();
int special_keys();
int control_keys(char ch);
void _resizeScreen();
wchar_t currentChar = 0;
char tempMessage[150];
int displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration);
void update_indicators();
int oldPositionY = 4; 
int oldPositionX = 2; 
void draw_screen(){
//BASE SCREEN IS STORED IN SCREEN 2
     int i=0;
     if (screen1 != NULL) deleteList(&screen1);
     //if (screen2 != NULL) deleteList(&screen2);
     //Init 2 : Create 2 Screens for a double buffer  approach  
     old_rows=new_rows;
     old_columns=new_columns;
     create_screen(&screen1);
     create_screen(&screen2);
     //SCREEN 2
     screen_color(screen1, EDITAREACOL, EDIT_FORECOLOR, FILL_CHAR);
    //Failsafe just in case it can't find the terminal dimensions
    if(old_rows == 0)
      old_rows = ROWS_FAILSAFE;
    if(old_columns == 0)
    old_columns = COLUMNS_FAILSAFE;

  //Draw upper and lower bars
    for(i = 0; i < old_columns; i++) {
     write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0);
    }

  for(i = 0; i < old_columns; i++) {
    write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1);
  }
  // Text messages
  write_str(screen1, 0, 1, "File  Options  Help", MENU_PANEL, MENU_FOREGROUND0,0);
  write_str(screen1, 0, 1, "F", MENU_PANEL, F_RED,0);
  write_str(screen1, 7, 1, "p", MENU_PANEL, F_RED,0);
  write_str(screen1, 15, 1, "H", MENU_PANEL, F_RED,0);
  write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0);

  /* Frames */
  //window appearance and scroll bar
  for(i = 2; i < old_rows; i++) {
    write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0);	//Scroll bar
    write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//upper vertical line box-like char 
  }
  for(i = 0; i < old_columns; i++) {
    write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//horizontal line box-like char
    write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0);
  }
  write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//upper-left box-like char
  //horizontal scroll bar
  for(i = 0; i < old_columns; i++) {
    write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0);
  }
  //Window-appearance
  write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);	//right window corner
  write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK,
	   EDITWINDOW_FORE,0);
  write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK,
	   EDITWINDOW_FORE,0);

  //Scroll symbols
  write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
  write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);
  write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0);
  if (strlen(fileName) == 0) strcpy(fileName, "UNTITLED");
  write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName,
        MENU_PANEL, MENU_FOREGROUND0,0); 

  dump_screen(screen1);
  //Save screen for later
  //copy_screen(screen2,screen1);
}

void cursor_tick(void){
//CURSOR ANIMATION
char drawChar=FILL_CHAR;
char drawChar0=FILL_CHAR;
int attrib = 0;
wchar_t code_point;
    //GET CHAR BEING POINTED AT FROM EDIT BUFFER
   if (edBuf1 != NULL)_dumpLine(edBuf1, posBufY, &tempLine);
    drawChar = tempLine.linea[posBufX].ch; 
    drawChar0 = tempLine.linea[posBufX].specialChar; 
    attrib =  tempLine.linea[posBufX].attrib;
    //CHECK FOR SPECIAL CHARACTERS AND CONVERT THEM TO UNICODE TO PRINT
    //IF CURSOR IS ON A CHAR HIGHLIGHT IT IN YELLOW
    if (drawChar0 != 0 && drawChar != '\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F);
    else {
            if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR;
	    code_point = drawChar;
    }
    if (cursor_timer1.ticks % 2 == 0) update_ch(cursorX, cursorY, CURSOR_CHAR, B_BLUE, F_WHITE);
    else update_ch(cursorX, cursorY, code_point, EDITAREACOL, FH_YELLOW);
    
    //REST ANSI VALUES TO HAVE HIGH INTENSITY COLORS
    resetAnsi(0);

    //CLEAR LAST POSITION OF CURSOR WITH FILL_CHAR OR GO BACK TO PREVIOUS CHAR
    if ((old_cursorX != cursorX) || (old_cursorY != cursorY)){
      //old?
      if (edBuf1 != NULL)_dumpLine(edBuf1, oldposBufY, &tempLine);
           drawChar = tempLine.linea[oldposBufX].ch; 
           drawChar0 = tempLine.linea[oldposBufX].specialChar; 
           attrib =  tempLine.linea[oldposBufX].attrib;
    //always clear cursor cell (avoids false misprints)
    update_ch(old_cursorX, old_cursorY, ' ', EDITAREACOL, EDIT_FORECOLOR);

  
    //then try to update to its previous state
    if (drawChar0 != 0 && drawChar != '\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F);
    else {
            if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR;
	    code_point = drawChar;
    }
       update_ch(old_cursorX, old_cursorY, code_point, EDITAREACOL, attrib);
    } 
    if (old_cursorY != cursorY) {
         //Point to line in buffer when Y position changes
        if (edBuf1 != NULL) _dumpLine(edBuf1, posBufY, &tempLine);
    }
    //printf("\n");
    //write_num(screen1, 10,10, cursorX, B_GREEN, F_WHITE,1);
    //write_num(screen1, 10,11, cursorY, B_RED, F_WHITE,1);
    //write_num(screen1, 10,12, old_cursorX, B_GREEN, F_WHITE,1);
    //write_num(screen1, 10,12, old_cursorY, B_GREEN, F_WHITE,1);
    //write_num(screen1, 10,14, posBufX, B_RED, F_WHITE,1);
    //write_num(screen1, 10,15, posBufY, B_RED, F_WHITE,1);
    //write_num(screen1, 10,16, findEndline(tempLine), BH_BLUE, F_WHITE,1);
    //write_num(screen1, 10,17, _length(&edBuf1), B_RED, F_WHITE,1);
    //for (int i=0; i<findEndline(tempLine);i++) write_ch(screen1, 10+i,16, code_point, B_RED, F_WHITE,1);
    //dump_screen(screen1);
   //Buffer pointer position
   /*
     update_str(new_columns - 24, new_rows, "| L:        C:     ", STATUSBAR, STATUSMSG);
    write_num(screen1, new_columns - 10, new_rows, posBufX, STATUSBAR, STATUSMSG,1);
    write_num(screen1, new_columns - 20, new_rows, posBufY+1, STATUSBAR, STATUSMSG,1);
    update_str(new_columns - 39, new_rows, "| LINES:      ", STATUSBAR, STATUSMSG);
    write_num(screen1, new_columns - 31, new_rows, _length(&edBuf1), STATUSBAR, STATUSMSG,1);
*/
    }

void update_indicators() {
/*
   Update cursor position display on screen.
   Values are float to save decimal points.
- Formulas:
   scrollRatio = totalFileLines / displayLength;
   currentPosition = bufferY / scrollRatio;
   percentage = (currentPosition * 100) / displayLength;
   To adjust to the bar dimensions:
   scrollBar = ((displayLength-3) * percentage) / 100;
*/
  char info[255];
  int pep=0;
  float scrollIndicator=1.0, positionY=0.0;
  float hscrollIndicator=1.0, positionX=0.0;
  float percentage=0.0, scrollBar=0.0, scrollRatio =0.0;
  float hpercentage=0.0, hscrollBar=0.0, hscrollRatio =0.0;
  pep = 100;

  //Scroll indicator and percentage display
 if (_length(&edBuf1) > vdisplayArea ) {
     write_ch(screen1,new_columns-1, oldPositionY, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1);	 
     positionY = posBufY;
     scrollRatio = _length(&edBuf1) / vdisplayArea;
     scrollIndicator = positionY / scrollRatio;
     percentage = (scrollIndicator * 100) / vdisplayArea;
     scrollBar = ((vdisplayArea-3) * percentage)/100;
     if (positionY == 1) percentage = 0;
     if (percentage > 100) percentage = 100;
     if (scrollBar+2>=new_rows-5) scrollBar = new_rows - 7;
     write_ch(screen1,new_columns-1, 4+scrollBar, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1);
     oldPositionY = 4+scrollBar;
     pep = percentage;
  }
 if (posBufX>0){
     positionX = posBufX;
     write_ch(screen1, oldPositionX,new_rows-1, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1);
     oldPositionX = 2+hscrollBar;
     hscrollRatio = MAX_LINE_SIZE / hdisplayArea;
     hscrollIndicator = positionX / hscrollRatio;
     hpercentage = (hscrollIndicator * 100) / hdisplayArea;
     hscrollBar = (((hdisplayArea) * hpercentage)/100);
     if (hscrollBar+2>=new_columns-3) hscrollBar = new_columns-5;
     write_ch(screen1, 2+hscrollBar,new_rows-1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1);
     oldPositionX = 2+hscrollBar;
 }
  strcpy(info, "\0");
  sprintf(info, "|LINES: %d| L: %ld C: %ld [%d%c]           ", _length(&edBuf1), posBufY, posBufX,pep,'%');
  update_str(new_columns - 40, new_rows, info, STATUSBAR, STATUSMSG);
}


int main(int argc, char *argv[]) {

char ch=0;
char old_ch=0;
int esc_key = 0;
int keypressed = 0;

    //Init Terminal
    init_term();
    initCEDIT();
    draw_screen();
    resetch();
    strcpy(fileName, "\0");
    //tempLine.linea[0].ch = END_LINE_CHAR;
    //tempLine.linea[posBufX].ch = END_LINE_CHAR;
    //tempLine.linea[posBufX].specialChar = 0;
    //tempLine.linea[posBufX].attrib = EDIT_FORECOLOR;
    if(argc > 1) {
     //Does the file exist? Open or create?
      strcpy(fileName, argv[1]);
      filetoBuffer(fileName);
      flush_editarea(0);
      buffertoScreen(0);
      dump_screen(screen1);
      fileModified= FILE_UNMODIFIED;
    } 
    do{    
	 //end flag from any part of the program
	 if (programStatus == ENDSIGNAL) break;
	 //Time animation & resize window 
	  if (timerC(&timer3) == TRUE){
		   displayMessage(tempMessage,  (new_columns/2)-strlen(tempMessage)/2, 1, FH_WHITE, B_RED, 5);
	  }
	 if (timerC(&timer2) == TRUE){
           _animation();
	    //Refresh screen size buffers if terminal dimension changes
	    if (new_rows != old_rows || new_columns != old_columns)
            {
	      _resizeScreen();
            }
	  }
         //Cursor Animation	 
	 if (timerC(&cursor_timer1) == TRUE){
	      //Animation
             cursor_tick();
	     //if (keypressed == FALSE) { esc_key = 0;}
           }
	//PROCESS INPUT
    	 keypressed = kbhit(1);
          if (keypressed == TRUE) {
	   keypressed = FALSE;
	   //try to catch and avoid printing unwanted chars with cursor keys
	   old_ch = ch;
	   ch=readch();
	   if (old_ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;}
	   if (ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;}
	   if (unwantedChars>0) esc_key = 1;

	   //Keys with a escape sequenece
           if (ch == ESC_KEY) {//buffertoScreen(0, 0,FALSE); 
			       esc_key = special_keys(); 
			       cursor_tick(); 
			       ch = 0;}       
           else {
		//Capture control keys   
		if ((ch>0 && ch< 0x0F) && (ch!=K_ENTER && ch != K_TAB)){buffertoScreen(FALSE); esc_key= control_keys(ch); ch=0;}   
		else 
	         //Process raw edit input from keyboard in editor.c		
		{
		  //try to avoid printing unwanted chars with cursor keys
		  if (ch != 0 && esc_key==0 && unwantedChars == 0&& posBufX <MAX_LINE_SIZE) editor_section(ch);
	        }
	   }
	   update_indicators();
        }else{
	//if not keypressed reset values for unwanted characters
             esc_key=0; unwantedChars = 0;
	}//Check for ESC-related keys
      } while (esc_key != ENDSIGNAL);     
    //restore terminal
     credits();    
     return 0;
}


//CONTROL KEYS
int control_keys(char ch){
  char    returnMenuChar=0;
  int menuCounter = 0;
  int returnValue=0;
  char countCh=0;
  char tempfileName[MAXFILENAME];
    if(ch == K_CTRL_L) {
      //Akin to F2
	handlemenus(&returnMenuChar, &menuCounter,TRUE);
    } 
    if(ch == K_CTRL_C) {
      returnValue  = ENDSIGNAL;
    }
    if (ch == K_CTRL_A) {
      flush_editarea(0);
       buffertoScreen(0);
      countCh=inputWindow("File:", tempfileName,  "Quick load...",28,2,48);
      if (countCh>0) {
	 strcpy(fileName, tempfileName);
	 filetoBuffer(fileName);
         flush_editarea(0);
         buffertoScreen(0);
        dump_screen(screen1);
     }//buffertoScreen(0, 0, 0);
    }

      if (ch == K_CTRL_N){
        if (openFileDialog(fileName,fullPath) == 1){
 	 filetoBuffer(fileName);
         flush_editarea(0);
         buffertoScreen(0);
     }
        dump_screen(screen1);
    
    
    }
	     

 
  return returnValue;
}

//ESCAPE-RELATED KEYS
int special_keys() {
/* MANAGE SPECIAL KEYS */
/*
   New implementation: Trail of chars found in keyboard.c
   If K_ESCAPE is captured read a trail up to 5 characters from the console.
   This is to control the fact that some keys may change
   according to the terminal and expand the editor's possibilities.
   Eg: F2 can be either 27 79 81 or 27 91 91 82.
*/
      //cursorY : position on screen
      //posBufY : position in buffer
 
  int     esc_key = 0;
  char    chartrail[5];
  char    returnMenuChar=0;
  int menuCounter = 0;
  int countCh = 0;
  int ok = -1;
  char tempfileName[MAXFILENAME];
    old_cursorX = cursorX;
    old_cursorY = cursorY;
    oldposBufX = posBufX;
    oldposBufY = posBufY;


    strcpy(chartrail, "\0");
    read_keytrail(chartrail);   //Read trail after ESC key
    //only ESC key detected, finish program
    if (chartrail[0] == ESC_KEY && chartrail[1]==0) {

            buffertoScreen(0);
	    if (fileModified == FILE_MODIFIED) {
		    ok=yesnoWindow(WMODIFIED_MSG, "Alert Window");
	            switch (ok){
		       case 0: //save file and exit
    			    strcpy(chartrail, K_ALT_S);
			    break;
		       case 1: //don't save and exit
	                    return ENDSIGNAL;
			    break;  

		       case 2: //cancel keep running c-edit
			   buffertoScreen(0);
			   break;
	             }
	    } else
            //regular escape with no modifications
	    return ENDSIGNAL;
    }
    
    //Check key trails for special keys starting with ESC.
    //FUNCTION KEYS : F1 - F4
    if(strcmp(chartrail, K_F2_TRAIL) == 0 ||
       strcmp(chartrail, K_F2_TRAIL2) == 0) {
       handlemenus(&returnMenuChar, &menuCounter,TRUE);
    } else if(strcmp(chartrail, K_F3_TRAIL) == 0 ||
          strcmp(chartrail, K_F3_TRAIL2) == 0) {
    } else if(strcmp(chartrail, K_F1_TRAIL) == 0 ||
          strcmp(chartrail, K_F1_TRAIL2) == 0) {
	  flush_editarea(0);
          buffertoScreen(0); 
	    displayHelp();
    } else if(strcmp(chartrail, K_F4_TRAIL) == 0 ||
          strcmp(chartrail, K_F4_TRAIL2) == 0) {

      // ARROW KEYS
    } else if(strcmp(chartrail, K_LEFT_TRAIL) == 0) {
      //Left-arrow key
      unwantedChars++;
      if(cursorX > 1){
        cursorX = cursorX - 1;
        //editScroll.bufferX--;
      }
      if (posBufX>0) posBufX--;
      //adjust shiftH when going back to account for the fact that cursorX=1 is not enough
      if (cursorX == new_columns - 4) shiftH++;
      if (cursorX == 1 && shiftH>0) {shiftH--;buffertoScreen(1);}
    } else if(strcmp(chartrail, K_RIGHT_TRAIL) == 0) {
      //Right-arrow key
      unwantedChars++;
      if(cursorX < new_columns - 3){
        cursorX = cursorX + 1;
        //shiftH = 0;
      } else{
	if (posBufX<MAX_LINE_SIZE) shiftH++;
	buffertoScreen(1);      
      }
      if (posBufX<MAX_LINE_SIZE) posBufX++;

    } else if(strcmp(chartrail, K_UP_TRAIL) == 0) {
      //Up-arrow key
      unwantedChars++;
      if(cursorY > 2) {
       cursorY = cursorY - 1;
        
      }else{
	      //scrolling up
	        if (currentLine>0) {
			currentLine--;
	               buffertoScreen(1);
		}
      }
      if (posBufY > 0) posBufY--;
 
    } else if(strcmp(chartrail, K_DOWN_TRAIL) == 0) {
      //Down-arrow key
     //Check if there are more lines to go to
      unwantedChars++;
      if (posBufY<_length(&edBuf1)-1){
        if(cursorY < new_rows - 3) {
          //stay put if we are are the end of the viewing area
          cursorY = cursorY + 1;
        }
	else{  
                //scrolling down
	        if (_length(&edBuf1) > vdisplayArea ) {
		  currentLine++;
	          buffertoScreen(1);
		}
	}  
        posBufY++;
      }
    } else if(strcmp(chartrail, K_PAGEDOWN_TRAIL) == 0) {
      //Page Down key
          vdisplayLimit = _length(&edBuf1) - vdisplayArea;
	  if (_length(&edBuf1) > vdisplayArea ) {
		if (currentLine + vdisplayArea <= vdisplayLimit )
                            currentLine =  currentLine + vdisplayArea;
                else
                            currentLine = vdisplayLimit;  // stop at the limit of our scroll
               posBufY = currentLine;
               cursorY = START_CURSOR_Y;
	       buffertoScreen(1);
	  }
     } else if(strcmp(chartrail, K_PAGEUP_TRAIL) == 0) {
      //Page Down key
	  if (_length(&edBuf1) > vdisplayArea ) {
                          if (currentLine  >= vdisplayArea)
                              currentLine = currentLine - vdisplayArea;
                          else
                             currentLine = 0;  // stop at the top			  
            posBufY = currentLine;
            cursorY = START_CURSOR_Y;
	    buffertoScreen(1);
	  }
     }else if(strcmp(chartrail, K_HOME_TRAIL) == 0 || strcmp(chartrail, K_HOME_TRAIL2) == 0 ) {
	  if (_length(&edBuf1) > vdisplayArea ) {
	    currentLine=0;
            cursorY = START_CURSOR_Y;
	    posBufY=0;
	    buffertoScreen(1);
	  }  
     }else if(strcmp(chartrail, K_END_TRAIL) == 0 || strcmp(chartrail, K_END_TRAIL2) == 0 ) {	      
	  if (_length(&edBuf1) > vdisplayArea ) {
	    currentLine=_length(&edBuf1)-vdisplayArea;
            cursorY = new_rows-3;
	    posBufY=_length(&edBuf1)-1;  
	    buffertoScreen(1);  
	  }
    } else if(strcmp(chartrail, K_DELETE) == 0) {
       deleteKeyPressed = 1;         	    
       editor_section(0);
      //delete button;
    } else if(strcmp(chartrail, K_ALT_F) == 0) {
      returnMenuChar=FILE_MENU;
      menuCounter=FILE_MENU;
      handlemenus(&returnMenuChar, &menuCounter,FALSE);
    } else if(strcmp(chartrail, K_ALT_P) == 0) {
      returnMenuChar=OPT_MENU;
      menuCounter=OPT_MENU;
      handlemenus(&returnMenuChar, &menuCounter,FALSE);
    } else if(strcmp(chartrail, K_ALT_H) == 0) {
      returnMenuChar=HELP_MENU;
      menuCounter=HELP_MENU;
      handlemenus(&returnMenuChar, &menuCounter,FALSE);
    } else if(strcmp(chartrail, K_ALT_O) == 0) {
      //openFileHandler();    //Open file Dialog
       buffertoScreen(0);
       dump_screen(screen1);
       if (openFileDialog(fileName,fullPath) == 1){
	       //is it a binary file?
	    filetoBuffer(fileName);
            flush_editarea(0);
            buffertoScreen(0);
	 }
        dump_screen(screen1);
    } else if(strcmp(chartrail, K_ALT_N) == 0) {
      //newDialog(currentFile);   // New file
      //refresh_screen(-1);
      resetch();
    } else if(strcmp(chartrail, K_ALT_A) == 0) {
      //saveasDialog(currentFile);    //Save as.. file
      //refresh_screen(-1);
    } else if(strcmp(chartrail, K_ALT_S) == 0) {
      //Save file
      flush_editarea(0);
      buffertoScreen(0);
      strcpy(tempMessage, "[File saved!]\0");
    	   if (strcmp(fileName, "UNTITLED") == 0) {
        countCh=inputWindow("File:", tempfileName,  "Save file as...",28,2,48);
        if (countCh>0) {
	   strcpy(fileName, tempfileName);
	   buffertoFile(fileName);
	   flush_editarea(0);
	   buffertoScreen(0);
           dump_screen(screen1);
           timer3.ticks=0; 
	}	
       } else{
	   buffertoFile(fileName);
	   flush_editarea(0);
	   buffertoScreen(0);
           dump_screen(screen1);
           timer3.ticks=0; 
       }
	   //a bit convoluted but it works / exit if user selcts yes after saving
        if (ok==0){printf("File saved!. Exiting...\n"); return ENDSIGNAL; }
    } else if(strcmp(chartrail, K_ALT_W) == 0) {
      //if(strcmp(currentFile, UNKNOWN) == 0)
    //saveasDialog(currentFile);  //Write to file
      //else {
    //saveDialog(currentFile);
      //}
      //refresh_screen(-1);
    } else if(strcmp(chartrail, K_ALT_X) == 0) {
    /*  
    if(fileModified == 1)
      exitp = confirmation(); //Shall we exit? Global variable!
      else
    exitp = EXIT_FLAG;
    } } 
    */
    }
    esc_key = 1;
  return esc_key;

}

/*
void linetoScreen(long whereY, VLINES tempLine, BOOL clean){
//dump temporary Line to screen buffer
   int i,j=0;
   for (i=0; i<findEndline(tempLine); i++){
   	if(tempLine.linea[i].specialChar != 0) {
	  //Special char ? print the two values to screen buffer.
	  write_ch(i+START_CURSOR_X, whereY,  tempLine.linea[i].specialChar, EDITAREACOL,
		   EDIT_FORECOLOR);
	  write_ch(i+START_CURSOR_X, whereY,  tempLine.linea[i].ch, EDITAREACOL,   EDIT_FORECOLOR);
	} else {
	  write_ch(i+START_CURSOR_X, whereY, tempLine.linea[i].ch, EDITAREACOL,
		   EDIT_FORECOLOR);
	}
	if (clean == TRUE) 
	  for (j=findEndline(tempLine); j<columns -2; j++)
		write_ch(j+START_CURSOR_X, whereY, FILL_CHAR, EDITAREACOL, EDIT_FORECOLOR); 	  
	}
	write_ch(findEndline(tempLine)+START_CURSOR_X, whereY, '|', B_GREEN,
		   F_WHITE);
}	
*/

/*---------*/
/* Credits */
/*---------*/

void credits() {
  //Frees memory and displays goodbye message 
  //Free selected path item/path from opfiledialog 
  size_t i; //to be compatible with strlen
  char auth[27] ="Coded by v3l0r3k 2018-2025";
  //int wherex=0,wherey=0;  

  close_term();			//restore terminal settings from failsafe
  gotoxy(1,1);
  printf(cedit_ascii_1);
  gotoxy(1,2);
  printf(cedit_ascii_2);
  gotoxy(1,3);
  printf(cedit_ascii_3);
  gotoxy(1,4);
  printf(cedit_ascii_4);
  gotoxy(1,5);
  printf(cedit_ascii_5);
  gotoxy(1,6);
  printf(cedit_ascii_6);
  gotoxy(1,7);
  outputcolor(0, 90);
  printf("\n%s",auth);
  outputcolor(0, 37);
  timer2.ms=10;
  timer2.ticks=0;
  i=0;

  outputcolor(0, 97);
  do{
    if (timerC(&timer2) == 1) { 
       gotoxy(i,8);
       if (i==strlen(auth)) outputcolor(0,93);
       if (i<10 || i>16) 
	if (i<=strlen(auth)) printf("%c", auth[i-1]);
       printf("\n");
       i++;
     }
    } while (timer2.ticks <30);
//log
// _printlist(&edBuf1);
//  printf("%ld:%ld\n", posBufX, posBufY);
//  printf("\n%ld\n",sizeof(&edBuf1));
 
  if (screen1 != NULL) deleteList(&screen1);
  if (screen2 != NULL) deleteList(&screen2);
  if (listBox1 != NULL) removeList(&listBox1);
 
  _deletetheList(&edBuf1); //free edit Buffer
  resetAnsi(0);
  showcursor();
  resetAnsi(0); 
}

void _resizeScreen(){
//redraw everything when screen size changes
	get_terminal_dimensions(&new_rows, &new_columns);
	if (screen1 != NULL) deleteList(&screen1);
	if (screen2 != NULL) deleteList(&screen2);
	create_screen(&screen1);
	create_screen(&screen1);
	draw_screen();
	flush_editarea(0);
	hdisplayArea = new_columns - 2;	
	vdisplayArea = new_rows - 4;
	//if screen resizes file pointers are rewound to the beginning
        currentLine = 0;
	posBufX = 0;
	posBufY = 0;
	shiftH = 0;
	buffertoScreen(0);
        dump_screen(screen1);
	cursorX = START_CURSOR_X;
	cursorY = START_CURSOR_Y;
}

int displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration){
//display a temporary nessage controlled by Timer3
   if (timer3.ticks == -1) {
           write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1);
	   return 0;
   }
  if (timer3.ticks  >= timeDuration) {
	  stop_timer(&timer3); 
          write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1);
	  return 0;
  } 
   write_str(screen1, x,y, temporaryMessage, bColor, fColor,1);
   return 1;
}




================================================
FILE: src/menu.c
================================================
/* Module to display Menus on C·edit 
 * for a Text User Interface
 * TextBox
 * Window
 * Last modified: 6/4/2024
 * @author:velorek
 */
#include <stdio.h>
#include "rterm.h"
#include "scbuf.h"
#include "ui.h"
#include "menu.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
#include "editor.h"
#include "opfile.h"
#include "fileb.h"
/*--------------------------------------------*/
/* Load current menu into circular linked list*/
/*--------------------------------------------*/

void loadmenus(int choice) {

  if(choice == HOR_MENU) {
 	if (listBox1 != NULL) removeList(&listBox1);
	listBox1 = addatend(listBox1, newitem("File", 0, 1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Options", 7, 1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Help", 16, 1,-1,-1));
    }
  

  if(choice == FILE_MENU) {
 	if (listBox1 != NULL) removeList(&listBox1);
	listBox1 = addatend(listBox1, newitem("New", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Open", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Quick load", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Save", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Save as...", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Exit", -1, -1,-1,-1));
 }
  if(choice == OPT_MENU) {
 	if (listBox1 != NULL) removeList(&listBox1);
	listBox1 = addatend(listBox1, newitem("File Info", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Find...", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("Colors", -1, -1,-1,-1));	
  }
  if(choice == HELP_MENU) {
 	if (listBox1 != NULL) removeList(&listBox1);
	listBox1 = addatend(listBox1, newitem("Help...", -1, -1,-1,-1));
	listBox1 = addatend(listBox1, newitem("About", -1, -1,-1,-1));	
 }
/*
  if(choice == YESNO_MENU) {
    add_item(mylist, "[YES]", (columns / 2) - 11, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
    add_item(mylist, "[NO]", (columns / 2) - 3, (rows / 2) + 2,  MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
    add_item(mylist, "[CANCEL]", (columns / 2) + 4, (rows / 2) + 2,  MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
  }
  if(choice == OK_MENU) {
    add_item(mylist, "[OK]", (columns / 2) - 1, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
  }
  if(choice == OK_MENU2) {
    add_item(mylist, "[OK]", (columns / 2) - 1, (rows / 2) + 3, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
  }
  if(choice == COLORS_MENU) {
    add_item(mylist, "C-Edit Theme", (columns / 2) - 6, (rows / 2) - 2, 
        MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
    add_item(mylist, "Classic Theme", (columns / 2) - 6, (rows / 2) -1, 
        MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
    add_item(mylist, "Dark Theme", (columns / 2) - 6, (rows / 2), 
        MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);
  }
*/
}

/*---------------
 Menu loop
It depends on two values passed by reference stored in the function from where this routine is called:
-returnMenuChar
-menuCounter
It does some tricky modulo operation to cycle back
*/
void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu)
{      

      setselectorLimit(15);
      copy_screen(screen2,screen1);
      if (horizontalMenu) *returnMenuChar= horizontal_menu();  
      do{
      switch (*returnMenuChar) {
	case 0: *menuCounter=FILE_MENU; *returnMenuChar=filemenu();  if (*returnMenuChar != DONT_UPDATE) xor_update(screen2,screen1); break;
     	case 1: *menuCounter=OPT_MENU; *returnMenuChar=optionsmenu();  xor_update(screen2,screen1); break;
	case 2: *menuCounter=HELP_MENU; *returnMenuChar=helpmenu(); xor_update(screen2,screen1);  break;
	default:
		break;
      } 
      //convert -2 from right cursor to 1 to advance     
      if (*returnMenuChar == -2 ) *returnMenuChar = 1; 
      *menuCounter=*menuCounter + *returnMenuChar;  
      if (*returnMenuChar == K_ENTER) break;
      if (*returnMenuChar == DONT_UPDATE) break;
      if (*returnMenuChar != ESC_KEY ) {
     			copy_screen(screen1,screen2);
	      		//euclidian modulo, we circle back through the different switch cases
	                *returnMenuChar = ((*menuCounter % 3) + 3) % 3; 
	 }

     } while (*returnMenuChar != ESC_KEY);
     //xor_update(screen2,screen1);
    if (*returnMenuChar != DONT_UPDATE){
      copy_screen(screen1,screen2);
      dump_screen(screen1);
   }
}
//Entry menu- horizontal
char horizontal_menu() {
char ch=0;

         dump_screen(screen1);
         //Save current screen to screen2
         loadmenus(HOR_MENU);	
	//load menus from ui.c onto lisBox in (global.c)
	//dump_screen(screen1);
        ch = listBox(listBox1, 0, 1 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  3, HORIZONTAL,0,1); 
        //delete listbox
	if(ch == ESC_KEY) scrollData.itemIndex = ch;; //to avoid warning
	removeList(&listBox1);
        //return option passed in scrollData (global.c)
	return scrollData.itemIndex;
}
/*-------------------------*/
/* Display File menu       */
/*-------------------------*/

char filemenu() {  
  char ch=0;
  int countCh = 0;
  char tempfileName[MAXFILENAME];
  int ok2 = -1;
  int retvalue = 0;
  write_str(screen1,0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);
  write_str(screen1,0, 1, "File", MENU_SELECTOR, MENU_FOREGROUND1,1);
  loadmenus(FILE_MENU);
  draw_window(screen1,0, 2, 13, 9, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1);
  ch = listBox(listBox1, 3, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  -1, VERTICALWITHBREAK,0,1); 
    // copy_screen(screen1,screen2);
    // dump_screen(screen1);
      
  //return if right and left arrow keys are pressed
  if (ch == K_RIGHTMENU || ch == K_LEFTMENU) return ch;

  if(scrollData.itemIndex == OPTION_1) {
    flush_editarea(0);
      buffertoScreen(0);
      countCh=inputWindow("File:", tempfileName,  "[+] New file",26,2,44);
      if (countCh>0) {
	 strcpy(fileName, tempfileName);
	 filetoBuffer(fileName);
         flush_editarea(0);
         buffertoScreen(0);
        dump_screen(screen1);
     }//buffertoScreen(0, 0, 0);
      ch=0;
     return DONT_UPDATE;
  }
  
  if(scrollData.itemIndex == OPTION_2) {
     //openFile Dialog in opfile.c
    flush_editarea(0);
    buffertoScreen(0);
     if (openFileDialog(fileName,fullPath) == 1){
 	 filetoBuffer(fileName);
         flush_editarea(0);
         buffertoScreen(0);
     }

        dump_screen(screen1);  
     return DONT_UPDATE;
  }
  if(scrollData.itemIndex == OPTION_3) {
    //External Module - Open file dialog.
    //openFileHandler();
      
      flush_editarea(0);
      buffertoScreen(0);
      countCh=inputWindow("File:", tempfileName,  "Quick load...",26,2,44);
      if (countCh>0) {
		//check if it's a binary file
	    if (openandcheckFile(tempfileName) == 1){
               ok2 = yesnoWindow(WCHECKFILE_MSG, "Alert window");
	       switch (ok2){
	        case 0: // open binary file anyway
		   retvalue=1;
	    	   break;            
	        case 1: //don't open binary file
	 	  strcpy (fileName,"\0");
	 	  strcpy (fullPath,"\0");
		  retvalue=0;
	 	  break;
	    	case 2: //cancel is the same as no here
		  strcpy (fileName,"\0");
	 	  strcpy (fullPath,"\0");
		  retvalue=0;
		break;
	     } 
	     }else{
		   retvalue = 1;
	     }
         if (retvalue==1){
     	   strcpy(fileName, tempfileName);
	   filetoBuffer(fileName);
           flush_editarea(0);
           buffertoScreen(0);
           dump_screen(screen1);
	 }
     }//buffertoScreen(0, 0, 0);
     return DONT_UPDATE;

  }
  if(scrollData.itemIndex == OPTION_4) {
       //Save file
       flush_editarea(0);
      buffertoScreen(0);
    	
	if (strcmp(fileName, "UNTITLED") == 0) {
        countCh=inputWindow("File:", tempfileName,  "Save file as...",26,2,44);
        if (countCh>0) {
	     	
	     strcpy(fileName, tempfileName);
	     buffertoFile(fileName);
	     flush_editarea(0);
	     buffertoScreen(0);
            dump_screen(screen1);
	}	
       } else{
	   buffertoFile(fileName);
	   flush_editarea(0);
	   buffertoScreen(0);
          dump_screen(screen1);
       }


     return DONT_UPDATE;
  }
  if(scrollData.itemIndex == OPTION_5) {
    //Save as option
       flush_editarea(0);
      buffertoScreen(0);
  
    countCh=inputWindow("File:", fileName,  "Save file as...",26,2,44);
    if (countCh>0) {
      buffertoFile(fileName);
      flush_editarea(0);
      buffertoScreen(0);
      dump_screen(screen1);
    }
    return DONT_UPDATE;
  }

  if(scrollData.itemIndex == OPTION_6) {
    //Exit option
    //if(fileModified == 1)
      //exitp = confirmation();	//Shall we exit? Global variable!
    //else
      programStatus  = ENDSIGNAL;
  }
 //restore previous screen
 //dump_screen(screen1);
	
return ch;
}

/*--------------------------*/
/* Display Options menu     */
/*--------------------------*/

char optionsmenu() {
  //int  setColor;
  char ch=0;

  write_str(screen1,6, 1, "Options", MENU_SELECTOR, MENU_FOREGROUND1,1);
  write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);
  loadmenus(OPT_MENU);
  draw_window(screen1,6, 2, 19, 6, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1);
  ch = listBox(listBox1, 9, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  -1, VERTICALWITHBREAK,0,1); 
  if(scrollData.itemIndex == OPTION_1) {
    //File Info
    //fileInfoDialog();
  }
  if(scrollData.itemIndex == OPTION_3) {
    //Set Colors
  /*  setColor = colorsWindow(mylist,COLORSWTITLE);
    setColorScheme(setColor);
    checkConfigFile(setColor);	//save new configuration in config file
    *///refresh_screen(1);
  }
return ch;

}

/*--------------------------*/
/* Display Help menu        */
/*--------------------------*/

char helpmenu() { 
  char ch= 0;

  write_str(screen1,15, 1, "Help", MENU_SELECTOR, MENU_FOREGROUND1,1);
  write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);
  loadmenus(HELP_MENU);
  draw_window(screen1,15, 2, 25, 5, MENU_PANEL, MENU_FOREGROUND0, 0,1,0,1,1);
  ch = listBox(listBox1, 18, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  -1, VERTICALWITHBREAK,0,1); 
  if(scrollData.itemIndex == OPTION_1 && ch>0) {
    //Help dialog
    //help_info();
    flush_editarea(0);
    buffertoScreen(0); 
     displayHelp();
  }
  if(scrollData.itemIndex == OPTION_2 && ch>0) {
    //About info
    flush_editarea(0);
    buffertoScreen(0);
  
   displayAbout();
  }
  return ch;
}

//ABOUT

int displayAbout(void)
{
	char ch = 0;
	int i = 0;
	int colAnimation = F_BLACK;
	int keypressed = 0;
        int colCounter = 0;
	copy_screen(screen2, screen1);

	window(screen1, (new_columns / 2) - 18, (new_rows / 2) - 6,
	       (new_columns / 2) + 17, (new_rows) / 2 + 3, B_WHITE, F_BLACK,
	       B_BLACK, 1, 1, 1);
	
	for (i = 0; i < 6; i++) {
		write_str(screen1, (new_columns / 2) - 15,
			  (new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE,
			  F_BLACK, 0);
	}
	
	write_str(screen1, (new_columns / 2) - 11, (new_rows / 2) - 7,
		 "[+] ABOUT INFORMATION", B_BLACK, FH_WHITE, 1);
		 
//	write_str(screen1, (new_columns / 2) - 25, (new_rows / 2) + 2,
		  //aboutMSG[3], B_YELLOW, F_BLACK, 0);
	write_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 2, "[OK]",
		  B_RED, FH_WHITE, 1);
	
	dump_screen(screen1);
	
	if (kbhit(100) == 1)
		ch = readch();
	ch = 0;
	i = 0;
	colCounter = 0;
	//pulsating animation
	do {
		keypressed = kbhit(30);
		if (timerC(&timer2) == TRUE) {
			//About animation            
			write_str(screen1, (new_columns / 2) - 15,
				  (new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE,
				  colAnimation, 1);
			i++;
			if (i == 6) {
				i = 0;
				switch (colCounter){
				case 1:
					colAnimation = FH_BLACK;
					break;
				case 2: 
					colAnimation = FH_BLACK;
					break;
				case 3: 
					colAnimation = FH_BLACK;
					break;
				case 4: 
					colAnimation = FH_BLACK;
					break;
				case 5: 
					colAnimation = FH_BLACK;
					break;
				case 6: 
					colAnimation = FH_WHITE;
					break;
				case 7: 
					colAnimation = FH_WHITE;
					break;
				case 8: 
					colAnimation = FH_WHITE;
					break;
				case 9: 
					colAnimation = F_BLACK;
					break;
				case 10: 
					colAnimation = F_BLACK;
					break;
					

				}
				colCounter++;
				if (colCounter ==11) colCounter = 0;
			}
			//if terminal resizes
			if (_animation() == -1)
				break;
		}
		//Process keys
		if (keypressed == 1) {
			ch = readch();
			keypressed = 0;

			//Read special keys
			if (ch == K_ESCAPE) {
				ch = readch();
				if (ch == ESC_KEY)
				  break;
			}

		}
	} while (ch != K_ENTER);
        resetch();
	copy_screen(screen1, screen2);
	if (listBox1 != NULL)
		removeList(&listBox1);
	dump_screen(screen1);
	return ch;
}
void addItemsHelp(LISTCHOICE **listBox1, char textarray[][MAXLINE], int rows)
{
	int h=0;
//Load items into the list.  
	//if (*listBox1 != NULL) removeList(listBox1);
	for (h = 0; h < rows-1; h++) {
		//*ch = textarray[h];
		*listBox1 = addatend(*listBox1, newitem(textarray[h],-1,-1,-1,-1));
	}
		*listBox1 = addatend(*listBox1, newitem(textarray[rows-1],-1,-1,B_WHITE,FH_BLUE));
}
int displayHelp(void)
{
	char ch = 0;
	resetScrollData(&scrollData);
	if (listBox1 != NULL)
		removeList(&listBox1);
	
	setselectorLimit(26*2-1);
	//scrollData.selectorLimit = (26 * 2) - 1;	//No. of chars per item display
	//scrollData.selectorLimit = 100;	//No. of chars per item display
 //create_screen(&screen2);
	copy_screen(screen2, screen1);
	window(screen1, (new_columns / 2) - 26, (new_rows / 2) - 8,
		    (new_columns / 2) + 26, (new_rows) / 2 + 8, B_WHITE, F_BLACK,
		    B_BLACK, 1, 1, 1);
	write_str(screen1, (new_columns / 2) - 12, (new_rows / 2) - 9,
		 "[+] MAIN HELP INFORMATION", B_BLACK, FH_WHITE, 1);
	
	write_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 7, "[OK]",
		  B_RED, F_WHITE, 1);
	dump_screen(screen1);
	addItemsHelp(&listBox1, help, HELPLINES);
	if (listBox1 != NULL)
		ch = listBox(listBox1, (new_columns / 2) - 24,
			     (new_rows / 2) - 7, &scrollData, B_WHITE, F_BLACK,
			     B_WHITE, FH_WHITE, 14, VERTICAL,1,LOCKED);
	copy_screen(screen1, screen2);
//	if (screen2 != NULL)
//		deleteList(&screen2);
	if (listBox1 != NULL)
		removeList(&listBox1);
	dump_screen(screen1);
	return ch;
}



================================================
FILE: src/menu.h
================================================
/*
========================================================================
- HEADER -
Module with all menus on C·EDIT
@author : Velorek
@version : 1.0
Last modified: 06/04/2024
========================================================================
*/

#ifndef _MENU_H_
#define _MENU_H_

#include "scbuf.h"
#include <stdio.h>

void loadmenus(int choice);
char horizontal_menu();
char filemenu();
char optionsmenu();
char helpmenu();
void credits();
void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu);
int displayAbout();
int displayHelp(void);

#endif




================================================
FILE: src/opfile.c
================================================
/*====================================================================*/
/* OPEN FILE MODULE
   +ListFiles with double linked list and selection menu in C.
   +Scroll function added.
   +Integrated with C-EDIT
   A window is drawn to the buffer and all of the scroll animations
   are drawn to the terminal on raw mode to have a better scrolling
   animation. Once the file is selected, the window is closed and the
   previous screen is painted to the terminal again.
   Last modified : 11/1/2019 - Switch to readch() instead of getch()
                   06/04/2019 - Corrected all memory leaks
		   14/04/2019 - Rename headers
		   22/04/2020 - Added Set File to Open
		   23/04/2023 - Merged with Lynx and vastly simplified
   Coded by Velorek.
   Target OS: Linux.                                                  */
/*====================================================================*/

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include "rterm.h"
#include "scbuf.h"
#include "listbox.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
#include "opfile.h"
#include "ui.h"
#include "fileb.h"
/*====================================================================*/
/* GLOBAL VARIABLES */
/*====================================================================*/

int     window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;
int ndirs=0, nfiles=0;

/*====================================================================*/
/* CODE */
/*====================================================================*/

int listFiles(LISTCHOICE ** listBox1, char *directory) {
  DIR    *d;
  struct dirent *dir;
  int     i;
  char    temp[MAX_ITEM_LENGTH];
  int     lenDir;       //length of directory
  ndirs=0;
  nfiles=0;
  if (*listBox1 != NULL) removeList(listBox1);
  *listBox1 = addatend(*listBox1, newitem("[..]",-1,-1,FH_BLUE,B_WHITE));    // ".."

  //Start at current directory
  d = opendir(directory);
  //Find directories and add them to list first
  if(d) {
    while((dir = readdir(d)) != NULL) {
      if(dir->d_type == DT_DIR) {

    lenDir = strlen(dir->d_name);

    //Check length of directory
    //Directories are displayed between brackets [directory]
    if(lenDir > MAX_ITEM_LENGTH - 2) {
      //Directory name is long. CROP
      memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line
      strcpy(temp,"\0");
      strcpy(temp, "[");
      for(i = 1; i < MAX_ITEM_LENGTH - 1; i++) {
        temp[i] = dir->d_name[i - 1];
      }
      temp[MAX_ITEM_LENGTH - 1] = ']';
    } else {
      //Directory's name is shorter than display
      //Add spaces to item string.
      memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line
      strcpy(temp,"\0");
      strcpy(temp, "[");
      for(i = 1; i < lenDir + 1; i++) {
        temp[i] = dir->d_name[i - 1];
      }
      temp[lenDir + 1] = ']';
    }
    //Add all directories except CURRENTDIR and CHANGEDIR
    if(strcmp(dir->d_name, ".") != 0
       && strcmp(dir->d_name, "..") != 0)
    { ndirs++;
      *listBox1 =
          addatend(*listBox1, newitem(temp, -1,-1,FH_BLUE,B_WHITE));}
      }
    }
  }
  closedir(d);

  //Find files and add them to list after directories
  d = opendir(directory);
  if(d) {
    while((dir = readdir(d)) != NULL) {
      if(dir->d_type == DT_REG) {
    //only list valid fiels
    if(strlen(dir->d_name) > MAX_ITEM_LENGTH) {
      for(i = 0; i < MAX_ITEM_LENGTH; i++) {
        temp[i] = dir->d_name[i];
      }
    } else {
      memset(&temp, '\0',sizeof(temp)); //Clear memory for temporary line
      strcpy(temp,"\0");
      strcpy(temp, dir->d_name);
    }
    nfiles++;
    *listBox1 =
        addatend(*listBox1, newitem(temp, -1,-1,-1,-1));
      }
    }
    closedir(d);
  }
  
  return 0;
}

void addItems(LISTCHOICE **listBox1)
{
	int h=0;
//Load items into the list.  
        //if (listBox1 != NULL) removeList(listBox1);
	for (h = 0; h <10; h++) {
		//*ch = textarray[h];
		*listBox1 = addatend(*listBox1, newitem("Test",-1,-1,-1,-1));
	}
}

int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]){
char ch=0;
char path[MAXFILENAME];
char bit[MAXFILENAME];
char ndirstr[100];
size_t i=0;
int ok2 =0;
int retvalue=0;
char nfilestr[100];
char currentPath[4] = "./\0";
    retvalue =0;
    setselectorLimit(23);
    window_y1 = (new_rows / 2) - 10;
    window_y2 = (new_rows / 2) + 10;
    window_x1 = (new_columns / 2) - 13;
    window_x2 = (new_columns / 2) + 13;   
   copy_screen(screen2,screen1);
   old_rows = new_rows;
   old_columns = new_columns; 
   do{
     draw_window(screen1,window_x1, window_y1, window_x2, window_y2,B_WHITE,F_BLACK,B_BLACK,1,1,1,0);
     draw_window(screen1,window_x1, window_y2-3, window_x2, window_y2,B_CYAN,F_WHITE,B_BLACK,1,0,0,0);
     dump_screen(screen1);
      listFiles(&listBox1,currentPath);
      sprintf(ndirstr, "[%d] Directories", ndirs);
      sprintf(nfilestr, "[%d] Files", nfiles);
      write_str(screen1,window_x1+2,window_y2-2,ndirstr,B_CYAN,FH_WHITE,1);
      write_str(screen1,window_x1+2,window_y2-1,nfilestr,B_CYAN,F_WHITE,1);
      write_str(screen1,window_x1+1,window_y2-4, "   PRESS [ESC] TO EXIT   ",B_BLACK,FH_WHITE,1);
      write_str(screen1,window_x1+2,window_y1,"Select file...",B_BLACK,FH_WHITE,1);
      ch = listBox(listBox1, window_x1+3,window_y1+1, &scrollData, B_WHITE, F_BLACK,B_RED, FH_WHITE, 15, VERTICAL,1,LOCKED);
      if (_animation() == -1) {ch=K_ESCAPE; break;} 
      if (ch == 0x27) {break;} 
      if (ch == K_ENTER){

        if (scrollData.item[0] == '[') {
	 //directory   
            memset(&path, '\0',sizeof(path)); //Clear memory for temporary line
            memset(&bit, '\0',sizeof(bit)); //Clear memory for temporary line
    	    strcpy(bit,"\0");
            strcpy(path,"\0");
            for (i=1; i<strlen(scrollData.item)-1; i++) bit[i-1] = scrollData.item[i];
	    getcwd(path, sizeof(path));
	    strcat(path, "/");
	    strcat(path, bit);
	    chdir(path);
	    ch=0;
      }
      else {
	     break;
      }	 
    } 
   } while (ch!=ESC_KEY);   
    setselectorLimit(15);
   

    if (ch!=27){
    	    //we pass the values
            //memset(&fullPath, '\0',sizeof(fullPath)); //Clear memory for temporary line
            memset(fileName, '\0', strlen(fileName) + 1); // Clear memory for temporary line
            memset(fullPath, '\0', strlen(fullPath) + 1); // Clear memory for temporary line
           // memset(&fileName, '\0',sizeof(fileName)); //Clear memory for temporary line
    	    strcpy(bit,"\0");
            strcpy(path,"\0");
            strcpy(fileName, scrollData.item);
            strcpy(fullPath, path);
	    //reset scroll values
	    cursorX=START_CURSOR_X;
	    cursorY=START_CURSOR_Y;
	    currentLine=0;
	    shiftH=0;
	    posBufX=0;
	    posBufY = 0;
	    retvalue = 1;
    }
    if (listBox1 != NULL) removeList(&listBox1);
   copy_screen(screen1,screen2); 
   //Finally check if it is a binary file
   if (openandcheckFile(fileName) == 1){
           ok2 = yesnoWindow(WCHECKFILE_MSG, "Alert window");
	 switch (ok2){
	    case 0: // open binary file anyway
		retvalue=1;
	    	break;            
	    case 1: //don't open binary file
	 	strcpy (fileName,"\0");
	 	strcpy (fullPath,"\0");
		retvalue=0;
	 	break;
	    case 2: //cancel is the same as no here
		strcpy (fileName,"\0");
	 	strcpy (fullPath,"\0");
		retvalue=0;
		break;
	   }
	 } else{
		 //file is a text file
    }
   return retvalue;
}






================================================
FILE: src/opfile.h
================================================
/*
========================================================================
- HEADER - 
Module to open a file by showing a dialogue that allows you to navigate 
through directories with a list with scroll.
@author : Velorek
@version : 1.0  
Last modified: 23/04/2024 Vastly simplified and integraed with lynx
========================================================================
*/

#ifndef _OPFILE_H_
#define _OPFILE_H_

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include "rterm.h"
#include "scbuf.h"
#include "listbox.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"

/*====================================================================*/
/* CONSTANTS */
/*====================================================================*/
#define MAX_ITEM_LENGTH 15


/*====================================================================*/
/* CONSTANT VALUES                                                    */
/*====================================================================*/

/*====================================================================*/
/* FUNCTION PROTOTYPES                                                */
/*====================================================================*/

int listFiles(LISTCHOICE ** listBox1, char *directory);
void addItems(LISTCHOICE **listBox1);
int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]);


#endif


================================================
FILE: src/rterm.c
================================================
/*
======================================================================
Module to control some display routines that implement ANSI functions.
on LINUX Terminals

@author : Velorek (routines extracted from the internet)
@version : 1.0

LAST MODIFIED : 18/01/2023 Kbhit with poll control added
======================================================================
*/

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <locale.h>
#include <sys/ioctl.h>
#include <poll.h>
#include "rterm.h"
#include "keyb.h"
/*====================================================================*/
/* GLOBAL VARIABLES                                                   */
/*====================================================================*/

struct winsize max;
static struct termios term, failsafe;
static int peek_character = -1;

/*====================================================================*/
/* FUNCTIONS - CODE                                                   */
/*====================================================================*/

/*-------------------------------------*/
/* Initialize new terminal i/o settings*/
/*-------------------------------------*/
void pushTerm() {
//Save terminal settings in failsafe to be retrived at the end
  tcgetattr(0, &failsafe);
}

/*---------------------------*/
/* Reset terminal to failsafe*/
/*---------------------------*/
int resetTerm() {
  //tcsetattr(0, TCSANOW, &failsafe);
  /* flush and reset */
  if (tcsetattr(0,TCSAFLUSH,&failsafe) < 0) return -1;
  return 0;
}


/*--------------------------------------.*/
/* Detect whether a key has been pressed.*/
/*---------------------------------------*/

int kbhit(int timeout_ms)
{
    struct pollfd fds = {STDIN_FILENO, POLLIN, 0};
    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
    int ret = poll(&fds, 1, timeout_ms);
    fcntl(STDIN_FILENO, F_SETFL, 0);
    if (ret > 0) {
        return 1;
    } else if (ret == 0) {
        return 0; // timeout occurred
    } else {
        return -1; // error occurred
    }
}

/*----------------------*/
/*Read char with control*/
/*----------------------*/
char readch() {
  char    ch;
 if(peek_character != -1) {
    ch = peek_character;
    peek_character = -1;
    return ch;
  }
  read(0, &ch, 1);
  return ch;
}

void resetch() {
//Clear ch
  term.c_cc[VMIN] = 0;
  tcsetattr(0, TCSANOW, &term);
  peek_character = 0;
}

/*----------------------------------*/
/* Move cursor to specified position*/
/*----------------------------------*/
void gotoxy(int x, int y) {
  printf("%c[%d;%df", 0x1B, y, x);
}

/*---------------------*/
/* Change colour output*/
/*---------------------*/
void outputcolor(int foreground, int background) {
  printf("%c[%d;%dm", 0x1b, foreground, background);
}

/*-----------------------------------------------------*/
/* Change the whole color of the screen by applying CLS*/
/*-----------------------------------------------------*/
void screencol(int x) {
  gotoxy(0, 0);
  outputcolor(0, x);
  printf("%c[2J", 0x1b);
  outputcolor(0, 0);
}

/*-----------------------*/
/* Reset ANSI ATTRIBUTES */
/*-----------------------*/
void resetAnsi(int x) {
  switch (x) {
    case 0:         //reset all colors and attributes
      printf("%c[0m", 0x1b);
      break;
    case 1:         //reset only attributes
      printf("%c[20m", 0x1b);
      break;
    case 2:         //reset foreg. colors and not attrib.
      printf("%c[39m", 0x1b);
      break;
    case 3:         //reset back. colors and not attrib.
      printf("%c[49m", 0x1b);
      break;
    default:
      break;
  }
}

/*------------------------*/
/* Get terminal dimensions*/
/*------------------------*/
int get_terminal_dimensions(int *rows, int *columns) {
  ioctl(0, TIOCGWINSZ, &max);
  *columns = max.ws_col;
  *rows = max.ws_row;
  return 0;
}

/*--------------------------*/
/* Ansi function hide cursor*/
/*--------------------------*/
void hidecursor() {
  printf("\e[?25l");
}

/*--------------------------*/
/* Ansi function show cursor*/
/*--------------------------*/
void showcursor() {
  printf("\e[?25h");
}
/*----------------------------------*/
/* Get cursor  position             */
/*----------------------------------*/

int get_pos(int *y, int *x) {

 char buf[30]={0};
 int ret, i, pow;
 char ch;

*y = 0; *x = 0;

 struct termios term, restore;

 tcgetattr(0, &term);
 tcgetattr(0, &restore);
 term.c_lflag &= ~(ICANON|ECHO);
 tcsetattr(0, TCSANOW, &term);

 write(1, "\033[6n", 4);

 for( i = 0, ch = 0; ch != 'R'; i++ )
 {
    ret = read(0, &ch, 1);
    if ( !ret ) {
       tcsetattr(0, TCSANOW, &restore);
       //fprintf(stderr, "getpos: error reading response!\n");
       return 1;
    }
    buf[i] = ch;
    //printf("buf[%d]: \t%c \t%d\n", i, ch, ch);
 }

 if (i < 2) {
    tcsetattr(0, TCSANOW, &restore);
    //printf("i < 2\n");
    return(1);
 }

 for( i -= 2, pow = 1; buf[i] != ';'; i--, pow *= 10)
     *x = *x + ( buf[i] - '0' ) * pow;

 for( i-- , pow = 1; buf[i] != '['; i--, pow *= 10)
     *y = *y + ( buf[i] - '0' ) * pow;

 tcsetattr(0, TCSANOW, &restore);
 return 0;
}
/*--------------------------*/
/* Set up terminal          */
/*--------------------------*/

//For code simplification purposes
void init_term(void)

{
        //switch to alternate screen buffer
        printf("\033[?1049h");
	hidecursor();
	pushTerm();
	resetch();
	//Setup unicode  
	setlocale(LC_ALL, "");
}

void close_term(void)
{
	showcursor();
	resetTerm();
	resetAnsi(0);
	//restore previous screen
        printf("\033[?1049l");
	//cls
	gotoxy(0,0);
	printf("%c[2J\r", 0x1b);

}
/*
void init_term(){
  hidecursor();
  pushTerm();
  resetch();
  //Setup unicode  
  setlocale(LC_ALL, "");
}


void close_term(){
  showcursor();
  resetTerm();
  outputcolor(F_WHITE, B_BLACK);
  screencol(B_BLACK);
  resetAnsi(0);
  printf("\n");
}
*/



================================================
FILE: src/rterm.h
================================================
/*
========================================================================
- HEADER -
Module to control some display routines that implement ANSI functions.
@author : Velorek
@version : 1.0
Last modified: 15/09/2021 + Linux Term
========================================================================
*/

#ifndef _RTERM_H_
#define _RTERM_H_

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

/*====================================================================*/
/* COLOR CONSTANTS                                                    */
/*====================================================================*/

// Background colors low intensity
#define B_BLACK 40
#define B_RED 41
#define B_GREEN 42
#define B_YELLOW 43
#define B_BLUE 44
#define B_MAGENTA 45
#define B_CYAN 46
#define B_WHITE 47

// Foreground colors low intensity
#define F_BLACK 30
#define F_RED 31
#define F_GREEN 32
#define F_YELLOW 33
#define F_BLUE 34
#define F_MAGENTA 35
#define F_CYAN 36
#define F_WHITE 37
//#define F_WHITE 37
#define F_GREY 90

// Background colors high intensity
#define BH_BLACK 100
#define BH_RED 101
#define BH_GREEN 102
#define BH_YELLOW 103
#define BH_BLUE 104
#define BH_MAGENTA 105
#define BH_CYAN 106
#define BH_WHITE 107

// Foreground colors high intensity
#define FH_BLACK 90
#define FH_RED 91
#define FH_GREEN 92
#define FH_YELLOW 93
#define FH_BLUE 94
#define FH_MAGENTA 95
#define FH_CYAN 96
#define FH_WHITE 97

#define TRUE 1
#define FALSE 0

//Keys used.
#define K_ENTER 13
#define K_ENTER2 10
#define K_ESCAPE 27
#define K_UP_TRAIL "\e[A\0\0"
#define K_DOWN_TRAIL "\e[B\0\0"
#define K_RIGHT_TRAIL "\e[C\0\0"
#define K_LEFT_TRAIL "\e[D\0\0"


//#define K_UP_ARROW 'A'      // K_ESCAPE + 'A' -> UP_ARROW
//#define K_DOWN_ARROW 'B'    // K_ESCAPE + 'B' -> DOWN_ARROW
typedef int BOOL;

/*====================================================================*/
/* FUNCTION PROTOTYPES                                                */
/*====================================================================*/

void    pushTerm();
int     resetTerm();
int kbhit(int timeout_ms);
	
char     readch();
char     getch();
void    resetch();
//char    getch(void);
void    gotoxy(int x, int y);
void    outputcolor(int foreground, int background);
void    screencol(int x);
void    resetAnsi(int x);
int     get_terminal_dimensions(int *rows, int *columns);
int get_pos(int *y, int *x);
void    showcursor();
void    hidecursor();
void    init_term();
void    close_term();
#endif


================================================
FILE: src/scbuf.c
================================================
/* Module to create a screen buffer
 * to act as an intermediate step between screen output and
 * the display so as to create a Text User Interface.
 * @author:velorek
 * Last modified: 1/02/2019
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rterm.h"
#include "scbuf.h"

#define ROWS_FAILSAFE 25
#define COLUMNS_FAILSAFE 80
#define FILL_CHAR 32

  int     sc_rows=0, sc_columns=0;
  int     buffersize=0;
 

/* SINGLE LINKED LIST ROUTINES */
// create new list element of type SCREENCELL from the supplied text string
SCREENCELL *newelement(SCREENCELL temp)
{
	SCREENCELL *newp;
	newp = (SCREENCELL *) malloc (sizeof(SCREENCELL));
	newp->index = temp.index;
	newp->backColor = temp.backColor;
	newp->foreColor = temp.foreColor;
        newp->toUpdate = 0;
	newp->ch = temp.ch;
        newp->next = NULL;
	return newp;
}


void deleteList(SCREENCELL **head) 
{ 
   /* deref head_ref to get the real head */
   SCREENCELL *current = *head; 
   SCREENCELL *next = NULL;
   while (current != NULL)  
   { 
       next = current->next; 
       free(current);
       current = next; 
   }
  
   free(current);
   free(next);
   current = NULL;
   next = NULL;
   *head = NULL; 
} 

/* addfront: add new SCREENCELL to front of list  */
/* example usage: start = (addfront(start, newelement("burgers")); */

SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp)
{
	newp -> next = head;
	return newp;
}

/* addend: add new SCREENCELL to the end of a list  */
/* usage example: start = (addend(start, newelement("wine")); */

SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp)
{
	SCREENCELL *p2; 	
	if (head == NULL)
		return newp;
// now find the end of list
	for (p2 = head; p2 -> next != NULL; p2 = p2 -> next)
		;
	p2 -> next = newp;
	return head;
}


int length(SCREENCELL **head)
// this routine uses pointer-to-pointer techniques :-)
{

	int count=0;
	SCREENCELL **tracer = head;
	while ((*tracer) != NULL) {
		count = count +1;	
		tracer = &(*tracer)->next;
	}
       return count;
}

void reindex(SCREENCELL **head)
{
	int count=0;	
	SCREENCELL *p=NULL;
	SCREENCELL **tracer = head;
	while ((*tracer) != NULL) {
		p = *tracer;
		p->index=count;
		count = count +1;
		tracer = &(*tracer)->next;
	}           
}

/* SCREEN BUFFER ROUTINES */

int create_screen(SCREENCELL **newScreen){
 /*
     Get terminal dimensions and create a dynamic list with the size of the screen.
     if it is not possible to determine screen dimensions default is set to 80x25.
     Insertion happens at the end of the list.   */
  int     i=0;
  SCREENCELL   temp;
  SCREENCELL  **aux = newScreen;

  //We attempt to get terminal dimensions. If not
  //successful failsafe values (80x25) apply.
  get_terminal_dimensions(&sc_rows, &sc_columns);
  if(sc_rows == 0)
    sc_rows = ROWS_FAILSAFE;
  if(sc_columns == 0)
    sc_columns = COLUMNS_FAILSAFE;
  buffersize = sc_rows * sc_columns;

  // Assign dummy data to Screen buffer
   if(*aux == NULL) {
    //All cells have the same init data
       temp.ch = FILL_CHAR;
       temp.backColor = B_BLACK;
       temp.foreColor = F_WHITE; 
     for(i = 0; i < buffersize; i++) {
      //Except for their index
      temp.index = buffersize - 1 - i;
      *aux = addfront(*aux, newelement(temp)); 
     }
     return 1; 
   } else{
      //Pointer is not void
     return 0;
   }
}
void copy_screen(SCREENCELL *destination,SCREENCELL *source){
  int     i=0;
  SCREENCELL *aux1=destination;
  SCREENCELL *aux2=source;
   //We attempt to get terminal dimensions. If not
  //successful failsafe values (80x25) apply.
 if((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2)) ) {
   for(i = 0; i < buffersize; i++) {
      aux1->backColor = aux2->backColor;
      aux1->foreColor = aux2->foreColor;
      aux1->ch = aux2->ch;
      aux1 = aux1->next;
      aux2 = aux2->next;
    }
   }
}


/*------------------------------------------*/
/* Update single char to screen for display */
/*------------------------------------------*/
void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor) {
//Write Unicode char to screen raw
   resetAnsi(0);
   gotoxy(x+1, y+1);
   outputcolor(forecolor, backcolor);
   printf("%lc", ch);  //unicode
}

void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor,BOOL raw) {
/* Update cell on screenbuffer. It will be shown on screen when it is updated by calling update_screen */
  int     i, pos;

  SCREENCELL *aux = newScreen;
  resetAnsi(0);
  if (aux != NULL && buffersize <= length(&aux)){

    pos = (y - 1) * sc_columns + x;   //This is the formula to calculate the position index in the screen buffer
    if(pos < buffersize) {
      // If it is within buffer limits, otherwise do nothing.
      for(i = 0; i <= pos; i++) {
        //Run through the buffer until reaching desired position
        if (aux->index == pos)
      break;
        aux = aux->next;
      }
      //Update cell info at position selected.
      //Manage special charaters as well.
	  aux->ch = ch;
          aux->backColor = backcolor;
          aux->foreColor = forecolor;
          aux->toUpdate = 1;

        if(raw==TRUE) {
   		gotoxy(x+1, y);
   		outputcolor(forecolor, backcolor);
   		if (ch>31) printf("%lc", ch);  //unicode
         }
    }
  }
}

SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y) {
/* read specific character with attributes from buffer */
  int     i=0, pos=0;
  SCREENCELL *aux=newScreen;
  SCREENCELL ret ={};
  if (aux != NULL && buffersize <= length(&aux)){
    pos = (y - 1) * sc_columns + x;	//this is the formula to calculate the position index in the screen buffer
   if(pos < buffersize) {
    for(i = 0; i <= pos; i++) {
        //run through the buffer until reaching desired position
        if(aux->index == pos)
	  break;
        aux = aux->next;
    }
    ret.index = aux->index;
    ret.ch = aux->ch;
    //for some unknown reason these values have to be inverted
    ret.backColor = aux->foreColor;
    ret.foreColor = aux->backColor;
    ret.next = NULL;
   }
 }
  return ret;
}


wchar_t read_char(SCREENCELL *newScreen, int x, int y) {
/* read specific character from buffer */
  int     i=0, pos=0;
  wchar_t ch = FILL_CHAR;
  SCREENCELL *aux=newScreen;
  if (aux != NULL && buffersize <= length(&aux)){
    pos = (y - 1) * sc_columns + x;	//this is the formula to calculate the position index in the screen buffer
   if(pos < buffersize) {
    for(i = 0; i <= pos; i++) {
        //run through the buffer until reaching desired position
        if(aux->index == pos)
	  break;
        aux = aux->next;
    }
    ch = aux->ch; 
   }
 }
  return ch;
}

/*------------------------------------------*/
/* Writes a string of characters to buffer. */
/*------------------------------------------*/

void write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw) {
  //Writes a string of characters to buffer.
  char   *astr=NULL;
  size_t     i=0;
  int wherex=0;
  SCREENCELL *aux = newScreen;

  if (aux!=NULL){
    wherex = x;
    astr = str;
    for(i = 0; i <= strlen(str) - 1; i++) {
      write_ch(aux, wherex, y, astr[i], backcolor, forecolor,raw);
      wherex = wherex + 1;
    }
 }
}

/*------------------------------------------*/
/* Writes a string of characters to screen. */
/*------------------------------------------*/

void update_str(int x, int y, char *str, char backcolor, char forecolor) {
  //Writes a string of characters to buffer.
  char   *astr=NULL;
  size_t     i=0;
  int wherex=0;

    resetAnsi(0);
    wherex = x;
    astr = str;
    for(i = 0; i <= strlen(str) - 1; i++) {
      update_ch(wherex, y, astr[i], backcolor, forecolor);
      wherex = wherex + 1;
    }
}

/*-----------------------------------------------*/
/* Writes an integer value as a string on screen */
/*-----------------------------------------------*/

int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,
	       char forecolor, BOOL raw) {
  //the length of the string must be passed on the function
  char   astr[30];
  char len=0;
  SCREENCELL *aux = newScreen;

  if (aux!=NULL){
    sprintf(astr, "%d", num);
    write_str(newScreen, x, y, astr, backcolor, forecolor,raw);
    len = strlen(astr);
  }
  return len;
}

void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch) {
/* Changes the color of all the cells to create the effect of changing color in the background */
  int     i=0;
  SCREENCELL *aux=newScreen;
  resetAnsi(0);
  //screen should be updated twice to get round the last row glitch
  if (aux != NULL && buffersize <= length(&aux)){ 
   for(i = 0; i < buffersize; i++) {
      aux->backColor = bcolor;
      aux->foreColor = fcolor;
      aux->ch = ch;
      aux->toUpdate = 1;
      aux = aux->next;
    }
 }
}

/*------------------------------------*/
/* Dumps buffer to screen for display */
/*------------------------------------*/


void dump_screen(SCREENCELL *newScreen) {
/* UPDATES ALL SCREEN CELLS TO DISPLAY */
  int     i=0;
  int     wherex=0, wherey=0;
  SCREENCELL *aux=newScreen;
  if (aux!=NULL && buffersize <= length(&aux)){
  for(i = 0; i < buffersize; i++) {
      update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor); 
      wherex = wherex + 1; //line counter
      if(wherex == sc_columns) {
        //new line
        wherex = 0;
        wherey = wherey + 1;
      }
      aux = aux->next;
    }
  }
}

void update_screen(SCREENCELL *newScreen) {
/* UPDATES ALL SCREEN CELLS TO DISPLAY */
  int     i=0;
  int     wherex=0, wherey=0;
  SCREENCELL *aux=newScreen;
  if (aux!=NULL && buffersize <= length(&aux)){
  for(i = 0; i < buffersize; i++) {
      if (aux->toUpdate ==1) {aux->toUpdate = 0; update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor);} 
      wherex = wherex + 1; //line counter
      if(wherex == sc_columns) {
        //new line
        wherex = 0;
        wherey = wherey + 1;
      }
      aux = aux->next;
    }
  }
}


void xor_update(SCREENCELL *screen1, SCREENCELL *screen2) {
/* UPDATE only the cells that are different */
  int     i=0;
  int     wherex=0, wherey=0;
  SCREENCELL *aux1=screen1;
  SCREENCELL *aux2=screen2;
  if ((aux1!=NULL && aux2!=NULL) && (length(&aux1) == length(&aux2))){
   for(i = 0; i < buffersize; i++) {
     if (aux1->ch != aux2->ch || aux1-> backColor != aux2 -> backColor || aux1-> foreColor != aux2 -> foreColor){ 
       update_ch(wherex,wherey,aux1->ch,aux1->backColor,aux1->foreColor);
      } 
      wherex = wherex + 1; //line counter
      if(wherex == sc_columns) {
        //new line
        wherex = 0;
        wherey = wherey + 1;
      }
      aux1 = aux1->next;
      aux2 = aux2->next;
    }
  }
}


void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2)
{
/* UPDATES ALL SCREEN CELLS TO DISPLAY */
	int i = 0;
	int wherex = 0, wherey = 0;
	SCREENCELL *aux1 = screen1;
	SCREENCELL *aux2 = screen2;
	if ((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2))) {
		for (i = 0; i < buffersize; i++) {

			if (aux1->ch != aux2->ch
			    || aux1->backColor != aux2->backColor
			    || aux1->foreColor != aux2->foreColor) {
				aux1->ch = aux2->ch;
				aux1->backColor = aux2->backColor;
				aux1->foreColor = aux2->foreColor;
				wherex = wherex + 1;	//line counter

				if (wherex == sc_columns) {
					//new line
					wherex = 0;
					wherey = wherey + 1;
				}

				aux1 = aux1->next;
				aux2 = aux2->next;
			}
		}
	}
}
/*------------------------------------------*/
/* Draw window area with or without border. */
/*------------------------------------------*/

void draw_window(SCREENCELL *newScreen, int x1, int y1, int x2, int y2, int backcolor, int bordercolor, int titlecolor, BOOL  border, BOOL title, BOOL shadow, BOOL raw) {
/*
   Draw a box on screen
 */
  SCREENCELL *aux = newScreen;
  int     i, j;
  wchar_t ch=FILL_CHAR;
  i = x1;
  j = y1;
  //shadow
  resetAnsi(0);
  if (shadow == TRUE){
  for(j = y1 + 1; j <= y2 + 1; j++)
    for(i = x1 + 1; i <= x2 + 1; i++)
    {
      ch=read_char(aux, i,j); //dynamic shadow
      if ((ch=='\0') || (ch == UNICODEBAR1) || (ch<0)) ch=FILL_CHAR;
      //ch=FILL_CHAR;
      //if (ch<0) ch = (tempLine.linea[i].specialChar << 8) | tempLine.linea[i].ch;
      write_ch(aux, i, j, ch, B_BLACK, F_WHITE,raw);
    }
  }
  //window
  for(j = y1; j <= y2; j++)
    for(i = x1; i <= x2; i++)
      write_ch(aux, i, j, FILL_CHAR, backcolor, bordercolor,raw);
 
 //borders
  if(border == TRUE) {
    for(i = x1; i <= x2; i++) {
      //upper and lower borders
      write_ch(aux, i, y1, HOR_LINE, backcolor, bordercolor,raw);   //horizontal line box-like char
      write_ch(aux, i, y2, HOR_LINE, backcolor, bordercolor,raw);
    }
    for(j = y1; j <= y2; j++) {
      //left and right borders
      write_ch(aux, x1, j, VER_LINE, backcolor, bordercolor,raw);   //vertical line box-like char
      write_ch(aux, x2, j, VER_LINE, backcolor, bordercolor,raw);
    }
    write_ch(aux, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,raw);   //upper-left corner box-like char
    write_ch(aux, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,raw);   //lower-left corner box-like char
    write_ch(aux, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,raw);  //upper-right corner box-like char
    write_ch(aux, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,raw);  //lower-right corner box-like char
  }

  if (title == TRUE) {
    for(i = x1+1; i <= x2-1; i++)
      write_ch(aux, i, y1, ' ', titlecolor, titlecolor,raw);
  }
}




================================================
FILE: src/scbuf.h
================================================
#ifndef _SCBUF_H_
#define _SCBUF_H_

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <wchar.h>
#include "rterm.h"

#define HOR_LINE 9472
#define VER_LINE 9474
#define UPPER_LEFT_CORNER 9484
#define LOWER_LEFT_CORNER 9492
#define UPPER_RIGHT_CORNER 9488
#define LOWER_RIGHT_CORNER 9496
#define UNICODEBAR1 0x2592

typedef struct _screencell 
{ 
	int index;
   	char backColor;
        char foreColor;
        unsigned char toUpdate;
        //int char attrib; 
        wchar_t ch;
	struct _screencell *next;
} SCREENCELL;


/* Adapted from Kernighan and Pike's "The Practice of Programming"  pp.46 et 
seq. (Addison-Wesley 1999) - computerPhile */

// create new list element of type SCREENCELL from the supplied text string
SCREENCELL *newelement(SCREENCELL temp);
SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp);
SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp);
void deleteList(SCREENCELL **head);
int length(SCREENCELL **head);
void reindex(SCREENCELL **head);
//SCREEN BUFFER ROUTINES
int create_screen(SCREENCELL **newScreen);
void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor);
void update_screen(SCREENCELL *newScreen);
void dump_screen(SCREENCELL *newScreen);
void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor, BOOL raw);
wchar_t read_char(SCREENCELL *newScreen, int x, int y);
SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y);
void write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw);
void update_str(int x, int y, char *str, char backcolor, char forecolor);
int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,
	       char forecolor, BOOL raw);
void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch);
void copy_screen(SCREENCELL *destination,SCREENCELL *source);
void xor_update(SCREENCELL *screen1, SCREENCELL *screen2);
void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2);
void draw_window(SCREENCELL *newScreen, int x1, int y1, int x2, int y2, int backcolor, int bordercolor, int titlecolor, BOOL border, BOOL title, BOOL shadow, BOOL raw);
#endif


================================================
FILE: src/t.txt
================================================
Hello 


there




================================================
FILE: src/tm.c
================================================
/* Module to create a milisecond timer
 * @author: velorek
 * Last modified: 10/08/2020
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tm.h"

#include <sys/time.h>
#include <poll.h>

long long epoch_ms(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000LL + (tv.tv_usec + 500) / 1000;
}
int timerC(NTIMER *mytimer1){
    long long difference = 0;
    long long res;
    if (mytimer1->ticks == -1) return 0;
    if (mytimer1->ticks == 0){
        // First tick, set up values
        mytimer1->oldtime = epoch_ms();
        mytimer1->ticks = 1;
        return 1;
    } else {
        // Subsequent ticks
        long long now = epoch_ms();
        difference = now - mytimer1->oldtime;
        res = difference;
        if (res < mytimer1->ms) {
            return 0;
        } else {
            mytimer1->oldtime = now;
            mytimer1->ticks = mytimer1->ticks + 1;
            return 1;
        }
    }
}

void init_timer(NTIMER *mytimer1, int ms){
    // Init routine
    mytimer1->ticks = 0;
    mytimer1->ms = ms;
}

void stop_timer(NTIMER *mytimer1){
    // Stop routine
    mytimer1->ticks = -1;
}

void resume_timer(NTIMER *mytimer1){
    // Resume routine
    mytimer1->ticks = 0;
}



================================================
FILE: src/tm.h
================================================
/*
========================================================================
- HEADER -
Module to implement a millisecond TIMER in C.
@author : Velorek
@version : 1.0
Last modified: 15/09/2021 + New technique + init timer
========================================================================
*/

#ifndef _TM_H_
#define _TM_H_

/*====================================================================*/
/* COMPILER DIRECTIVES AND INCLUDES                                   */
/*====================================================================*/

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

/*====================================================================*/
/* FUNCTION PROTOTYPES                                                */
/*====================================================================*/
typedef struct nTimer{
        int  ms; //milliseconds
    long oldtime; //to calculate increment in time
    long ticks; //how many ticks have been made
} NTIMER;

/* Miliseconds timer */
int timerC(NTIMER *mytimer1);
void init_timer(NTIMER *mytimer, int ms);
void stop_timer(NTIMER *mytimer);
void resume_timer(NTIMER *mytimer);

#endif


================================================
FILE: src/ui.c
================================================
/* Module to create different widgets/gadgets 
 * for a Text User Interface
 * TextBox
 * Window
 * Last modified: 15/04/2023
 * @author:velorek
 */
#include <stdio.h>
#include "rterm.h"
#include "scbuf.h"
#include "ui.h"
#include "tm.h"
#include "keyb.h"
#include "global.h"
/*----------------------------*/
/* User Interface - Text Box. */
/*----------------------------*/
int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength,
        char *label, char text[MAX_TEXT], int backcolor,
        int labelcolor, int textcolor, BOOL raw, BOOL locked) {
  int     charCount = 0;
  int     exitFlag = 0;
  int     cursorON = 1;
  int     i;
  int     limitCursor = 0;
  int     positionx = 0;
  int     posCursor = 0;
  int     keypressed = 0;
  char    chartrail[5];
 // char    accentchar[2];
  char    displayChar;
  char    ch;
  NTIMER  cursorTime;
  SCREENCELL *aux = newScreen;
  resetAnsi(0); 
  init_timer(&cursorTime,150);
  positionx = wherex + strlen(label);
  limitCursor = wherex+strlen(label)+displayLength+1;
  write_str(aux,wherex, wherey, label, backcolor, labelcolor,raw);
  write_ch(aux,positionx, wherey, '[', backcolor, textcolor,raw);
  for(i = positionx + 1; i <= positionx + displayLength; i++) {
    write_ch(aux,i, wherey, '.', backcolor, textcolor,raw);
  }
  write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor,
       textcolor,raw);
  if (raw != TRUE) dump_screen(aux);
  //Reset keyboard
  if(kbhit(1) == 1) ch = readch();
  ch = 0;

  do {
	 if (locked == 0) break;
      keypressed = kbhit(1);
       if (timerC(&timer2) == TRUE) _animation();
    //Cursor Animation
   if (keypressed == 0){
    
    if (timerC(&cursorTime) == TRUE){
      switch (cursorON) {
    case 1:
      posCursor = positionx + 1;
          displayChar = '.';
          if (posCursor == limitCursor) {
            posCursor = posCursor - 1;
            displayChar = ch;
          }
          write_ch(aux,posCursor, wherey, displayChar, backcolor, textcolor,raw);
          //update_screen(aux);
          if (raw != TRUE) dump_screen(aux);
          cursorON = 0;
      break;
    case 0:
          posCursor = positionx + 1;
          if (posCursor == limitCursor) posCursor = posCursor - 1;
          write_ch(aux,posCursor, wherey, '|', backcolor, textcolor,raw);
          //update_screen(aux);
          if (raw != TRUE) dump_screen(aux);
          cursorON = 1;
      break;
      }
     }
    }
    //Process keys
    if(keypressed == 1) {
      ch = readch();
      keypressed = 0;
      //Read special keys
      if (ch==K_ESCAPE) {
               read_keytrail(chartrail);
      }
      //Read accents
      //if (ch==SPECIAL_CHARSET_1) read_accentchar(&ch, accentchar);
      //if (ch==SPECIAL_CHARSET_2) read_accentchar(&ch, accentchar);

      if(charCount < displayLength) {
     if(ch > 31 && ch < 127) {
      write_ch(aux,positionx + 1, wherey, ch, backcolor, textcolor,raw);
      text[charCount] = ch;
      positionx++;
      charCount++;
      //update_screen(aux);
      if (raw != TRUE) dump_screen(aux);
    }
      }
    }
    if (ch==K_CTRL_C){
	    return ENDSIGNAL;
    }
    if (ch==K_BACKSPACE){
      if (positionx>0 && charCount>0){
       ch=0;
       positionx--;
       charCount--;
       text[charCount] = '\0';
       write_ch(aux,positionx + 1, wherey, '.', backcolor, textcolor,raw);
       if (positionx < limitCursor-2) write_ch(aux,positionx + 2, wherey, '.', backcolor, textcolor,raw);
       //update_screen(aux);
       if (raw != TRUE) dump_screen(aux);
       //resetch();
      }
    }
    if(ch == K_ENTER || ch == K_TAB || ch == K_ESCAPE)
      exitFlag = 1;

    //ENTER OR TAB FINISH LOOP
  } while(exitFlag != 1);
  text[charCount] = '\0';
  //Clear field
  positionx = wherex + strlen(label);
  for(i = positionx + 1; i <= positionx + displayLength; i++) {
    write_ch(aux,i, wherey, '.', backcolor, textcolor,raw);
  }
  write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor,
       textcolor,raw);
 
  //resetch();
  if (ch == K_ESCAPE) charCount = 0;
  return charCount;
}


void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor,
         int bordercolor, int titlecolor, int border, int title, int shadow) {
/*
   Chars for drawing box-like characters will be passed as negative values.
   When the update_screen routine is called, it will check for negative
   values and map these chars to Unicode characters.
 */
  int     i, j;
  //char ch=0x20;
  wchar_t ch=0x20;
  i = x1;
  j = y1;
  
  resetAnsi(0);
  //shadow
  if (shadow==1){
   for(j = y1 + 1; j <= y2 + 1; j++)
    for(i = x1 + 1; i <= x2 + 1; i++)
    {
      ch=read_char(screen1, i,j); //dynamic shadow
      if ((ch=='\0') || (ch==UNICODEBAR1)) ch=0x20;
      write_ch(screen1, i, j, ch, B_BLACK, F_WHITE,0);
    }
  }
  //window
  for(j = y1; j <= y2; j++)
    for(i = x1; i <= x2; i++)
      write_ch(screen1, i, j, ' ', backcolor, bordercolor,0);
  //borders
  if(border == 1) {
    //with borders. ANSI-ASCII 106-121
    for(i = x1; i <= x2; i++) {
      //upper and lower borders
      write_ch(screen1, i, y1, HOR_LINE, backcolor, bordercolor,0);   //horizontal line box-like char
      write_ch(screen1, i, y2, HOR_LINE, backcolor, bordercolor,0);
    }
    for(j = y1; j <= y2; j++) {
      //left and right borders
      write_ch(screen1,x1, j, VER_LINE, backcolor, bordercolor,0);   //vertical line box-like char
      write_ch(screen1,x2, j, VER_LINE, backcolor, bordercolor,0);
    }
    write_ch(screen1, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,0);   //upper-left corner box-like char
    write_ch(screen1, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,0);   //lower-left corner box-like char
    write_ch(screen1, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,0);  //upper-right corner box-like char
    write_ch(screen1, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,0);  //lower-right corner box-like char
  }
  if (title == 1) {
    for(i = x1; i <= x2; i++)
      write_ch(screen1, i, y1-1, ' ', titlecolor, titlecolor,0);
  }
 // dump_screen(screen1);
}

int inputWindow(char *label, char *tempFile, char *windowTitle,  int offsetX, int offsetY, int length) {
  int     window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;
  int     count = 0;
  resetAnsi(0);
  copy_screen(screen2,screen1);
  window_y1 = (new_rows / 2) - offsetY;
  window_y2 = (new_rows / 2);
  window_x1 = (new_columns / 2) - offsetX;
  window_x2 = (new_columns / 2) + offsetX;
  
  window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0,
          WINDOW_TITLEB,1,1,1);
  write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1-1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,0);
  dump_screen(screen1);
  count =
      textbox(screen1, window_x1 + 1, window_y1 + 1, length, label, tempFile, MENU_PANEL,
          MENU_FOREGROUND0, MENU_FOREGROUND0,1,1);
  copy_screen(screen1,screen2);
  dump_screen(screen1);
  return count;
}

int yesnoWindow(char *message, char *windowTitle) {

  int     window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;
  char ch = 0;
  int ok = 0;
  size_t i=0;
  int j = 0;
  int ix = 0;
  char tempChar=0;
  resetAnsi(0);
  copy_screen(screen2,screen1);
 
  window_y1 = (new_rows / 2) - 4;
  window_y2 = (new_rows / 2) + 4;
  window_x1 = (new_columns / 2) - 16;
  window_x2 = (new_columns / 2) + 16;
  window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0, WINDOW_TITLEB,1,0,1);
  dump_screen(screen1);
  write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,1);
 //'|' is used as line separator
 
  for(i = 0; i < strlen(message); i++) {
    tempChar = message[i];
    if (tempChar != '|'){
      write_ch(screen1,window_x1 + 1 + ix, window_y1 + 1 + j, tempChar, MENU_PANEL,MENU_FOREGROUND0,1);
    ix++;
    }else {
	    j++;
	    ix = 0;
    }
    }
  printf("\n");
  if (listBox1 != NULL) removeList(&listBox1);
  listBox1 = addatend(listBox1, newitem("[  YES ]",window_x1+3,window_y2-1,-1,-1));
  listBox1 = addatend(listBox1, newitem("[  NO  ]",window_x1+13,window_y2-1,-1,-1));
  listBox1 = addatend(listBox1, newitem("[CANCEL]",window_x1+23,window_y2-1,-1,-1));

  setselectorLimit(8);
  ch = listBox(listBox1, window_x1+2,window_y2, &scrollData, MENU_PANEL, MENU_FOREGROUND0,MENU_SELECTOR, MENU_FOREGROUND1, 3, HORIZONTAL,1,LOCKED);
  ok = scrollData.itemIndex;
  if (listBox1 != NULL) removeList(&listBox1);
  ch++;
  copy_screen(screen1,screen2);
  dump_screen(screen1);
  resetScrollData(&scrollData); 
  return ok;
}


================================================
FILE: src/ui.h
================================================
/*
========================================================================
- HEADER -
Module with different UI gadgets for LYNX.
@author : Velorek
@version : 1.0
Last modified: 06/02/2022
========================================================================
*/

#ifndef _UI_H_
#define _UI_H_
#define MAX_TEXT 255

#include "scbuf.h"
#include <stdio.h>

int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength,
        char *label, char text[MAX_TEXT], int backcolor,
        int labelcolor, int textcolor, BOOL raw, BOOL locked);

void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor,
         int bordercolor, int titlecolor, int border, int title, int shadow);

int inputWindow(char *label, char *tempFile, char *windowTitle, int offsetX, int offsetY, int length);
int yesnoWindow(char *message, char *windowTitle);
#endif


Download .txt
gitextract_9g946023/

├── LICENSE
├── README.md
├── TODO
├── TODO.md
└── src/
    ├── Makefile
    ├── TODO.md
    ├── edbuf.c
    ├── edbuf.h
    ├── editor.c
    ├── editor.h
    ├── fileb.c
    ├── fileb.h
    ├── global.c
    ├── global.h
    ├── keyb.c
    ├── keyb.h
    ├── listbox.c
    ├── listbox.h
    ├── main.c
    ├── menu.c
    ├── menu.h
    ├── opfile.c
    ├── opfile.h
    ├── rterm.c
    ├── rterm.h
    ├── scbuf.c
    ├── scbuf.h
    ├── t.txt
    ├── tm.c
    ├── tm.h
    ├── ui.c
    └── ui.h
Download .txt
SYMBOL INDEX (129 symbols across 19 files)

FILE: src/edbuf.c
  function VLINES (line 8) | VLINES *_newline(VLINES temp)
  function _RemoveThing (line 20) | void _RemoveThing(VLINES **head, int index)
  function _hardupdateLINE (line 38) | void _hardupdateLINE(VLINES **head, int index, VLINES temp)
  function _deletetheList (line 60) | void _deletetheList(VLINES **head)
  function VLINES (line 81) | VLINES *_update(VLINES *head, int index, VLINES temp)
  function VLINES (line 95) | VLINES *_getObject(VLINES *head, int index)
  function VLINES (line 110) | VLINES *_deleteline(VLINES *head, int index)
  function VLINES (line 130) | VLINES *_addfront(VLINES *head, VLINES *newp)
  function VLINES (line 139) | VLINES *_addatend (VLINES *head, VLINES *newp)
  function _printlist (line 151) | void _printlist(VLINES **head)
  function _length (line 166) | int _length(VLINES **head)
  function _reindex (line 179) | void _reindex(VLINES **head)
  function _deleteObject (line 192) | void _deleteObject(VLINES **head,int index, BOOL sort){
  function _dumpLine (line 201) | int _dumpLine(VLINES *head, long index, VLINES *line){
  function _updateLine (line 222) | int _updateLine(VLINES *head, long index, VLINES *line){
  function CHARBUF (line 244) | CHARBUF _getSingleChar(VLINES *head, long X, long Y ){
  function findEndline (line 268) | int findEndline(VLINES line) {
  function BOOL (line 285) | BOOL isLineTerminated(VLINES line) {

FILE: src/edbuf.h
  type BOOL (line 9) | typedef int BOOL;
  type CHARBUF (line 11) | typedef struct _charbuf
  type VLINES (line 18) | typedef struct _vlines

FILE: src/editor.c
  function wchar_t (line 21) | wchar_t convertChar(char c1, char c2) {
  function linetoScreenRAW (line 35) | void linetoScreenRAW(long whereY, VLINES tempLine){
  function linetoScreen (line 60) | void linetoScreen(long whereY, VLINES tempLine){
  function cleanScreenLine (line 93) | void cleanScreenLine(long whereY)
  function cleanSection (line 105) | void cleanSection(long whereY, long start, int amount)
  function buffertoScreen (line 121) | void buffertoScreen(BOOL raw){
  function buffertoFile (line 140) | void buffertoFile(char *fileName){
  function editor_section (line 166) | int editor_section(char ch){
  function filetoBuffer (line 554) | int filetoBuffer(char *fileName) { //EDBUF*
  function flush_editarea (line 633) | void flush_editarea(int force_update) {

FILE: src/fileb.c
  function file_exists (line 27) | int file_exists(char *fileName) {
  function getfileSize (line 41) | long getfileSize(FILE * filePtr) {
  function countLinesFile (line 56) | long countLinesFile(FILE * filePtr) {
  function checkFile (line 78) | long checkFile(FILE * filePtr) {
  function openandcheckFile (line 98) | int openandcheckFile(char *fileName) {
  function openFile (line 133) | int openFile(FILE ** filePtr, char fileName[], char *mode)
  function closeFile (line 156) | int closeFile(FILE * filePtr) {

FILE: src/global.c
  function initCEDIT (line 74) | int initCEDIT(){
  function _animation (line 105) | int _animation(){

FILE: src/global.h
  type BOOL (line 27) | typedef int BOOL;

FILE: src/keyb.c
  function read_keytrail (line 28) | int read_keytrail(char chartrail[5]){
  function read_accent (line 56) | int read_accent(char *ch, char accentchar[2])

FILE: src/listbox.c
  function LISTCHOICE (line 40) | LISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned for...
  function removeList (line 56) | void removeList(LISTCHOICE ** head) {
  function LISTCHOICE (line 70) | LISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp) {
  function gotoIndex (line 89) | void gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,
  function printlist (line 108) | void printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned disp...
  function loadlist (line 132) | void loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned index...
  function query_length (line 155) | int query_length(LISTCHOICE ** head) {
  function displayItem (line 171) | void displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select)
  function move_selector (line 227) | int move_selector(LISTCHOICE ** selector, SCROLLDATA * scrollData) {
  function selectorMenu (line 340) | char selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData) {
  function setselectorLimit (line 474) | void setselectorLimit(int num){
  function resetScrollData (line 477) | void resetScrollData(SCROLLDATA *scrollData)
  function listBox (line 497) | char listBox(LISTCHOICE * head,

FILE: src/listbox.h
  type LISTCHOICE (line 42) | typedef struct _listchoice {
  type SCROLLDATA (line 53) | typedef struct _scrolldata {

FILE: src/main.c
  function draw_screen (line 35) | void draw_screen(){
  function cursor_tick (line 106) | void cursor_tick(void){
  function update_indicators (line 174) | void update_indicators() {
  function main (line 226) | int main(int argc, char *argv[]) {
  function control_keys (line 312) | int control_keys(char ch){
  function special_keys (line 355) | int special_keys() {
  function credits (line 620) | void credits() {
  function _resizeScreen (line 674) | void _resizeScreen(){
  function displayMessage (line 696) | int displayMessage(char *temporaryMessage, int x, int y, int fColor, int...

FILE: src/menu.c
  function loadmenus (line 23) | void loadmenus(int choice) {
  function handlemenus (line 83) | void handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontal...
  function horizontal_menu (line 116) | char horizontal_menu() {
  function filemenu (line 135) | char filemenu() {
  function optionsmenu (line 277) | char optionsmenu() {
  function helpmenu (line 305) | char helpmenu() {
  function displayAbout (line 332) | int displayAbout(void)
  function addItemsHelp (line 439) | void addItemsHelp(LISTCHOICE **listBox1, char textarray[][MAXLINE], int ...
  function displayHelp (line 450) | int displayHelp(void)

FILE: src/opfile.c
  function listFiles (line 46) | int listFiles(LISTCHOICE ** listBox1, char *directory) {
  function addItems (line 125) | void addItems(LISTCHOICE **listBox1)
  function openFileDialog (line 136) | int openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]){

FILE: src/rterm.c
  type winsize (line 31) | struct winsize
  type termios (line 32) | struct termios
  function pushTerm (line 42) | void pushTerm() {
  function resetTerm (line 50) | int resetTerm() {
  function kbhit (line 62) | int kbhit(int timeout_ms)
  function readch (line 80) | char readch() {
  function resetch (line 91) | void resetch() {
  function gotoxy (line 101) | void gotoxy(int x, int y) {
  function outputcolor (line 108) | void outputcolor(int foreground, int background) {
  function screencol (line 115) | void screencol(int x) {
  function resetAnsi (line 125) | void resetAnsi(int x) {
  function get_terminal_dimensions (line 147) | int get_terminal_dimensions(int *rows, int *columns) {
  function hidecursor (line 157) | void hidecursor() {
  function showcursor (line 164) | void showcursor() {
  function get_pos (line 171) | int get_pos(int *y, int *x) {
  function init_term (line 220) | void init_term(void)
  function close_term (line 232) | void close_term(void)

FILE: src/rterm.h
  type BOOL (line 85) | typedef int BOOL;

FILE: src/scbuf.c
  function SCREENCELL (line 23) | SCREENCELL *newelement(SCREENCELL temp)
  function deleteList (line 37) | void deleteList(SCREENCELL **head)
  function SCREENCELL (line 59) | SCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp)
  function SCREENCELL (line 68) | SCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp)
  function length (line 81) | int length(SCREENCELL **head)
  function reindex (line 94) | void reindex(SCREENCELL **head)
  function create_screen (line 109) | int create_screen(SCREENCELL **newScreen){
  function copy_screen (line 144) | void copy_screen(SCREENCELL *destination,SCREENCELL *source){
  function update_ch (line 165) | void update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor) {
  function write_ch (line 173) | void write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char back...
  function SCREENCELL (line 206) | SCREENCELL read_cell(SCREENCELL *newScreen, int x, int y) {
  function wchar_t (line 232) | wchar_t read_char(SCREENCELL *newScreen, int x, int y) {
  function write_str (line 256) | void write_str(SCREENCELL *newScreen, int x, int y, char *str, char back...
  function update_str (line 277) | void update_str(int x, int y, char *str, char backcolor, char forecolor) {
  function write_num (line 296) | int write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,
  function screen_color (line 311) | void screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar...
  function dump_screen (line 333) | void dump_screen(SCREENCELL *newScreen) {
  function update_screen (line 352) | void update_screen(SCREENCELL *newScreen) {
  function xor_update (line 372) | void xor_update(SCREENCELL *screen1, SCREENCELL *screen2) {
  function xor_copy (line 396) | void xor_copy(SCREENCELL *screen1, SCREENCELL *screen2)
  function draw_window (line 430) | void draw_window(SCREENCELL *newScreen, int x1, int y1, int x2, int y2, ...

FILE: src/scbuf.h
  type SCREENCELL (line 20) | typedef struct _screencell

FILE: src/tm.c
  function epoch_ms (line 14) | long long epoch_ms(void)
  function timerC (line 20) | int timerC(NTIMER *mytimer1){
  function init_timer (line 44) | void init_timer(NTIMER *mytimer1, int ms){
  function stop_timer (line 50) | void stop_timer(NTIMER *mytimer1){
  function resume_timer (line 55) | void resume_timer(NTIMER *mytimer1){

FILE: src/tm.h
  type NTIMER (line 25) | typedef struct nTimer{

FILE: src/ui.c
  function textbox (line 18) | int textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLen...
  function window (line 142) | void window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int bac...
  function inputWindow (line 195) | int inputWindow(char *label, char *tempFile, char *windowTitle,  int off...
  function yesnoWindow (line 217) | int yesnoWindow(char *message, char *windowTitle) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (177K chars).
[
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2021 Velorek1\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "README.md",
    "chars": 3074,
    "preview": "C-EDIT Project in C language (NO NCURSES)\n=========================================\nC-EDIT for linux - ALPHA - A linux t"
  },
  {
    "path": "TODO",
    "chars": 679,
    "preview": "* Top Priority:\nCheck https://github.com/velorek1/ceditbuf/ for latest development implementations (2024(\n\n- Code a more"
  },
  {
    "path": "TODO.md",
    "chars": 273,
    "preview": "* Top Priority: (2025)\n- Complete menus / dialogs \n- READ MODE\n- FULL UTF 8 - SUPPORT change char to win_t/wchar in edit"
  },
  {
    "path": "src/Makefile",
    "chars": 942,
    "preview": ".POSIX:\nTARGET = cedit\nCC     = cc\nCFLAGS = -Wall -Wextra -fsigned-char   \nLDFLAGS =\nLDLIBS  =\n\n# The list of object fil"
  },
  {
    "path": "src/TODO.md",
    "chars": 55,
    "preview": "# ceditbuf\nC-edit with dynamic buffer (in development)\n"
  },
  {
    "path": "src/edbuf.c",
    "chars": 7037,
    "preview": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"edbuf.h\"\n\n\n// create new list element of type VLINE"
  },
  {
    "path": "src/edbuf.h",
    "chars": 1383,
    "preview": "#ifndef _EDBUF_H_\n#define _EDBUF_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#define MAX_LINE_SIZE 512\n#define TRUE 1\n#de"
  },
  {
    "path": "src/editor.c",
    "chars": 24394,
    "preview": "/* Main editor section C·edit \n * for a Text User Interface\n * Last modified: 6/04/2024\n * @author:velorek\n */\n#include "
  },
  {
    "path": "src/editor.h",
    "chars": 892,
    "preview": "/*\n========================================================================\n- HEADER -\nModule with main editor in C·edit"
  },
  {
    "path": "src/fileb.c",
    "chars": 3401,
    "preview": "/* \n======================================================================\nModule to describe basic file operations.\n\n@a"
  },
  {
    "path": "src/fileb.h",
    "chars": 1409,
    "preview": "/*\n========================================================================\n- HEADER - \nModule to handle basic file oper"
  },
  {
    "path": "src/global.c",
    "chars": 4393,
    "preview": "#include \"global.h\"\n#include \"rterm.h\"\n#include \"time.h\"\n\n// GLOBALS : SCREEN1 : ANIMATED | SCREEN2 : BASE SCREEN\nLISTCH"
  },
  {
    "path": "src/global.h",
    "chars": 7460,
    "preview": "/*\n * Global variables are intented to be placed here\n * Last modified: 9/7/2022\n * @author: velorek\n *\n */\n#ifndef _GLO"
  },
  {
    "path": "src/keyb.c",
    "chars": 2206,
    "preview": "/*\n======================================================================\nModule to control keyboard input.\n\n@author : V"
  },
  {
    "path": "src/keyb.h",
    "chars": 2556,
    "preview": "/*\n========================================================================\n- HEADER -\nModule to handle keyboard input i"
  },
  {
    "path": "src/listbox.c",
    "chars": 17204,
    "preview": "/*====================================================================*/\n/* +ListBox with double linked list and selecti"
  },
  {
    "path": "src/listbox.h",
    "chars": 4416,
    "preview": "/*\n========================================================================\n- HEADER -\nModule to implement a listBox int"
  },
  {
    "path": "src/main.c",
    "chars": 23714,
    "preview": "/* C-edit project\n* Last updated - 29/8/2024\n* New drop-down menu implementation\n* Added more modularisation: editor.c m"
  },
  {
    "path": "src/menu.c",
    "chars": 14351,
    "preview": "/* Module to display Menus on C·edit \n * for a Text User Interface\n * TextBox\n * Window\n * Last modified: 6/4/2024\n * @a"
  },
  {
    "path": "src/menu.h",
    "chars": 583,
    "preview": "/*\n========================================================================\n- HEADER -\nModule with all menus on C·EDIT\n@"
  },
  {
    "path": "src/opfile.c",
    "chars": 7656,
    "preview": "/*====================================================================*/\n/* OPEN FILE MODULE\n   +ListFiles with double l"
  },
  {
    "path": "src/opfile.h",
    "chars": 1647,
    "preview": "/*\n========================================================================\n- HEADER - \nModule to open a file by showing"
  },
  {
    "path": "src/rterm.c",
    "chars": 6089,
    "preview": "/*\n======================================================================\nModule to control some display routines that i"
  },
  {
    "path": "src/rterm.h",
    "chars": 2760,
    "preview": "/*\n========================================================================\n- HEADER -\nModule to control some display ro"
  },
  {
    "path": "src/scbuf.c",
    "chars": 13522,
    "preview": "/* Module to create a screen buffer\n * to act as an intermediate step between screen output and\n * the display so as to "
  },
  {
    "path": "src/scbuf.h",
    "chars": 2211,
    "preview": "#ifndef _SCBUF_H_\n#define _SCBUF_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#incl"
  },
  {
    "path": "src/t.txt",
    "chars": 17,
    "preview": "Hello \n\n\nthere\n\n\n"
  },
  {
    "path": "src/tm.c",
    "chars": 1259,
    "preview": "/* Module to create a milisecond timer\n * @author: velorek\n * Last modified: 10/08/2020\n */\n\n#include <stdio.h>\n#include"
  },
  {
    "path": "src/tm.h",
    "chars": 1165,
    "preview": "/*\n========================================================================\n- HEADER -\nModule to implement a millisecond"
  },
  {
    "path": "src/ui.c",
    "chars": 8681,
    "preview": "/* Module to create different widgets/gadgets \n * for a Text User Interface\n * TextBox\n * Window\n * Last modified: 15/04"
  },
  {
    "path": "src/ui.h",
    "chars": 877,
    "preview": "/*\n========================================================================\n- HEADER -\nModule with different UI gadgets "
  }
]

About this extraction

This page contains the full source code of the velorek1/c-edit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (163.4 KB), approximately 48.0k tokens, and a symbol index with 129 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!