[
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Velorek1\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "C-EDIT Project in C language (NO NCURSES)\n=========================================\nC-EDIT for linux - ALPHA - A linux text editor in the style of the MSDOS EDIT - WITHOUT USING NCURSES\nWorks well with Termux! :)\n* WARNING: DO NOT EDIT YOUR PRECIOUS FILES WITH THIS EDITOR!!\n\n\nContact me at: velorek1@gmail.com\n\n**NEW: AUGUST 2025**\n- Fixed flickering issues in status bar\n- Added pageup/down home/end keys\n\nHistory:\n- 2024 -> Dynamyc buffer added (vector of lineS)\n- 2023 -> Previous demo version kept in https://github.com/velorek1/C-editold\n- 2022 -> I have rewritten the screenbuffer and fixed polling issues (lynx: https://github.com/velorek1/lynx). \nIdeally, a keyboard library abstraction would be nice to expand the editor's possibilities.**\n- 2018 -> Start of the project; basic demo concepts developed (https://oldstuff286.blogspot.com/2018/03/c-edit-in-progress.html)\n\nTO INSTALL:  \n\n    * Download or clone repository.\n    * Type \"cd src\", \"make\" and \"./cedit\" to execute.\n    \nSo far I have implemented:\n\n* A very simple Double Screen Buffer with a simple linked list in memory for greater display control. \n* Rudimentary Text User Interface with Windows, Textbox, Keyboard handling, Color schemes, etc.\n* Automatic display resizing.\n* Open file dialog with a Listbox and SCROLL capabilities to navigate and find the file to open.\n* Rudimentary Edit buffer with vertical and horizontal scroll (vector of lines). \n* A millisecond timer for animations.\n* Timers and kbhit with no polling for optimate CPU usage.\n* Greater modularity than Demo version\n* Rudimentary syntax highlighting\n\nFiles in /src/:\n===============\n* rterm.c -> code for the library that handles output with Ansi Functions and kbhit() in linux console (with its header file)\n* listbox.c -> code for the circular linked list responsible for handling menus \n* scbuf.c -> code for controlling display with a double screen buffer (with its header file)\n* keyb.c -> module to control keyboard input.\n* opfile.c -> module that list files with scroll capabilities to select the file to open.\n* ui.c -> module with user interface widgets: alert windows, confirmation windows, textbox, etc.\n* fileb.c -> module for single file operations.\n* tm.c -> module for a millisecond timer for animations (C11)\n* main.c -> Editor in C in the style of MSDOS EDIT (In progress).\n* global.c -> Global variables and main animation\n* menu.c -> Drop-down menu\n* editor.c -> Code for the editor section\n* edbuf.c -> Buffer - vector of lines\n\n\nAs 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)\n\nTO-DO:\n* Clean code\n* Complete menus / dialogs \n* READ MODE\n* FULL UTF 8! - SUPPORT change from char to win_t/wchar in editor buffer\n* Copy/Paste/Cut routines / Highlight text\n* Create Keyboard abstraction to make it more portable (bottom-up fashion!)\n* Address glitches/bugs\n\n![Alt text](cedit3.jpg?raw=true \"Demo\")\n![Alt text](cedit4.jpg?raw=true \"Demo\")\n"
  },
  {
    "path": "TODO",
    "content": "* Top Priority:\nCheck https://github.com/velorek1/ceditbuf/ for latest development implementations (2024(\n\n- Code a more backward compatible timer : tm.c (done!)\n- Create Keyboard abstraction to make it more portable (bottom-up fashion!)\n- Rewrite screen buffer (in progress).\n- Rewrite and merge listbox with openfiledialog and menus.\n- Turn fw into a library to display long text with scroll.\n- Change editBuffer from static array to dynamic structure (in progress)\n- Expand behaviour of ENTER and BACKSPACE and REAL TAB SUPPORT! (in progress)\n- Add horizontal scroll (in progress)\n\n\n* Less Priority:\n- Highlight text and copy/paste function\n- Find text\n- Full UTF8 support?\n\n\n"
  },
  {
    "path": "TODO.md",
    "content": "* Top Priority: (2025)\n- Complete menus / dialogs \n- READ MODE\n- FULL UTF 8 - SUPPORT change char to win_t/wchar in editor buffer\n- Copy/Paste/Cut routines / Highlight text\n- Create Keyboard abstraction to make it more portable (bottom-up fashion!)\n- Address glitches/bugs\n"
  },
  {
    "path": "src/Makefile",
    "content": ".POSIX:\nTARGET = cedit\nCC     = cc\nCFLAGS = -Wall -Wextra -fsigned-char   \nLDFLAGS =\nLDLIBS  =\n\n# The list of object files.\nOBJS =  main.o rterm.o listbox.o scbuf.o\nOBJS += ui.o fileb.o global.o menu.o editor.o \nOBJS += keyb.o tm.o edbuf.o opfile.o \n\n# the list of files to clean\nTOCLEAN = cedit $(OBJS)\n\nRM ?= rm -f\n\nall: $(TARGET)\nclean:\n\t$(RM) $(TOCLEAN)\n\ncedit: $(OBJS)\n\t$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)\n\n# INCLUDE DEPENDENCIES to compile depending on which\n# source has been touched.\nmain.o: main.c rterm.h listbox.h scbuf.h keyb.h ui.h fileb.h tm.h \nfileb.o: fileb.c fileb.h\nkeyb.o: keyb.c rterm.h keyb.h\nlistbox.o: listbox.c scbuf.h keyb.h\neditor.o: scbuf.h keyb.h rterm.h\nrterm.o: rterm.c \nmenu.o: listbox.c scbuf.h ui.h keyb.h rterm.h\ntm.o: tm.c tm.h\nglobal.o: global.c global.h\nscbuf.o: scbuf.c rterm.h keyb.h scbuf.h\nui.o: ui.c scbuf.h rterm.h keyb.h\nopfile.o: opfile.c scbuf.h rterm.h listbox.h keyb.h tm.h global.h ui.h \n"
  },
  {
    "path": "src/TODO.md",
    "content": "# ceditbuf\nC-edit with dynamic buffer (in development)\n"
  },
  {
    "path": "src/edbuf.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"edbuf.h\"\n\n\n// create new list element of type VLINES from the supplied text string\nVLINES *_newline(VLINES temp)\n{\n\tVLINES *newp;\n\tnewp = (VLINES *) malloc (sizeof(VLINES));\n\tnewp->index = temp.index;\n\tmemcpy(newp->linea,temp.linea,sizeof(temp.linea)+1);\n        newp->next = NULL;\n\treturn newp;\n}\n\n// Delete first element on list whose item field matches the given text\n// NOTE!! delete requests for elements not in the list are silently ignored :-)\nvoid _RemoveThing(VLINES **head, int index)\n{\n\tBOOL present = FALSE;\n\tVLINES *old;\n\tVLINES **tracer = head;\n\tif ((*tracer)->index==index) present=TRUE;\n\twhile((*tracer) && !(present)){\n\t\tif ((*tracer)->index==index) present=TRUE;\n\t\ttracer = &(*tracer)->next;\n\t}\n\n\tif(present)\n\t{\n\t\told = *tracer;\n\t\t*tracer = (*tracer)->next;\n\t\tfree(old); // free up remainder of list element \n\t}\n}\nvoid _hardupdateLINE(VLINES **head, int index, VLINES temp)\n{\n\tint i=0;\n\tBOOL present = FALSE;\n\tVLINES **tracer = head;\n\tif ((*tracer)->index==index) present=TRUE;\n\twhile((*tracer) && !(present)){\n\t\tif ((*tracer)->index==index) {present=TRUE; break;}\n\t\ttracer = &(*tracer)->next;\n\t}\n\n\tif(present)\n\t{\n                for (i=0; i<MAX_LINE_SIZE; i++)\n                {\n                  (*tracer)->linea[i].ch = temp.linea[i].ch;\n                  (*tracer)->linea[i].attrib = temp.linea[i].attrib;\n                  (*tracer)->linea[i].specialChar = temp.linea[i].specialChar;\n                }\n\n\t}\n}\nvoid _deletetheList(VLINES **head) \n{ \n   /* deref head_ref to get the real head */\n   VLINES *current = *head; \n   VLINES *next = NULL;\n   VLINES **tracer=head; \n   while (current != NULL)  \n   { \n       next = current->next; \n       free(current);\n       current = next; \n   } \n    \n   /* deref head_ref to affect the real head back \n      in the caller. */\n\n   *tracer = NULL;\n} \n\n\n// updatelement: remove from list the first instance of an element \nVLINES *_update(VLINES *head, int index, VLINES temp)\n{\n\tVLINES *p;\n\tfor (p = head; p != NULL; p = p -> next) {\n            if (p -> index == index) {\n\t\tbreak;\n\t   }\n\t}\n\t p-> index = temp.index;\t\n\t return head;\n\t\n}\n\n// getObject \nVLINES *_getObject(VLINES *head, int index)\n{\n\tVLINES *p;\n\tfor (p = head; p != NULL; p = p -> next) {\n            if (p -> index == index) {\n\t\tbreak;\n\t   }\n\t}\n\t //p-> index = temp.index;\t\n\t return p;\n\t\n}\n// deleteline: remove from list the first instance of an element \n// containing a given text string\n// NOTE!! delete requests for elements not in the list are silently ignored \nVLINES *_deleteline(VLINES *head, int index)\n{\n\tVLINES *p, *prev;\n\tprev = NULL;\n\tfor (p = head; p != NULL; p = p -> next) {\n            if (p -> index == index) {\n\t\tif(prev == NULL)\n\t\t   head = p-> next;\n\t\telse\n\t\t   prev -> next = p -> next;\n\t\tfree(p);\t// remove rest of VLINES\n\t\treturn head;\n\t   }\n\t   prev = p;\t\n\t}\n  return NULL;\n}\n/* addfront: add new VLINES to front of list  */\n/* example usage: start = (addfront(start, newelement(\"burgers\")); */\n\nVLINES *_addfront(VLINES *head, VLINES *newp)\n{\n\tnewp -> next = head;\n\treturn newp;\n}\n\n/* addend: add new VLINES to the end of a list  */\n/* usage example: start = (addend(start, newelement(\"wine\")); */\n\nVLINES *_addatend (VLINES *head, VLINES *newp)\n{\n\tVLINES *p2; \t\n\tif (head == NULL)\n\t\treturn newp;\n// now find the end of list\n\tfor (p2 = head; p2 -> next != NULL; p2 = p2 -> next)\n\t\t;\n\tp2 -> next = newp;\n\treturn head;\n}\n\nvoid _printlist(VLINES **head)\n// this routine uses pointer-to-pointer techniques :-)\n{\n\tVLINES **tracer = head;\n\tint index=0, i = 0;\n\t  while ((*tracer) != NULL) {\n\t\tindex = (*tracer)->index;\n\t\tprintf(\"LINE %d | \", index);\n\t\tfor (i=0; i < MAX_LINE_SIZE; i++)\n\t\t      printf(\"%c\",(*tracer)->linea[i].ch);\n\t\tprintf(\"\\n\");\n\t\ttracer = &(*tracer)->next;\n\t  }  \n}\n\nint _length(VLINES **head)\n// this routine uses pointer-to-pointer techniques :-)\n{\n\n\tint count=0;\n\tVLINES **tracer = head;\n\tif (*head == NULL) return -1;\n\twhile ((*tracer) != NULL) {\n\t\tcount = count +1;\t\n\t\ttracer = &(*tracer)->next;\n\t}\n       return count;\n}\nvoid _reindex(VLINES **head)\n{\n\tint count=0;\t\n\tVLINES *p=NULL;\n\tVLINES **tracer = head;\n\twhile ((*tracer) != NULL) {\n\t\tp = *tracer;\n\t\tp->index=count;\n\t\tcount = count +1;\n\t\ttracer = &(*tracer)->next;\n\t}           \n}\n\nvoid _deleteObject(VLINES **head,int index, BOOL sort){\n   VLINES *p=*head;\n  if (index == 0 || _length(head) <=1 || p->index == index )\n    _RemoveThing(head,index);\n  else \n    _deleteline(*head,index);\n  if (sort == TRUE) _reindex(head); \n}\n\nint _dumpLine(VLINES *head, long index, VLINES *line){\n//Dumps contents of desired line from buffer into temporary line\n   int i=-1; char ch=0; char attrib = 0; char specialChar = 0;\n   VLINES *aux = NULL; //auxiliary pointer\n   aux = _getObject(head, index);\n   memset(line, '\\0',sizeof(&line)); //Clear memory for temporary line\n   //Does the line exist?\n   if (aux != NULL) { \n     for (i=0; i<MAX_LINE_SIZE; i++)\n     {\n       ch = aux->linea[i].ch;\n       attrib = aux->linea[i].attrib;\n       specialChar = aux->linea[i].specialChar;\n       line->linea[i].ch = ch;\n       line->linea[i].attrib = attrib;\n       line->linea[i].specialChar = specialChar;\n     }\n     i = aux->index;\n  }\n  return i;\n}\nint _updateLine(VLINES *head, long index, VLINES *line){\n//Copies contents of desired line from temporary line to buffer\n   int i=0; char ch=0; char specialChar = 0; \n   char attrib = 0;\n   VLINES *aux = NULL; //auxiliary pointer\n   aux = _getObject(head, index);\n   //Does the line exist?\n   if (aux != NULL) { \n     for (i=0; i<MAX_LINE_SIZE-1; i++)\n     {\n       ch = line->linea[i].ch;\n       specialChar = line->linea[i].specialChar;\n       attrib = line->linea[i].attrib;\n       aux->linea[i].ch = ch;\n       aux->linea[i].specialChar = specialChar;\n       aux->linea[i].attrib = attrib;\n      }\n     i = aux->index;\n  } \n  return i;\n}\n\nCHARBUF _getSingleChar(VLINES *head, long X, long Y ){\n//Dumps contents of desired line from buffer into temporary line\n   char ch=0; char attrib = 0; char specialChar = 0;\n   CHARBUF retvalues;\n   VLINES *aux = NULL; //auxiliary pointer\n   aux = _getObject(head, Y);\n   //Does the line exist?\n   if (aux != NULL) { \n       ch = aux->linea[X].ch;\n       specialChar = aux->linea[X].specialChar;\n       attrib = aux->linea[X].attrib;\n\n     } else\n  {\n       ch = '\\0';\n       specialChar = '\\0';\n       attrib = '\\0';\n  }\n  retvalues.ch = ch;\n  retvalues.attrib = attrib;\n  retvalues.specialChar = specialChar;\n  return retvalues;\n}\n\nint findEndline(VLINES line) {\n  char    ch = 0;\n  int     i=0;\n  int     result = 0;\n\n  do {\n    ch = line.linea[i].ch;\n    //write_ch(i,1,ch,F_RED,B_WHITE);\n    if(ch == 0x00 || ch == 0x10 || ch == 0x0A) //ch = 00\n      break;\n    i++;\n  } while(i < MAX_LINE_SIZE);\n  result = i;\n  ch = 0;\n  return result;\n}\n\nBOOL isLineTerminated(VLINES line) {\n  BOOL flag=FALSE;\n  char ch=0;\n  int i = 0;\n  for (i=0; i< MAX_LINE_SIZE; i++){\n    ch = line.linea[i].ch;\n    if(ch == 0x10 || ch == 0x0A)\n      flag = TRUE;\n  }\n  return flag;\n}\n\n\n"
  },
  {
    "path": "src/edbuf.h",
    "content": "#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#define FALSE 0\ntypedef int BOOL;\n\ntypedef struct _charbuf\n{\n    char ch;\n    char specialChar;\n    char attrib;    \n}CHARBUF;\n\ntypedef struct _vlines \n{ \n\tint  index;\n   \tCHARBUF linea[MAX_LINE_SIZE];\n\tstruct _vlines *next;\n} VLINES;\n\n/* Adapted from Kernighan and Pike's \"The Practice of Programming\"  pp.46 et \nseq. (Addison-Wesley 1999) */\n\n// create new list element of type VLINES from the supplied text string\nVLINES *_newline(VLINES temp);\nVLINES *_addfront(VLINES *head, VLINES *newp);\nVLINES *_addatend (VLINES *head, VLINES *newp);\nVLINES *_addmiddle (VLINES *head, VLINES *newp);\nVLINES *_update(VLINES *head, int index, VLINES temp);\nVLINES *_getObject(VLINES *head, int index);\nvoid _hardupdateLINE(VLINES **head, int index, VLINES temp);\nvoid _RemoveThing(VLINES **head, int index);\nvoid _deletetheList(VLINES **head);\nVLINES *_deleteline(VLINES *head, int index);\nvoid _deleteObject(VLINES **head,int index, BOOL sort);\nint _length(VLINES **head);\nvoid _printlist(VLINES **head);\nvoid _reindex(VLINES **head);\nint _dumpLine(VLINES *head, long index, VLINES *line);\nint _updateLine(VLINES *head, long index, VLINES *line);\nCHARBUF _getSingleChar(VLINES *head, long X, long Y );\nint findEndline(VLINES line);\nBOOL isLineTerminated(VLINES line);\n#endif\n"
  },
  {
    "path": "src/editor.c",
    "content": "/* Main editor section C·edit \n * for a Text User Interface\n * Last modified: 6/04/2024\n * @author:velorek\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include <locale.h>\n#include <wchar.h>\n#include \"rterm.h\"\n#include \"scbuf.h\"\n#include \"ui.h\"\n#include \"tm.h\"\n#include \"keyb.h\"\n#include \"global.h\"\n#include \"editor.h\"\n#include \"fileb.h\"\n#include \"edbuf.h\"\nint oldEndLine= 0;\n\nwchar_t convertChar(char c1, char c2) {\n\n    // Combine the bytes into a single string\n    char temp[3];\n    temp[0] = c1;\n    temp[1] = c2;\n    temp[2] = '\\0';\n\n    wchar_t wchar;\n\n    mbstowcs(&wchar, temp, 1);\n\n    return wchar;\n}\nvoid linetoScreenRAW(long whereY, VLINES tempLine){\n//dump temporary Line to screen buffer - RAW MODE\n   int i=0;\n   int attrib = EDIT_FORECOLOR;\n   int tempEndLine = findEndline(tempLine);\n   //if (tempEndLine <0) return;\n   for (i=0; i<tempEndLine; i++){\n\t   attrib = tempLine.linea[i+shiftH].attrib;  \n         //don't print beyond display!\n\n\t if (i+START_CURSOR_X < new_columns-1){\n\t  if(tempLine.linea[i+shiftH].specialChar!= 0) {\n\t    //Special char ? print the two values to screen buffer.\n            gotoxy(i+START_CURSOR_X+1, whereY+1);\n            outputcolor(attrib, EDITAREACOL);\n            printf(\"%c%c\", tempLine.linea[i+shiftH].specialChar,tempLine.linea[i+shiftH].ch);\n\t  } else {\n\t    gotoxy(i+START_CURSOR_X+1, whereY+1);\n            outputcolor(attrib, EDITAREACOL);\n            printf(\"%c\", tempLine.linea[i+shiftH].ch);\n  \t  }\n       }\n   } \n}\n\nvoid linetoScreen(long whereY, VLINES tempLine){\n//dump temporary Line to screen buffer - RAW MODE\n   int i=0;\n   int attrib = EDIT_FORECOLOR;\n   wchar_t temp='0';\n   int tempEndLine = findEndline(tempLine);\n   for (i=0; i<tempEndLine; i++){\n\t   attrib = tempLine.linea[i+shiftH].attrib;  \n         //don't print beyond display!\n\t if (i+START_CURSOR_X < new_columns-1){\n\t  if(tempLine.linea[i].specialChar != 0) {\n\t    //Special char ? print the two values to screen buffer.\n            //write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);\n            temp = convertChar(tempLine.linea[i+shiftH].specialChar, tempLine.linea[i+shiftH].ch);         // Second char\n            //if (temp<1 ) {temp = FILL_CHAR; attrib =F_BLUE;}\n            if ((temp<1 || temp =='\\0' || temp==END_LINE_CHAR)) {temp = FILL_CHAR; attrib =F_BLUE;}\n            write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);\n\t    \n            //rintf(\"%c%c\", tempLine.linea[i].specialChar,tempLine.linea[i].ch);\n\t  } else {\n            //write_ch(screen1,i+START_CURSOR_X, whereY+1,tempLine.linea[i].ch,attrib,EDITAREACOL,0);\n            temp = tempLine.linea[i+shiftH].ch;\n            //if (temp<1 ) temp = FILL_CHAR; \n            if ((temp<1 || temp =='\\0' || temp==END_LINE_CHAR)) {temp = FILL_CHAR; attrib =F_BLUE;}\n            write_ch(screen1,i+START_CURSOR_X, whereY+1,temp,attrib,EDITAREACOL,0);\n            //printf(\"%c\", tempLine.linea[i].ch);\n  \t  }\n       }\n   }\n\n}\n\n\nvoid cleanScreenLine(long whereY)\n{\n   int i=0;\n   for (i=0; i<new_columns-2; i++){\n\t \tgotoxy(i+START_CURSOR_X+1, whereY+1);\n         \toutputcolor(EDIT_FORECOLOR, EDITAREACOL);\n          \tprintf(\"%c\", FILL_CHAR);\n\t}\n    resetAnsi(0);\n   \n}\n\nvoid cleanSection(long whereY, long start, int amount)\n{\n   int i=0;\n   for (i=start; i<start+amount; i++){\n\t   if (i<new_columns-2){\n\t \tgotoxy(i+START_CURSOR_X+1, whereY+1);\n        \toutputcolor(EDIT_FORECOLOR, EDITAREACOL);\n          \tprintf(\"%c\", FILL_CHAR);\n\t   }\n\t}\n    resetAnsi(0);\n   \n}\n\n\n\nvoid buffertoScreen(BOOL raw){\n   long j=0;\n   if (raw == 0) flush_editarea(0);\n   for (j=0; j<vdisplayArea; j++){\n\t  _dumpLine(edBuf1, j+currentLine , &tempLine);\n \t  if (raw==TRUE){ \n\t      cleanScreenLine(j+START_CURSOR_Y);\n\t      linetoScreenRAW(j+START_CURSOR_Y, tempLine);\n\t  }else{ \n\t      //cleanScreenLine(j+START_CURSOR_Y);\n              linetoScreen(j+START_CURSOR_Y, tempLine);\n\t  }\n\t}\n//restore tempLine to active line\n     memset(&tempLine, '\\0',sizeof(tempLine));\n    _dumpLine(edBuf1, currentLine, &tempLine);\n    resetAnsi(0);\n}\n\nvoid buffertoFile(char *fileName){\n  long j=0,i=0; \n  wchar_t tempLongChar = 0;\n  openFile(&filePointer, fileName, \"w\");\n  if (filePointer != NULL){\n  for (j=0; j<_length(&edBuf1); j++){\n       //tempLine = {0};\n      _dumpLine(edBuf1, j, &tempLine);\n      for (i=0; i<findEndline(tempLine); i++){\n\n\t  if(tempLine.linea[i].specialChar != 0) {\n            tempLongChar = convertChar(tempLine.linea[i].specialChar, tempLine.linea[i].ch);         // Special character\n            fprintf(filePointer, \"%lc\", tempLongChar); \n\t  }else{\t\t \n            //regular ASCII char\n            fprintf(filePointer, \"%c\", tempLine.linea[i].ch); \n\t  }\n      }\n      fprintf(filePointer,\"%c\" , END_LINE_CHAR);\n  }\n  closeFile(filePointer);\n\n\t   fileModified = FILE_UNMODIFIED;\n  }\n};\n\nint editor_section(char ch){\nchar accentchar[2];\nint insertMode=0;\nVLINES *aux = NULL;\nVLINES splitLine = {0};\nint i,j=0;\nint attrib=EDIT_FORECOLOR;\nchar newch=0;\nint endLine=0;\n       \n       if (fileModified==FILE_UNMODIFIED) fileModified= FILE_MODIFIED;\n       //Check whether we are on Readmode\n       // if (fileModified != FILE_READMODE) {\n       //if ((ch > 31 && ch < 127) || ch < 0) {\n\n       // A KEY IS PRESSED AND ADDED TO EDIT BUFFER\n       // FIRST check for negative chars and special characters\n        newch=ch;\n        accentchar[0] = 0;\n        accentchar[1] = newch;\n       //Check whether we are on Readmode\n       // if (fileModified != FILE_READMODE) {\n     //Process normal printable chars first\n     if (ch == 27) return 0;\n\n     if ((ch > 31 && ch < 127) || ch < 0) {\n\tif (ch < 0) {\n\t    read_accent(&newch, accentchar);\n\t    newch = accentchar[1];\n      }\n      //if ((posBufX != endLine) && (shiftH>0)) return 0;\n      //check if we are at the limit of our display to print chars\n      if (cursorX < new_columns-2) cursorX++;\n      if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {shiftH++;}\n      //write_num(screen1,20,2,currentLine,B_CYAN,F_WHITE,1);\n      //SYNTAX HIGHLIGHTING DEMO\n      //Highlight numbers in GREEN\n      if ((accentchar[1] >= 48) && (accentchar[1] <=57)) attrib = FH_GREEN; \n      //Highlight special characters in CYAN\n      \n      if ((accentchar[1] >= 33) && (accentchar[1] <=47)) attrib = FH_CYAN; \n      aux = _getObject(edBuf1, posBufY);\n      if ((accentchar[1] >= 58) && (accentchar[1] <=64)) attrib = FH_CYAN; \n      aux = _getObject(edBuf1, posBufY);\n      if ((accentchar[1] >= 91) && (accentchar[1] <=96)) attrib = FH_CYAN; \n      aux = _getObject(edBuf1, posBufY); \n      if ((accentchar[1] >= 123) && (accentchar[1] <=126)) attrib = FH_CYAN; \n      aux = _getObject(edBuf1, posBufY);\n\n      //FIRST TIME -> CREATE LINES IN BUFFER\n      if (aux == NULL) {\n\t//FIRST CHAR - if not we create a new line in buffer\n\n      \ttempLine.index = posBufY;\n\t//Add spaces if cursor is not at (0,0)\n \tif (posBufX != 0) {\n\t\tfor (i=0; i<posBufX; i++) {\n\t\t\ttempLine.linea[i].ch = FILL_CHAR;\n        \t\ttempLine.linea[i].specialChar = 0;\n\t\t\ttempLine.linea[i].attrib = EDIT_FORECOLOR;\n\t\t}\n\t}\t\n\ttempLine.linea[posBufX].ch = accentchar[1];\n        tempLine.linea[posBufX].specialChar = accentchar[0];\n        tempLine.linea[posBufX].attrib = attrib;\n\t//add end_line_char to line\n\tposBufX = posBufX + 1;\n\ttempLine.linea[posBufX].ch = END_LINE_CHAR;\n        tempLine.linea[posBufX].specialChar = 0;\n        tempLine.linea[posBufX].attrib = attrib;\n\tedBuf1 = _addatend(edBuf1, _newline(tempLine));\n\tlinetoScreenRAW(cursorY,tempLine);          \n\n     } else\n\t//LINE ALREADY EXISTS\n\t{\n\t//Locate the end of the line\n\tendLine = findEndline(tempLine);\n\n\t//Insert characters in the middle of other characters\n\tif (endLine > posBufX) {\n\n\t   tempLine.index = posBufY; //with every line index is incremented\n\t   if (insertMode == FALSE){\n\t     for (i=endLine; i>=posBufX; i--){ \n                 tempLine.linea[i+1].ch = tempLine.linea[i].ch;\n                 tempLine.linea[i+1].specialChar = tempLine.linea[i].specialChar;\n                 tempLine.linea[i+1].attrib = tempLine.linea[i].attrib;\n              }\n\t    }\n             tempLine.linea[posBufX].ch = accentchar[1];\n             tempLine.linea[posBufX].specialChar = accentchar[0];\n             tempLine.linea[posBufX].attrib = attrib;\n              posBufX = posBufX + 1;\n             _updateLine(edBuf1, posBufY, &tempLine);\n\t     linetoScreenRAW(cursorY,tempLine);\t\n\t     \t\n\t}\n          \t\n\telse {\n\t  // POSBUFX >= ENDLINE: Cursor is at the end or further away from latest text\n          //ADD SPACES IF CURSOR IS NOT AT THE END OF THE LINE AND LINE ALREADY EXISTS\n\t  if(posBufX > endLine) {\t  \n\t    for(i = endLine; i < posBufX; i++) {\n\t     tempLine.linea[i].ch = FILL_CHAR;\n             tempLine.linea[i].specialChar = 0;\n\t     tempLine.linea[i].attrib = EDIT_FORECOLOR;\n\t   } \n          }\n\t  tempLine.linea[posBufX].ch = accentchar[1];\n          tempLine.linea[posBufX].specialChar = accentchar[0];\n          tempLine.linea[posBufX].attrib = attrib;\n\t   posBufX = posBufX + 1;\n\t  tempLine.linea[posBufX].ch = END_LINE_CHAR;\n          tempLine.linea[posBufX].specialChar = 0;\n          tempLine.linea[posBufX].attrib = attrib;\n\t  _updateLine(edBuf1, posBufY, &tempLine);  \n\t  linetoScreenRAW(cursorY,tempLine);\n\t  //the cursor returns to its place when scrolling horizontally\n          if (posBufX < MAX_LINE_SIZE && cursorX == new_columns-2) {cursorX--;}\n         }\n      }\n\tif (shiftH>0){\n\t\tbuffertoScreen(1);\n\t}\n\n    }\n    //record previous values\n    old_cursorX = cursorX;\n    old_cursorY = cursorY;\n    oldposBufX = posBufX;\n    oldposBufY = posBufY;\n    oldEndLine = endLine;\n   //HANDLE ENTER KEY \n\n   if (ch == K_ENTER) {\n    // ENTER key\n    update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL);\n\n    // Move cursor down if not at the bottom of the screen\n    if (cursorY < new_rows - 3) {\n        cursorY++;\n    }\n    cursorX = START_CURSOR_X;\n\n    // If the buffer pointer is at the end, create a new empty line\n    if (_length(&edBuf1) <= posBufY) {\n        // Create a new line without characters in the current line in the edit buffer\n        memset(&tempLine, '\\0', sizeof(tempLine));\n        tempLine.index = _length(&edBuf1);\n        tempLine.linea[0].ch = END_LINE_CHAR;\n        tempLine.linea[0].specialChar = 0;\n        tempLine.linea[0].attrib = 0;\n        edBuf1 = _addatend(edBuf1, _newline(tempLine));\n    } else {\n        // SPLIT LINE INTO TWO\n        _dumpLine(edBuf1, posBufY, &tempLine);\n        endLine = findEndline(tempLine);\n\n        // Create a new line to insert the split content\n        memset(&splitLine, '\\0', sizeof(splitLine));\n        memset(&tempLine, '\\0', sizeof(tempLine));\n        tempLine.index = _length(&edBuf1);\n        edBuf1 = _addatend(edBuf1, _newline(tempLine));\n\n        // Move lines below the current line down by one\n        for (j = _length(&edBuf1) - 1; j > posBufY; j--) {\n            _dumpLine(edBuf1, j, &tempLine);\n            _updateLine(edBuf1, j + 1, &tempLine);\n            if (j + START_CURSOR_Y < new_rows - 3) {\n                cleanSection(j + START_CURSOR_Y, 0, findEndline(tempLine));\n            }\n        }\n\n        // Split the current line at the cursor position\n        _dumpLine(edBuf1, posBufY, &tempLine);\n        memset(&splitLine, '\\0', sizeof(splitLine));\n\n        // Copy characters before the cursor to the current line\n        for (i = 0; i < posBufX; i++) {\n            splitLine.linea[i].ch = tempLine.linea[i].ch;\n            splitLine.linea[i].specialChar = tempLine.linea[i].specialChar;\n            splitLine.linea[i].attrib = tempLine.linea[i].attrib;\n        }\n        if (isLineTerminated(splitLine) == FALSE) {\n            splitLine.linea[i].ch = END_LINE_CHAR;\n        }\n        _updateLine(edBuf1, posBufY, &splitLine);\n\n        // Move characters after the cursor to the next line\n        memset(&splitLine, '\\0', sizeof(splitLine));\n        j = 0;\n        for (i = posBufX; i < endLine; i++) {\n            splitLine.linea[j].ch = tempLine.linea[i].ch;\n            splitLine.linea[j].specialChar = tempLine.linea[i].specialChar;\n            splitLine.linea[j].attrib = tempLine.linea[i].attrib;\n            j++;\n        }\n        if (isLineTerminated(splitLine) == FALSE) {\n            splitLine.linea[j].ch = END_LINE_CHAR;\n        }\n\n        // Update the new line with the split content\n        _updateLine(edBuf1, posBufY + 1, &splitLine);\n\n        // Clean the screen for the current line and refresh the buffer\n        cleanSection(cursorY - 1, 0, findEndline(tempLine));\n        buffertoScreen(TRUE);\n    }\n\n    // Scroll if needed when cursor is at the bottom of the screen\n    if (_length(&edBuf1) > vdisplayArea && cursorY == new_rows - 3) {\n        buffertoScreen(1);\n        currentLine++;\n    }\n\n    // Move buffer pointer positions\n    posBufY++;\n    posBufX = 0;\n}\n\nif(ch == K_BACKSPACE) {\n    // BACKSPACE key\n    update_ch(cursorX, cursorY, ' ', EDITAREACOL, EDITAREACOL);\n\n    if (posBufX == findEndline(tempLine)) {\n        // Cursor is at the end of the line\n        tempLine.linea[posBufX-1].ch = 0;\n        tempLine.linea[posBufX-1].specialChar = 0;\n        tempLine.linea[posBufX-1].attrib = 0;\n    } else {\n        // Shift characters to the left if we are not at the end of the line\n        if (posBufX != 0) {\n            for(i = posBufX - 1; i < findEndline(tempLine) - 1; i++) {\n                tempLine.linea[i].ch = tempLine.linea[i + 1].ch;\n                tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar;\n                tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib;\n            }\n            // Clear the last character in the line\n            tempLine.linea[i].ch = 0;\n            tempLine.linea[i].specialChar = 0;\n            tempLine.linea[i].attrib = 0;\n        }\n    }\n\n    // Remove line if we continue pressing backspace at the beginning of a line\n    if(cursorX == START_CURSOR_X && cursorY > START_CURSOR_Y) {\n        if (posBufY > 0) {\n            memset(&tempLine, '\\0', sizeof(tempLine));\n            memset(&splitLine, '\\0', sizeof(splitLine));\n            _dumpLine(edBuf1, posBufY - 1, &tempLine);\n\n            if (findEndline(tempLine) < 1) {\n                // Previous line is empty, remove it\n                for (j = posBufY - 1; j < _length(&edBuf1) - 1; j++) {\n                    _dumpLine(edBuf1, j + 1, &tempLine);\n                    _hardupdateLINE(&edBuf1, j, tempLine);\n                }\n                _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);\n            } else {\n                // Merge two lines\n                endLine = findEndline(tempLine);\n                _dumpLine(edBuf1, posBufY, &splitLine);\n                \n                for (i = 0; i < findEndline(splitLine); i++) {\n                    tempLine.linea[endLine + i].ch = splitLine.linea[i].ch;\n                    tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib;\n                    tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar;\n                }\n                tempLine.linea[endLine + i].ch = END_LINE_CHAR;\n\n                _hardupdateLINE(&edBuf1, posBufY - 1, tempLine);\n\n                // Update subsequent lines\n                for (j = posBufY; j < _length(&edBuf1) - 1; j++) {\n                    _dumpLine(edBuf1, j + 1, &tempLine);\n                    _hardupdateLINE(&edBuf1, j, tempLine);\n                }\n                _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);\n            }\n\n            posBufY--;\n            cursorY--;\n            if (cursorY == new_rows - 3 && currentLine > 0) currentLine--;\n            buffertoScreen(1);\n            _dumpLine(edBuf1, posBufY, &tempLine);\n\n            // Adjust cursor position after merging lines\n            if (findEndline(splitLine) != 0 && findEndline(splitLine) != findEndline(tempLine)) {\n                posBufX = findEndline(tempLine) + 1;\n                cursorX = posBufX + START_CURSOR_X;\n            } else {\n                if (endLine != findEndline(tempLine)) {\n                    cursorX = START_CURSOR_X;\n                    posBufX = cursorX - 1;\n                } else {\n                    posBufX = findEndline(tempLine) + 1;\n                    cursorX = posBufX + START_CURSOR_X;\n                }\n            }\n        }\n    }\n\n    // Normal backspace within a line\n    if(cursorX > START_CURSOR_X) {     \n        cursorX--;\n        posBufX--;\n        _updateLine(edBuf1, posBufY, &tempLine);\n    }\n\n    // Clean up and refresh the line on screen\n    cleanSection(cursorY, findEndline(tempLine), 2);\n    linetoScreenRAW(cursorY, tempLine);\n}\n\nif (deleteKeyPressed == 1) {\n    deleteKeyPressed = 0;         \t    \n    // DEL key\n    if (posBufX == findEndline(tempLine)) {\n        // Cursor is at the end of the line\n        if (posBufY < _length(&edBuf1) - 1) {\n            // If there is a next line, merge it with the current line\n            _dumpLine(edBuf1, posBufY + 1, &splitLine);\n            endLine = findEndline(tempLine);\n            \n            // Copy the characters from the next line to the end of the current line\n            for (i = 0; i < findEndline(splitLine); i++) {\n                tempLine.linea[endLine + i].ch = splitLine.linea[i].ch;\n                tempLine.linea[endLine + i].attrib = splitLine.linea[i].attrib;\n                tempLine.linea[endLine + i].specialChar = splitLine.linea[i].specialChar;\n            }\n            tempLine.linea[endLine + i].ch = END_LINE_CHAR;\n            \n            // Update the buffer with the modified line\n            _hardupdateLINE(&edBuf1, posBufY, tempLine);\n            \n            // Remove the next line from the buffer\n            for (j = posBufY + 1; j < _length(&edBuf1); j++) {\n                _dumpLine(edBuf1, j + 1, &tempLine);\n                _hardupdateLINE(&edBuf1, j, tempLine);\n            }\n            _deleteObject(&edBuf1, _length(&edBuf1) - 1, FALSE);\n            \n            // Update the screen\n            buffertoScreen(1);\n        }\n    } else {\n        // Cursor is in the middle of the line, so delete the character at the cursor position\n        for (i = posBufX; i < findEndline(tempLine); i++) {\n            tempLine.linea[i].ch = tempLine.linea[i + 1].ch;\n            tempLine.linea[i].specialChar = tempLine.linea[i + 1].specialChar;\n            tempLine.linea[i].attrib = tempLine.linea[i + 1].attrib;\n        }\n        tempLine.linea[i].ch = 0; // Nullify the last character\n\n        // Update the buffer with the modified line\n        _updateLine(edBuf1, posBufY, &tempLine);\n\n        // Update the screen\n        cleanSection(cursorY, findEndline(tempLine), 2);\n        linetoScreenRAW(cursorY, tempLine);\n    }\n}\n\n    if(ch == K_TAB) {\n      //TAB key sends spaces for convenience\n      \t      for (i=posBufX; i<posBufX+TAB_SPACES; i++)\n\n\t\t{\n\t            tempLine.linea[i].ch = FILL_CHAR;\n                    tempLine.linea[i].specialChar = 0;\n                    tempLine.linea[i].attrib = EDIT_FORECOLOR;\n\t      }      \n\t      posBufX=posBufX + TAB_SPACES;\n\t      if (cursorX < new_columns-8) {\n                      for (i=0; i<TAB_SPACES; i++) update_ch(cursorX+i, cursorY, ' ', EDITAREACOL, EDITAREACOL);\n\t\t      cursorX = cursorX + TAB_SPACES;\n\t      }\n        _updateLine(edBuf1, posBufY, &tempLine);    \n     }\n\n   return 0; \n}\n\n/*------------------------------*/\n/* Open file and dump to buffer */\n/*------------------------------*/\n\nint filetoBuffer(char *fileName) { //EDBUF*\n  long     inlineChar = 0, lineCounter = 0;\n  //wchar_t tempLongChar = 0;\n  char    ch;\n  int attrib = EDIT_FORECOLOR;\n  fileModified = FILE_UNMODIFIED;\n  \n  openFile(&filePointer, fileName, \"r\");\n  memset(&tempLine, '\\0',sizeof(tempLine));\n  tempLine.index = 0;\n  if (edBuf1 != NULL) _deletetheList(&edBuf1);\n  edBuf1 = _addatend(edBuf1, _newline(tempLine));\n\n  //Check if pointer is valid\n  if(filePointer != NULL) {\n    rewind(filePointer);        //Make sure we are at the beginning\n    ch = getc(filePointer);     //Peek ahead in the file\n    while(!feof(filePointer)) {\n      if(ch != '\\0') {\n    //Temporary restrictions until scroll is implemented.\n    //if(lineCounter == rows - 4)\n    //  break;\n\n    if(ch == SPECIAL_CHARS_SET1 || ch == SPECIAL_CHARS_SET2) {\n      tempLine.linea[inlineChar].specialChar = ch;\n      //Read accents\n      ch = getc(filePointer);\n      tempLine.linea[inlineChar].ch = ch;\n    } else {\n      if(ch > 0)\n       tempLine.linea[inlineChar].ch = ch;\n    }\n       //SYNTAX HIGHLIGHTING DEMO\n      //Highlight numbers in GREEN\n      attrib = EDIT_FORECOLOR;\n      if ((ch >= 48) && (ch <=57)) attrib = FH_GREEN; \n      //Highlight special characters in CYAN\n      \n      if ((ch >= 33) && (ch <=47)) attrib = FH_CYAN; \n      if ((ch >= 58) && (ch <=64)) attrib = FH_CYAN; \n      if ((ch >= 91) && (ch <=96)) attrib = FH_CYAN; \n      if ((ch >= 123) && (ch <=126)) attrib = FH_CYAN; \n\n   \n     tempLine.linea[inlineChar].attrib = attrib;\n        //TABs are converted into spaces\n      /*  if(ch == K_TAB) {\n        for (tabcount=0;tabcount<TAB_DISTANCE;tabcount++){\n          ch = FILL_CHAR;\n          writetoBuffer(editBuffer, inlineChar, lineCounter, ch);\n          inlineChar++;\n        }*/\n\n    inlineChar++; //NEXT CHARACTER\n\n    if(ch == END_LINE_CHAR) {\n      inlineChar = 0;\n      ch = 0;\n      _updateLine(edBuf1, lineCounter, &tempLine);\n      lineCounter++;\n      memset(&tempLine, '\\0',sizeof(tempLine));\n      tempLine.index = _length(&edBuf1);\n      edBuf1 = _addatend(edBuf1, _newline(tempLine));\n    }\n       if (lineCounter == MAX_LINES) {\n           //open as readMode\n           fileModified = FILE_READMODE;\n           break;\n       }\n       //If file is bigger than buffer\n      //break loop at last allowed line.\n      }\n      ch = getc(filePointer);\n    }\n  }\n  closeFile(filePointer);\n  return 1;\n}\n\nvoid flush_editarea(int force_update) {\nint i;\n  //Paint blue edit area\n  //draw_screen();\n  screen_color(screen1, EDITAREACOL, EDITAREACOL, FILL_CHAR);\n  //Draw upper and lower bars\n    for(i = 0; i < old_columns; i++) {\n     write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0);\n    }\n\n  for(i = 0; i < old_columns; i++) {\n    write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1);\n  }\n  // Text messages\n  write_str(screen1, 0, 1, \"File  Options  Help\", MENU_PANEL, MENU_FOREGROUND0,0);\n  write_str(screen1, 0, 1, \"F\", MENU_PANEL, F_RED,0);\n  write_str(screen1, 7, 1, \"p\", MENU_PANEL, F_RED,0);\n  write_str(screen1, 15, 1, \"H\", MENU_PANEL, F_RED,0);\n  write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0);\n\n  /* Frames */\n  //window appearance and scroll bar\n  for(i = 2; i < old_rows; i++) {\n    write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0);\t//Scroll bar\n    write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//upper vertical line box-like char \n  }\n  for(i = 0; i < old_columns; i++) {\n    write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//horizontal line box-like char\n    write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0);\n  }\n  write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//upper-left box-like char\n  //horizontal scroll bar\n  for(i = 0; i < old_columns; i++) {\n    write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0);\n  }\n  //Window-appearance\n  write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//right window corner\n  write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK,\n\t   EDITWINDOW_FORE,0);\n  write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK,\n\t   EDITWINDOW_FORE,0);\n\n  //Scroll symbols\n  write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);\n  write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);\n  write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  if (strlen(fileName) == 0) strcpy(fileName,\"UNTITLED\");\n  write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName,\n        MENU_PANEL, MENU_FOREGROUND0,0);\n if (force_update) dump_screen(screen1);\n}\n"
  },
  {
    "path": "src/editor.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule with main editor in C·edit\n@author : Velorek\n@version : 1.0\nLast modified: 06/04/2024\n========================================================================\n*/\n\n#ifndef _EDITOR_H_\n#define _EDITOR_H_\n\n#include \"scbuf.h\"\n#include \"global.h\"\n#include \"edbuf.h\"\n#include <stdio.h>\nint process_input(char ch);\nint special_keys();\nint control_keys(char ch);\nvoid linetoScreen(long whereY, VLINES tempLine);\nvoid linetoScreenRAW(long whereY, VLINES tempLine);\nvoid cleanScreenLine(long whereY);\nvoid cleanSection(long whereY, long start, int amount);\nvoid buffertoScreen(BOOL raw);\nint editor_section(char ch);\nwchar_t convertChar(char c1, char c2);\n//int filetoBuffer(FILE * filePtr);\nvoid buffertoFile(char *fileName);\nint filetoBuffer(char *fileName);\nvoid flush_editarea(int force_update);\n#endif\n\n\n"
  },
  {
    "path": "src/fileb.c",
    "content": "/* \n======================================================================\nModule to describe basic file operations.\n\n@author : Velorek\n@version : 1.0\n \nLAST MODIFIED : 14/04/2019 - Rename headers \n======================================================================\n*/\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <stdio.h>\n#include \"global.h\"\n#include \"fileb.h\"\n/*====================================================================*/\n/* FUNCTIONS - CODE                                                   */\n/*====================================================================*/\n\n/*----------------------*/\n/* Check if file exists */\n/*----------------------*/\n\nint file_exists(char *fileName) {\n  int     ok=0;\n  if(access(fileName, F_OK) != -1) {\n    ok = 1;\t\t\t//File exists\n  } else {\n    ok = 0;\n  }\n  return ok;\n}\n\n/*---------------*/\n/* Get file size */\n/*---------------*/\n\nlong getfileSize(FILE * filePtr) {\n  long    sz=0;\n  if(filePtr != NULL) {\n    fseek(filePtr, 0L, SEEK_END);\n    sz = ftell(filePtr);\n    rewind(filePtr);\n  }\n\n  return sz;\n}\n\n/*---------------------*/\n/* Count lines in File */\n/*---------------------*/\n\nlong countLinesFile(FILE * filePtr) {\n  char    ch=0;\n  long    counterA = 0;\n  if(filePtr != NULL) {\n    rewind(filePtr);\t\t//Make sure we are at the beginning\n\n    ch = getc(filePtr);\t\t//Peek ahead in the file\n    while(!feof(filePtr)) {\n      if(ch == END_LINE_CHAR) {\n\tcounterA++;\n      }\n      ch = getc(filePtr);\n    }\n  }\n  return counterA;\n}\n\n/*-----------------*/\n/* Check file type */\n/*-----------------*/\n\n\nlong checkFile(FILE * filePtr) {\n  char    ch=0;\n  long    counterA = 0;\n  if(filePtr != NULL) {\n    rewind(filePtr);\t\t//Make sure we are at the beginning\n\n    ch = getc(filePtr);\t\t//Peek ahead in the file\n    while(!feof(filePtr)) {\n      if(ch < 9) {\n\t//discard accents\n\tif(ch > -60)\n\t  counterA++;\n      }\n      ch = getc(filePtr);\n    }\n  }\n  return counterA;\n}\n\n//check whether the file is a text file\nint openandcheckFile(char *fileName) {\n  unsigned char    ch=0;\n  long    counterA = 0;\n  FILE *fp;\n\n  openFile(&fp, fileName, \"r\");\n  if(fp != NULL) {\n    rewind(fp);\t\t//Make sure we are at the beginning\n\n    ch = getc(fp);\t\t//Peek ahead in the file\n    while(!feof(fp)) {\n \n      if (ch == 0x00) {closeFile(fp); fp = NULL; return 1;}\n      if(ch < 9) {\n\t//discard accents\n\tif(ch > 196)\n\t  counterA++;\n      }\n      ch = getc(fp);\n    }\n  }\n  //If there are more strange characters than half the size of the file probably a binary file\n  if (counterA > (getfileSize(fp)/2)) {\n     if (fp != NULL) closeFile(fp); \n     fp = NULL;\n  return 1;\n  }\n   if (fp != NULL) closeFile(fp);\n    fp = NULL; \n  return 0;\n}\n/*-----------*/\n/* Open file */\n/*-----------*/\n\nint openFile(FILE ** filePtr, char fileName[], char *mode)\n/* \nOpen file.\n@return ok = 1 ? 0 Success! \n*/\n{\n  int     ok = 0;\n  *filePtr = fopen(fileName, mode);\n\n  if(*filePtr != NULL) {\n    //File opened correctly.\n    ok = 1;\n  } else {\n    //Error\n    ok = 0;\n  }\n  return ok;\n}\n\n/*------------*/\n/* Close file */\n/*------------*/\n\nint closeFile(FILE * filePtr) {\n/* \n   Close file\n@return ok: \n*/\n  int     ok=0;\n\n  if(filePtr != NULL) {\n    ok = fclose(filePtr);\n  }\n\n  return ok;\n}\n\n"
  },
  {
    "path": "src/fileb.h",
    "content": "/*\n========================================================================\n- HEADER - \nModule to handle basic file operations\n@author : Velorek\n@version : 1.0  \nLast modified: 31/08/2025 Open and check file                                                           \n========================================================================\n*/\n\n#ifndef _FILEB_H_\n#define _FILEB_H_\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <stdio.h>\n#include \"scbuf.h\"\n\n/*====================================================================*/\n/* CONSTANTS                                                          */\n/*====================================================================*/\n#define CONFIGFILE \"cedit.cfg\"\n\n/*====================================================================*/\n/* FUNCTION PROTOTYPES                                                */\n/*====================================================================*/\n\nint     openFile(FILE ** filePtr, char fileName[], char *mode);\nint     closeFile(FILE * filePtr);\nlong    getfileSize(FILE * filePtr);\nlong    countLinesFile(FILE * filePtr);\nlong    checkFile(FILE * filePtr);\nint     openandcheckFile(char *fileName);\nint     file_exists(char *fileName);\n\n#endif\n"
  },
  {
    "path": "src/global.c",
    "content": "#include \"global.h\"\n#include \"rterm.h\"\n#include \"time.h\"\n\n// GLOBALS : SCREEN1 : ANIMATED | SCREEN2 : BASE SCREEN\nLISTCHOICE *listBox1 = NULL;\nSCREENCELL *screen1=NULL;\nSCREENCELL *screen2=NULL;\nSCREENCELL *screen3=NULL;\nNTIMER cursor_timer1;\nNTIMER timer2;\nNTIMER timer3;\n//NTIMER timer4;\nSCROLLDATA scrollData;\nVLINES *edBuf1=NULL; //Buffer vector of lines(1022 chars)\nVLINES tempLine;\n\n//C-Edit Theme\nint EDITAREACOL= B_BLUE;\nint EDIT_FORECOLOR=FH_WHITE;\nint STATUSBAR =B_BLACK;\nint STATUSMSG =F_WHITE;\nint MENU_PANEL =B_WHITE;\nint MENU2_PANEL = B_BLACK;\nint MENU_SELECTOR =B_RED;\nint MENU_FOREGROUND0 =F_BLACK;\nint MENU2_FOREGROUND0 = F_WHITE;\nint MENU_FOREGROUND1= FH_WHITE;\nint EDITWINDOW_BACK= B_BLUE;\nint EDITWINDOW_FORE= F_WHITE;\nint SCROLLBAR_BACK= B_WHITE;\nint SCROLLBAR_FORE= FH_WHITE;\nint SCROLLBAR_SEL= B_CYAN;\nint SCROLLBAR_ARR= B_BLACK;\nint WINDOW_TITLEB = B_BLACK; \nint WINDOW_TITLEF = F_WHITE;\n\nint new_rows = 0, new_columns = 0, old_rows = 0, old_columns = 0;\t// Terminal dimensions\nint cursorX = START_CURSOR_X, cursorY = START_CURSOR_Y;\nint old_cursorX = START_CURSOR_X, old_cursorY = START_CURSOR_Y;\nlong posBufX = 0, posBufY = 0;\nlong oldposBufX = 0, oldposBufY = 0;\nlong shiftH = 0;\nint unwantedChars = 0; //try to avoid printing unwanted characgters from cursor chars counter\n\t\t\n//TEXT BUFFER POINTERS\nint  hdisplayLimit=0; //horizontal scroll, last char position in line that allows scroll\nint  currentColumn=0; //horizontal scroll, pointer to current char position in line\nlong linesinFile=0; //vertical scroll\nlong vdisplayLimit=0; //vertical scroll, last line that allows scroll\nint vdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes \nint hdisplayArea = 0; //size in lines of the allowed displayed area // calculated when screen resizes \nlong currentLine=0; //verticall scroll, pointer to current top line in scroll\nint vscrollActive=0; //vertical scroll, vertical scroll is posible\n//extern int hscrollActive; //horizontal scroll, horizontal scroll is posible\nint     programStatus = 0; //signal for overall program Status\nchar fileName[MAXFILENAME]; \nchar fullPath[MAXFILENAME]; \n\nFILE *filePointer;\nint fileModified=FILE_UNMODIFIED;\nint deleteKeyPressed = 0;         \t    \n\nchar aboutMSG[7][MAXLINE] = {ABOUT_ASC_0,ABOUT_ASC_1,ABOUT_ASC_2,ABOUT_ASC_3,ABOUT_ASC_4,ABOUT_ASC_5};\nchar help[HELPLINES][MAXLINE] = { HELP0,\n\tHELP1, HELP2, HELP3,\n\tHELP4, HELP5, HELP6,\n\tHELP7, HELP8, HELP9,\n\tHELP10, HELP11, HELP12,\n\tHELP13, HELP14, HELP15,\n\tHELP16, HELP17, HELP18,\n\tHELP19, HELP20\n};\nint initCEDIT(){\n   get_terminal_dimensions(&new_rows,&new_columns);\n   //Init timer\n   init_timer(&cursor_timer1,TIMER_SPEED);\n   init_timer(&timer2,TIMER_SPEED2);\n   init_timer(&timer3,TIMER_SPEED3);\n   //init_timer(&timer4,ABOUT_SPEED);\n   timer2.ticks=0;\n   timer3.ticks=-1;\n   //timer4.ticks=0;\n   cursor_timer1.ticks=0;\n   //Init Text buffer\n   VLINES tempLine = {0};\n  \n   memset(&fileName, '\\0',sizeof(fileName)); //Clear fileName\n   memset(&tempLine, '\\0',sizeof(tempLine)); //Clear memory for temporary line\n   //Create one screen in memory\n   if (screen1 != NULL) deleteList(&screen1);\n   if (screen2 != NULL) deleteList(&screen2);\n     //Init 2 : Create 2 Screens for a double buffer  approach  \n   old_rows=new_rows;\n   old_columns=new_columns;\n   create_screen(&screen1);\n   create_screen(&screen2);\n   //how many lines are vertical display area consists of\n   vdisplayArea = new_rows - 4;\n   hdisplayArea = new_columns - 2;\t\n   shiftH=0; \n   return 0;\n}\t\n\nint _animation(){ \n/* Timer for animations - Display time and clean cursor */\n  time_t  mytime = time(NULL);\n  char   *time_str = ctime(&mytime);\n  char    temp[4];\n\n  temp[0] = '[';\n  temp[1] = ANIMATION[timer2.ticks];\n  temp[2] = ']';\n  temp[3] = '\\0';\n    get_terminal_dimensions(&new_rows,&new_columns);\n    resetAnsi(0);\n    time_str[strlen(time_str) - 1] = '\\0';\n    //display system time\n    update_str(new_columns - strlen(time_str) - 1, 0, time_str, MENU_PANEL,\n          MENU_FOREGROUND0);\n    update_str(new_columns - strlen(time_str) - 5, 0, temp, MENU_PANEL,\n          MENU_FOREGROUND0);\n    printf(\"\\n\");\n    //update only the screen bits that change\n    if(timer2.ticks > 6)\n      timer2.ticks = 0;\n    //return a signal if screen size changes\n     if (new_rows != old_rows || new_columns != old_columns)\n\t\treturn -1;\n\telse\n\t\treturn 0;\n   \n    \n\n}\n\n\n"
  },
  {
    "path": "src/global.h",
    "content": "/*\n * Global variables are intented to be placed here\n * Last modified: 9/7/2022\n * @author: velorek\n *\n */\n#ifndef _GLOBAL_H_\n#define _GLOBAL_H_\n#include \"scbuf.h\"\n#include \"tm.h\"\n#include \"edbuf.h\" \n#include \"listbox.h\" \n\n#define TIMER_SPEED 100 //animation\n#define TIMER_SPEED2 30 //cursor\n#define TIMER_SPEED3 100 //temporary messages\n//#define ABOUT_SPEED 300 //about animation\n#define END_LINE_CHAR 0x0A\n#define FILL_CHAR 0x20\n#define ENDSIGNAL -1\n#define ESC_KEY '\\e'\n#define ROWS_FAILSAFE 25\n#define COLUMNS_FAILSAFE 80 \n#define TRUE 1\n#define FALSE 0\n#define CURSOR_CHAR '|'\ntypedef int BOOL;\n\n//USER-DEFINED MESSAGES\nextern SCREENCELL *screen1;\nextern SCREENCELL *screen2;\nextern NTIMER cursor_timer1;\nextern NTIMER timer2;\nextern NTIMER timer3;\n//extern NTIMER timer4;\nextern size_t animation;\nextern int centerX;\n//extern LISTCHOICE listBox1;\nextern SCROLLDATA scrollData;\nextern VLINES *edBuf1; //Buffer vector of lines(512 chars)\nextern VLINES tempLine;\n\n//COLOR SCHEME\nextern int EDITAREACOL;\nextern int EDIT_FORECOLOR;\nextern int STATUSBAR;\nextern int STATUSMSG;\nextern int MENU_PANEL;\nextern int MENU2_PANEL;\nextern int MENU_SELECTOR;\nextern int MENU_FOREGROUND0;\nextern int MENU2_FOREGROUND0;\nextern int MENU_FOREGROUND1;\nextern int EDITWINDOW_BACK;\nextern int EDITWINDOW_FORE;\nextern int SCROLLBAR_BACK;\nextern int SCROLLBAR_FORE;\nextern int SCROLLBAR_SEL;\nextern int SCROLLBAR_ARR;\nextern int WINDOW_TITLEB; // to be accessible from opfile.c\nextern int WINDOW_TITLEF;\n\n//GOODBYE MSG - ASCII ART\n#define cedit_ascii_1 \"  _____      ______    _ _ _   \\n\"\n#define cedit_ascii_2 \" / ____|    |  ____|  | (_) |  \\n\"\n#define cedit_ascii_3 \"| |   ______| |__   __| |_| |_ \\n\"\n#define cedit_ascii_4 \"| |  |______|  __| / _` | | __|\\n\"\n#define cedit_ascii_5 \"| |____     | |___| (_| | | |_ \\n\"\n#define cedit_ascii_6 \" \\\\_____|    |______\\\\__,_|_|\\\\__|\\n\"\n#define TAB_SPACES 8\n\n//ABOUT - ASCII ART\n#define ABOUT_ASC_0 \"______________________________\"       \n#define ABOUT_ASC_1 \"        _   __                \"\n#define ABOUT_ASC_2 \"       /  _|__ _|.___         \"\n#define ABOUT_ASC_3 \"       \\\\_  |__(_]| |  v0.1   \"       \n#define ABOUT_ASC_4 \"______________________________\"       \n#define ABOUT_ASC_5 \"      Coded   by  V3l0rek     \"\n#define ANIMATION \"||//--\\\\\\\\\"\n\n#define HELP0 \"C-EDIT                                             \\0\"\n#define HELP1 \"=======                                            \\0\"\n#define HELP2 \"C-EDIT is a terminal TUI curses text editor.       \\0\"\n#define HELP3 \"It offers both vertical and horizontal scroll      \\0\"\n#define HELP4 \"for file buffer navigation. It also features a     \\0\"\n#define HELP5 \"variety of animations and has a built-in open file \\0\"\n#define HELP6 \"dialog to easily locate the files in directories.  \\0\"\n#define HELP7 \"___________________________________________________\\0\"\n#define HELP8 \"[F1] or [ALT + H] -> Display help                  \\0\"\n#define HELP9 \"[F2] or [CTRL + L] -> Activate menu                \\0\"\n#define HELP10 \"[Arrow Keys] -> Navigate file buffer              \\0\"\n#define HELP11 \"[CTRL + A] -> Quick Load  | CTRL + N -> New file  \\0\"\n#define HELP12 \"[ALT + O] -> Open file    |                       \\0\"\n#define HELP13 \"[ALT + S] -> Save file                             \\0\"\n#define HELP14 \"[ESC] or [CTRL + C] or [ALT+X] -> Exit program     \\0\"\n#define HELP15 \"[S] Hide/Show table | CTRL or ALT may be used.     \\0\"\n#define HELP16 \"___________________________________________________\\0\"\n#define HELP17 \"This program was coded in C & Vim from 2018-2024.  \\0\"\n#define HELP18 \"Some of the techniques used can be found in my     \\0\"\n#define HELP19 \"personal blog : oldstuff286.blogspot.com           \\0\"\n#define HELP20 \"Peace!  - by v3l0r3k                               \\0\"\n#define HELPLINES 21\n\n//USER-DEFINED MESSAGES\n#define UNKNOWN \"UNTITLED\"\n#define WINDOWMSG \"DISPLAY IS TOO SMALL. PLEASE, RESIZE WINDOW\"\n#define STATUS_BAR_MSG1  \" [C-Edit] | F2,CTRL+L: MENU | F1: HELP\"\n#define STATUS_BAR_MSG2 \" [C-Edit] Press ESC to exit menu.             \"\n#define STATUS_BAR_MSG3 \" ENTER: SELECT | <- -> ARROW KEYS             \"\n#define WLEAVE_MSG \"\\n       Are you sure\\n    you want to quit?\"\n#define WSAVE_MSG \":\\nFile saved successfully!\"\n#define WSAVELABEL_MSG \"[-] File:\"\n#define WINFO_NOPEN \"Error:\\nThere isn't any file open!\"\n#define WINFO_SIZE \"-File size: \"\n#define WINFO_SIZE2 \"\\n-No. of lines: \"\n#define WINFO_SIZE3 \"\\n-File name: \"\n#define WCHECKFILE2_MSG \" File does not exist!  \\n\\n A new buffer will be created. \\n\"\n#define WCHECKFILE_MSG \" This file isn't a|text file. Program may crash.|Open anyway?\"\n#define WINFONOTYET_MSG \"Not implemented yet!\"\n#define WCHECKLINES_MSG \" File longer than 3000 \\n lines. You'll view those \\n lines as read Mode! \"\n#define WMODIFIED_MSG \"File has been modified|Save current buffer?\"\n#define WFILEEXISTS_MSG \" File exists. \\n Overwrite?\"\n#define WFILEINREADMODE_MSG \" File is on read mode. \\n\"\n\n#define START_CURSOR_X 1\n#define START_CURSOR_Y 2\n\n//MENU CONSTANTS\n#define HOR_MENU -1\n#define FILE_MENU 0\n#define OPT_MENU 1\n#define HELP_MENU 2\n#define YESNO_MENU 3\n#define OK_MENU 4\n#define MAX_FILENAME 255\n#define MAX_LINES 100000\n#define MAXLINE 255\n\n//DROP-DOWN MENUS\n#define OPTION_1 0\n#define OPTION_2 1\n#define OPTION_3 2\n#define OPTION_4 3\n#define OPTION_5 4\n#define OPTION_6 5\n#define OPTION_NIL -1\t\t//Reset option\n#define CONFIRMATION 1\n#define K_LEFTMENU -1\t\t//Left arrow key pressed while in menu\n#define K_RIGHTMENU -2\t\t//Right arrow key pressed while in menu\n#define DONT_UPDATE -5\n//MENU CONSTANTS\n#define HOR_MENU -1\n#define FILE_MENU 0\n#define OPT_MENU 1\n#define HELP_MENU 2\n#define YESNO_MENU 3\n#define OK_MENU 4\n#define MAXFILENAME 100\n#define OK_MENU2 5\n#define COLORS_MENU 6\n\n//FILE CONSTANTS\n#define FILE_MODIFIED 1\n#define FILE_UNMODIFIED 0\n#define FILE_READMODE 2\nextern char aboutMSG[7][MAXLINE];\nextern char help[HELPLINES][MAXLINE];\n\nextern int new_rows, new_columns, old_rows, old_columns;\t// Terminal dimensions\nextern int cursorX, cursorY; //position on screen X:[0, columns -2] Y:[0, rows-3]\nextern int old_cursorX, old_cursorY;\nextern long posBufX, posBufY; //position in the edit buffer X:[0,1022] Y:[0,13000]\nextern long oldposBufX, oldposBufY; //position in the edit buffer X:[0,1022] Y:[0,13000]\nextern long shiftH; //for horizontal scroll\nextern int unwantedChars;\nint _animation();\nint initCEDIT(); \n\n\n//TEXT BUFFER POINTERS\nextern VLINES *edBuf1; //Buffer vector of lines(1022 chars)\nextern VLINES tempLine;\n\nextern FILE *filePointer;\nextern int vdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes \nextern int hdisplayArea; //size in lines of the allowed displayed area // calculated when screen resizes \nextern int  hdisplayLimit; //horizontal scroll, last char position in line that allows scroll\nextern int  currentColumn; //horizontal scroll, pointer to current char position in line\nextern long linesinFile; //vertical scroll\nextern long vdisplayLimit; //vertical scroll, last line that allows scroll\nextern long currentLine; //verticall scroll, pointer to current top line in scroll\nextern int vscrollActive; //vertical scroll, vertical scroll is posible\nextern int programStatus; //signal for overall program status\nextern char fileName[MAXFILENAME]; \nextern char fullPath[MAXFILENAME]; \nextern int fileModified;\nextern int deleteKeyPressed;         \t    \n//extern int hscrollActive; //horizontal scroll, horizontal scroll is posible\n\n\n\n\n#endif\n"
  },
  {
    "path": "src/keyb.c",
    "content": "/*\n======================================================================\nModule to control keyboard input.\n\n@author : Velorek\n@version : 1.0\n\nLAST MODIFIED : 14/04/2019 Rename headers\n======================================================================\n*/\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <stdio.h>\n#include \"rterm.h\"\n#include \"keyb.h\"\n\n/*====================================================================*/\n/* FUNCTIONS - CODE                                                   */\n/*====================================================================*/\n\n/*----------------------------------*/\n/* Read ESC-key char with its trail */\n/*----------------------------------*/\n\nint read_keytrail(char chartrail[5]){\n/*\n   New implementation: Trail of chars found in keyboard.c\n   If K_ESCAPE is captured read a trail up to 5 characters from the console.\n   This is to control the fact that some keys may change\n   according to the terminal and expand the editor's possibilities.\n   Eg: F2 can be either 27 79 81 or 27 91 91 82.\n*/\nchar ch;\nint i;\n   chartrail[0] = K_ESCAPE;\n   for(i = 1; i < 5; i++) {\n     if(kbhit(1) == 1) {\n        ch=readch();\n        chartrail[i] = ch;\n     } else {\n        chartrail[i] = 0;\n     }\n   }\n   resetch();\n   return 1;\n}\n\n/*----------------------------------*/\n/* Read Accents and Special Chars   */\n/*----------------------------------*/\n\n\nint read_accent(char *ch, char accentchar[2])\n{\n/*\nInput Ref: ch, accentchar\n@return : 1 - SET 1 | 2 - SET 2 | 0 - NO ACCENT CHAR\n*/\n  int result;\n  result = 0;\n    //Accents and special chars\n   accentchar[0] = 0;\n   accentchar[1] = *ch;\n    if(*ch == SPECIAL_CHARS_SET1) {\n      accentchar[0] = SPECIAL_CHARS_SET1;   //Accents and special chars SET1\n      accentchar[1] = readch();\n      result = 1;\n      resetch();\n    }\n    if(*ch == SPECIAL_CHARS_SET2) {\n      accentchar[0] = SPECIAL_CHARS_SET2;   //Accents and special chars SET2\n      accentchar[1] = readch();\n      result = 2;\n      resetch();\n    }\n    return result;\n}\n"
  },
  {
    "path": "src/keyb.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule to handle keyboard input in Linux and create\na further layer of abstraction.\n@author : Velorek\n@version : 1.0\nLast modified: 14/04/2019 Rename Headers\n========================================================================\n*/\n\n#ifndef _KEYB_H_\n#define _KEYB_H_\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <stdio.h>\n#include \"rterm.h\"\n\n/*====================================================================*/\n/* KEYS - CONSTANTS                                                   */\n/*====================================================================*/\n\n#define K_ENTER 13\n#define K_CAPS 91\n#define K_BACKSPACE 127\n#define K_TAB 9\n#define K_ESCAPE 27\n\n#define K_F1_TRAIL \"\\eOP\\0\\0\"\n#define K_F1_TRAIL2 \"\\e[[A\\0\"\n#define K_F2_TRAIL \"\\eOQ\\0\\0\"\n#define K_F2_TRAIL2 \"\\e[[B\\0\"\n#define K_F3_TRAIL \"\\eOR\\0\\0\"\n#define K_F3_TRAIL2 \"\\e[[C\\0\"\n#define K_F4_TRAIL \"\\eOS\\0\\0\"\n#define K_F4_TRAIL2 \"\\e[[D\\0\"\n\n#define K_UP_TRAIL \"\\e[A\\0\\0\"\n#define K_DOWN_TRAIL \"\\e[B\\0\\0\"\n#define K_RIGHT_TRAIL \"\\e[C\\0\\0\"\n#define K_LEFT_TRAIL \"\\e[D\\0\\0\"\n\n#define K_PAGEDOWN_TRAIL \"\\e[6~\"\n#define K_PAGEUP_TRAIL \"\\e[5~\"\n#define K_HOME_TRAIL \"\\e[H\"\n#define K_END_TRAIL \"\\e[F\"\n#define K_HOME_TRAIL2 \"\\e[1~\"\n#define K_END_TRAIL2 \"\\e[4~\"\n\n\n#define K_DELETE \"\\e[3~\"\n\n#define K_CTRL_A 0x01\n#define K_CTRL_B 0x02\n#define K_CTRL_C 0x03\n#define K_CTRL_D 0x04\n#define K_CTRL_E 0x05\n#define K_CTRL_J 0x0A\n#define K_CTRL_L 0x0C\n#define K_CTRL_H 0x08\n#define K_CTRL_M 0x0D\n#define K_CTRL_N 0x0E\n#define K_CTRL_O 0x0F\n#define K_CTRL_S 0x14\n\n#define K_ALT_X \"\\ex\"\n#define K_ALT_L \"\\el\"\n#define K_ALT_S \"\\es\"\n#define K_ALT_W \"\\ew\"\n#define K_ALT_H \"\\eh\"\n#define K_ALT_N \"\\en\"\n#define K_ALT_O \"\\eo\"\n#define K_ALT_W \"\\ew\"\n#define K_ALT_A \"\\ea\"\n#define K_ALT_I \"\\ei\"\n#define K_ALT_C \"\\ec\"\n#define K_ALT_F \"\\ef\"\n#define K_ALT_P \"\\ep\"\n#define K_ALT_S \"\\es\"\n#define K_ALT_V \"\\ev\"\n#define K_ALT_D \"\\ed\"\n#define ESC3X  \"\\e\\e\\e\"\n#define ESC2X  \"\\e\\e\"\n#define SPECIAL_CHARS_SET1 -61\n#define SPECIAL_CHARS_SET2 -62\n\n/*====================================================================*/\n/* FUNCTION PROTOTYPES                                                */\n/*====================================================================*/\n\nint     read_keytrail(char chartrail[5]);\nint     read_accent(char *ch, char accentchar[2]);\n\n#endif\n"
  },
  {
    "path": "src/listbox.c",
    "content": "/*====================================================================*/\n/* +ListBox with double linked list and selection menu in C with\n * horizontal scroll.\n   +Scroll function added. \n   Last modified : 01/04/2024 + Horizontal option implementation started\n   \t\t\t      + ESC_KEY added\n\t\t\t      + X,Y option added for different options\n\t\t\t      - Pending: horizontal scroll\n   Coded by Velorek. Raw output\n   Target OS: Linux.                                                  */\n/*====================================================================*/\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES */\n/*====================================================================*/\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"rterm.h\"\n#include \"listbox.h\"\n#include \"keyb.h\"\n#include \"tm.h\"\n#include \"global.h\"\n\n/*====================================================================*/\n/* CODE */\n/*====================================================================*/\nint double_escape=0;\nint selectorLimit = 15; //by default selectoLimit is 15 when spaces are added\nint newrows=0, newcolumns=0;\nint listrows=0, listcolumns=0;\nchar KTRAIL0[5]={0};\nchar KTRAIL1[5]={0};\n\n/* --------------------- */\n/* Dynamic List routines */\n/* --------------------- */\n\n// create new list element of type LISTCHOICE from the supplied text string\nLISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor) {\n  LISTCHOICE *newp;\n  newp = (LISTCHOICE *) malloc(sizeof(LISTCHOICE));\n  newp->item = (char *)malloc(strlen(text) + 1);\n  strcpy(newp->item, text);\n  newp->next = NULL;\n  newp->back = NULL;\n  newp->setX = setX;\n  newp->setY = setY;\n  newp->foreColor = foreColor;\n  newp->backColor = backColor;\n \n  return newp;\n}\n\n// deleleteList: remove list from memory\nvoid removeList(LISTCHOICE ** head) {\n  LISTCHOICE *aux = *head;\n  LISTCHOICE *next = NULL;\n  while(aux != NULL) {\n    next = aux->next;\n    free(aux->item);\n    free(aux);\t\t\t//remove item\n    aux = next;\n  }\n  *head = NULL;\n}\n\n/* addatend: add new LISTCHOICE to the end of a list  */\n/* usage example: listBox1 = (addatend(listBox1, newitem(\"Item\")); */\nLISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp) {\n  LISTCHOICE *p2;\n  if(head == NULL) {\n    newp->index = 0;\n    newp->back = NULL;\n    return newp;\n  }\n// now find the end of list\n  for(p2 = head; p2->next != NULL; p2 = p2->next) ;\n  p2->next = newp;\n  newp->back = p2;\n  newp->index = newp->back->index + 1;\n  return head;\n}\n\n/* ---------------- */\n/* Listbox routines */\n/* ---------------- */\n\nvoid gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,\n\t       unsigned indexAt)\n//Go to a specific location on the list.\n{\n  LISTCHOICE *aux2;\n  unsigned counter = 0;\n  *aux = listBox1;\n  aux2 = *aux;\n  while(counter != indexAt) {\n    aux2 = aux2->next;\n    counter++;\n  }\n  //Highlight current item\n\n  displayItem(aux2, scrollData, SELECT_ITEM);\n\n  //Update pointer\n  *aux = aux2;\n}\nvoid printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit) {\n/*\nDisplays the items contained in the list with the properties specified\nin scrollData.\n*/\n\n  LISTCHOICE *aux;\n  unsigned wherey, counter = 0;\n\n  aux = head;\n  gotoIndex(&aux, scrollData, 0);\n  /* Save values */\n  //wherex = scrollData->wherex;\n  wherey = scrollData->wherey;\n  do {\n    displayItem(aux, scrollData, UNSELECT_ITEM);\n    aux = aux->next;\n    counter++;\n    scrollData->selector++;\t// wherey++\n  } while(counter != displayLimit);\n  scrollData->selector = wherey;\t//restore value\n}\n\n\nvoid loadlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned indexAt) {\n/*\nDisplays the items contained in the list with the properties specified\nin scrollData.\n*/\n\n  LISTCHOICE *aux;\n  unsigned wherey, counter = 0;\n\n  aux = head;\n  gotoIndex(&aux, scrollData, indexAt);\n  /* Save values */\n  //wherex = scrollData->wherex;\n  wherey = scrollData->wherey;\n  do {\n    displayItem(aux, scrollData, UNSELECT_ITEM);\n    aux = aux->next;\n    counter++;\n    scrollData->selector++;\t// wherey++\n  } while(counter != scrollData->displayLimit);\n  scrollData->selector = wherey;\t//restore value\n}\n\nint query_length(LISTCHOICE ** head) {\n//Return no. items in a list.\n  {\n    LISTCHOICE *aux;\n\n    unsigned itemCount = 0;\n    aux = *head;\n    while(aux->next != NULL) {\n      aux = aux->next;\n      itemCount++;\n    }\n    return itemCount;\n  }\n\n}\n\nvoid displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select)\n//Select or unselect item animation\n{\n size_t i=0;\n wchar_t newchar=0;\n resetAnsi(0);\n  switch (select) {\n\n    case SELECT_ITEM:\n      if ((aux->setX == -1) || (aux->setY== -1 )) \t    \n        gotoxy(scrollData->wherex, scrollData->selector);\n      else\n        gotoxy(aux-> setX, aux -> setY);\n\n      if ((aux->foreColor == -1) || (aux->backColor== -1 )) \t    \n        outputcolor(scrollData->foreColor1, scrollData->backColor1);\n      else\n        outputcolor(aux->foreColor, aux->backColor);\n\n      //printf(\"%s\\n\", aux->item);\n      \n      for (i=0;i<scrollData->selectorLimit;i++) {\n              if(i < strlen(aux->item)){\n\t\t  newchar=aux->item[i];\n\t          printf(\"%lc\", newchar);\n\t      }\n\t      else\n\t        if (scrollData->addSpaces != 0) printf(\"%c\", 0x20);\n      }\n     printf(\"\\n\");\n     break;\n\n    case UNSELECT_ITEM:\n       if ((aux->setX == -1) || (aux->setY== -1 )) \t    \n         gotoxy(scrollData->wherex, scrollData->selector);\n       else\n         gotoxy(aux -> setX, aux -> setY);\n\n       outputcolor(scrollData->foreColor0, scrollData->backColor0);\n      //printf(\"%s\\n\", aux->item);\n      \n\n      for (i=0;i<scrollData->selectorLimit;i++) { \n\t      if(i < strlen(aux->item)){\n\t\t  newchar = aux->item[i];\n\t          printf(\"%lc\", newchar);\n\t      }\n\t      else\n\t       if (scrollData->addSpaces != 0) printf(\"%c\", 0x20);\n\n      }\n     printf(\"\\n\");\n      break;\n  }\n}\n\nint move_selector(LISTCHOICE ** selector, SCROLLDATA * scrollData) {\n/* \nCreates animation by moving a selector highlighting next item and\nunselecting previous item\n*/\n\n  LISTCHOICE *aux;\n  unsigned scrollControl = 0, continueScroll = 0, circular =\n      CIRCULAR_INACTIVE;\n\n  //Auxiliary pointer points to selector.\n  aux = *selector;\n\n  //Circular list animation when not scrolling.\n  if(aux->index == scrollData->listLength - 1\n     && scrollData->scrollActive == SCROLL_INACTIVE\n     && scrollData->scrollDirection == DOWN_SCROLL) {\n    //After last item go back to the top.\n    displayItem(aux, scrollData, UNSELECT_ITEM);\n    scrollData->selector = scrollData->wherey;\n    gotoIndex(&aux, scrollData, 0);\n    *selector = aux;\n    circular = CIRCULAR_ACTIVE;\n  }\n\n  if(aux->index == 0 && scrollData->scrollActive == SCROLL_INACTIVE\n     && scrollData->scrollDirection == UP_SCROLL) {\n    //Before first item go back to the bottom.\n    displayItem(aux, scrollData, UNSELECT_ITEM);\n    scrollData->selector = scrollData->wherey + scrollData->listLength - 1;\n    gotoIndex(&aux, scrollData, scrollData->listLength - 1);\n    *selector = aux;\n    circular = CIRCULAR_ACTIVE;\n  }\n  //Check if we do the circular list animation.\n  //If active, we skip the code one time.\n\n  if(circular == CIRCULAR_INACTIVE) {\n\n    //Check if we are within boundaries.\n    if((aux->next != NULL && scrollData->scrollDirection == DOWN_SCROLL)\n       || (aux->back != NULL && scrollData->scrollDirection == UP_SCROLL)) {\n\n      //Unselect previous item\n      displayItem(aux, scrollData, UNSELECT_ITEM);\n\n      //Check whether we move UP or Down\n      switch (scrollData->scrollDirection) {\n\n\tcase UP_SCROLL:\n\t  //Calculate new top index if scroll is active \n\t  //otherwise it defaults to 0 (top)\n\t  if(scrollData->scrollActive == SCROLL_ACTIVE)\n\t    scrollControl = scrollData->currentListIndex;\n\t  else\n\t    scrollControl = 0;\n\n\t  //Move selector\n\t  if(aux->back->index >= scrollControl) {\n\t    scrollData->selector--;\t//whereY--\n\t    aux = aux->back;\t//Go to previous item\n\t  } else {\n\t    if(scrollData->scrollActive == SCROLL_ACTIVE)\n\t      continueScroll = 1;\n\t    else\n\t      continueScroll = 0;\n\t  }\n\t  break;\n\n\tcase DOWN_SCROLL:\n\t  //Calculate bottom index limit if scroll is ACTIVE\n\t  //Otherwise it defaults to scrollData->ListLength-1\n\n\t  if(scrollData->scrollActive == SCROLL_ACTIVE)\n\t    scrollControl =\n\t\tscrollData->currentListIndex + (scrollData->displayLimit -\n\t\t\t\t\t\t1);\n\t  else\n\t    scrollControl = scrollData->listLength - 1;\n\n\t  //Move selector\n\t  if(aux->next->index <= scrollControl) {\n\t    aux = aux->next;\t//Go to next item\n\t    scrollData->selector++;\t//whereY++;\n\t  } else {\n\t    if(scrollData->scrollActive == SCROLL_ACTIVE)\n\t      continueScroll = 1;\n\t    else\n\t      continueScroll = 0;\n\t  }\n\t  break;\n      }\n\n    /*  //Metrics\n      gotoxy(6, 5);\n      printf(\"Length:%d|Index:%d|Memory addr:%p\",\n\t     scrollData->listLength, aux->index, aux);\n      gotoxy(6, 6);\n      printf(\"Scroll Limit: %d|IsScActive?:%d|ContinueScroll: %d\",\n\t     scrollControl, scrollData->scrollActive, continueScroll);\n*/\n      //Highlight new item\n      displayItem(aux, scrollData, SELECT_ITEM);\n  //    update_screen(screen1);\n      //Update selector pointer\n      *selector = aux;\n    }\n  }\n  //update_screen(screen1);\n  circular = CIRCULAR_INACTIVE;\n  return continueScroll;\n}\n\nchar selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData) {\n  char    ch=0;\n  int keypressed=0;\n  int control = 0;\n  int continueScroll=0;\n  unsigned counter = 0;\n  char chartrail[5];\n\n  //Go to and select expected item at the beginning\n\n  gotoIndex(&aux, scrollData, scrollData->currentListIndex);\n\n  if(scrollData->scrollDirection == DOWN_SCROLL\n     && scrollData->currentListIndex != 0) {\n    //If we are going down we'll select the last item \n    //to create a better scrolling transition (animation)\n    for(counter = 0; counter < scrollData->displayLimit; counter++) {\n       scrollData->scrollDirection = DOWN_SCROLL;\n        move_selector(&aux, scrollData);\n     }\n  } else {\n    //Do nothing if we are going up. Selector is always at the top item.\n  }\n\n  //It break the loop everytime the boundaries are reached.\n  //to reload a new list to show the scroll animation.\n  while(control != CONTINUE_SCROLL) {\n       if (timerC(&timer2) == TRUE){\n\t      //Animation in global.c\n             if (_animation() == -1) {scrollData->itemIndex = -1;double_escape = 1; break;}\n        }\n\n    //check listbox orientation and change keys\n    if (scrollData->orientation == VERTICAL || scrollData->orientation == VERTICALWITHBREAK){\n\tstrcpy(KTRAIL0, K_UP_TRAIL);\n\tstrcpy(KTRAIL1, K_DOWN_TRAIL);\n     }\n    else\n    {\n\tstrcpy(KTRAIL1, K_RIGHT_TRAIL);\n\tstrcpy(KTRAIL0, K_LEFT_TRAIL);\n    }\n\n    keypressed = kbhit(1);\n    if (keypressed == 1)\n      ch = readch();\n    else\n      ch = 0;\n    //if enter key pressed - break loop\n    if(ch == K_ENTER)\n      control = CONTINUE_SCROLL;\t//Break the loop\n\n     if (ch == 'x' || ch == K_BACKSPACE || ch == K_CTRL_C){\n         double_escape=1;\n\t scrollData->itemIndex = -1;\n\t  break;\n     }\n \n\n\t\tif (ch == K_ESCAPE)\t// escape key\n\t\t{\n\t\t\tstrcpy(chartrail, \"\\0\");\n\t\t\tread_keytrail(chartrail);\n\t\t        //If mode VERTICALWITHBREAK is selected; selector menu is interrupted when left/right arrow keys are pressed\n\t\t        if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_LEFT_TRAIL))==0)\n\t\t\t     return K_LEFTMENU;\n\t\t        if ((scrollData->orientation == VERTICALWITHBREAK) && (strcmp(chartrail,K_RIGHT_TRAIL))==0)\n\t\t\t     return K_RIGHTMENU;\n\n\t\t\tif (chartrail[0] == K_ESCAPE && chartrail[1] == 0) {\n\t\t\t\tdouble_escape = 1;\n\t\t\t\tscrollData->itemIndex = -1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (strcmp(chartrail, K_ALT_X) == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (strcmp(chartrail, KTRAIL0) == 0) {\n\t\t\t\t// escape key + A => arrow key up\n\t\t\t\t//Move selector up\n\t\t\t\tscrollData->scrollDirection = UP_SCROLL;\n\t\t\t\tcontinueScroll =\n\t\t\t\t    move_selector(&aux, scrollData);\n\t\t\t\t//Break the loop if we are scrolling\n\t\t\t\tif (scrollData->scrollActive == SCROLL_ACTIVE\n\t\t\t\t    && continueScroll == 1) {\n\t\t\t\t\tcontrol = CONTINUE_SCROLL;\n\t\t\t\t\t//Update data\n\t\t\t\t\tscrollData->currentListIndex =\n\t\t\t\t\t    scrollData->currentListIndex - 1;\n\t\t\t\t\tscrollData->selector =\n\t\t\t\t\t    scrollData->wherey;\n\t\t\t\t\tscrollData->item = aux->item;\n\t\t\t\t\tscrollData->itemIndex = aux->index;\n\t\t\t\t\t//Return value\n\t\t\t\t\tch = control;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// escape key + B => arrow key down\n\t\t\tif (strcmp(chartrail, KTRAIL1) == 0) {\n\t\t\t\t//Move selector down\n\t\t\t\tscrollData->scrollDirection = DOWN_SCROLL;\n\t\t\t\tcontinueScroll =\n\t\t\t\t    move_selector(&aux, scrollData);\n\t\t\t\t//Break the loop if we are scrolling\n\t\t\t\tif (scrollData->scrollActive == SCROLL_ACTIVE\n\t\t\t\t    && continueScroll == 1) {\n\t\t\t\t\tcontrol = CONTINUE_SCROLL;\n\t\t\t\t\t//Update data\n\t\t\t\t\tscrollData->currentListIndex =\n\t\t\t\t\t    scrollData->currentListIndex + 1;\n\t\t\t\t\tscrollData->selector =\n\t\t\t\t\t    scrollData->wherey;\n\t\t\t\t\tscrollData->item = aux->item;\n\t\t\t\t\tscrollData->itemIndex = aux->index;\n\t\t\t\t\tscrollData->scrollDirection =\n\t\t\t\t\t    DOWN_SCROLL;\n\t\t\t\t}\n\t\t\t\t//Return value\n\t\t\t\tch = control;\n\t\t\t}\n                      \n\t\t}\n\t}\n\n\tif (ch == K_ENTER || ch == K_ENTER2)\t// enter key\n\t{\n\t\t//Pass data of last item selected\n\t\tscrollData->item = aux->item;\n\t\tscrollData->itemIndex = aux->index;\n\t}\n\treturn ch;\n}\n//method to change how wide the selector is\nvoid setselectorLimit(int num){\n   selectorLimit = num;\n}\nvoid resetScrollData(SCROLLDATA *scrollData)\n{\n\tscrollData->scrollActive = 0;\t//To know whether scroll is active or not.\n\tscrollData->scrollLimit = 0;\t//Last index for scroll.\n\tscrollData->listLength = 0;\t//Total no. of items in the list\n\tscrollData->currentListIndex = 0;\t//Pointer to new sublist of items when scrolling.\n\tscrollData->displayLimit = 0;\t//No. of elements to be displayed.\n\tscrollData->selectorLimit = selectorLimit;\t//No. of chars per item display\n\tscrollData->scrollDirection = 0;\t//To keep track of scrolling Direction.\n\tscrollData->selector = 0;\t//Y++\n\tscrollData->wherex = 0;\n\tscrollData->wherey = 0;\n\tscrollData->backColor0 = 0;\t//0 unselected; 1 selected\n\tscrollData->foreColor0 = 0;\n\tscrollData->backColor1 = 0;\n\tscrollData->foreColor1 = 0;\n\tscrollData->itemIndex = 0;\n\tscrollData->addSpaces = 0;\n\tscrollData->orientation = VERTICAL;\n}\nchar listBox(LISTCHOICE * head,\n\t     unsigned whereX, unsigned whereY,\n\t     SCROLLDATA * scrollData, unsigned bColor0,\n\t     unsigned fColor0, unsigned bColor1, unsigned fColor1,\n\t     unsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked) {\n\n  unsigned list_length = 0;\n  //unsigned currentIndex = 0;\n  int     scrollLimit = 0;\n  unsigned currentListIndex = 0;\n  char    ch=0;\n  LISTCHOICE *aux=NULL;\n //Init values\n  double_escape=0;\n  resetScrollData(scrollData);\n  scrollData->orientation = listorientation;\n // Query size of the list\n  list_length = query_length(&head) + 1;\n\n  //Save calculations for SCROLL and store DATA\n  scrollData->displayLimit = displayLimit;\n  scrollLimit = list_length - scrollData->displayLimit;\t//Careful with negative integers\n  if(scrollLimit < 0 || displayLimit > list_length)\n    scrollData->displayLimit = list_length;\t//Failsafe for overboard values\n\n  scrollData->scrollLimit = scrollLimit;\n  scrollData->listLength = list_length;\n  scrollData->wherex = whereX;\n  scrollData->wherey = whereY;\n  scrollData->selector = whereY;\n  scrollData->backColor0 = bColor0;\n  scrollData->backColor1 = bColor1;\n  scrollData->foreColor0 = fColor0;\n  scrollData->foreColor1 = fColor1;\n  scrollData->addSpaces = addSpaces;\n\n  get_terminal_dimensions(&listrows,&listcolumns);\n  //Check whether we have to activate scroll or not \n  //and if we are within bounds. [1,list_length)\n    ch=0;\n    aux = head;\n    printlist(aux, scrollData, scrollData->displayLimit);\nif (locked == LOCKED) {    \n  if(list_length > scrollData->displayLimit && scrollLimit > 0\n     && displayLimit > 0) {\n    //Scroll is possible  \n\n    scrollData->scrollActive = SCROLL_ACTIVE;\n\n    currentListIndex = 0;\t//We listBox1 the scroll at the top index.\n    scrollData->currentListIndex = currentListIndex;\n\n    //Scroll loop animation. Finish with ENTER.\n    loadlist(aux, scrollData, currentListIndex);\n    do {\n      currentListIndex = scrollData->currentListIndex;\n      loadlist(aux, scrollData, currentListIndex);\n      gotoIndex(&aux, scrollData, currentListIndex);\n    /*  gotoxy(6, 4);\n      printf(\"Current List Index: %d:%d\\n\", scrollData->currentListIndex,\n\t     aux->index); */\n        ch = selectorMenu(aux, scrollData);\n\tif (double_escape == 1) {\n\t  scrollData->itemIndex = -1;\n\t  locked = FALSE;\n\t  ch= K_ESCAPE;\n\t  break;\n\t}\n\tif (_animation() == -1) {\n\t  scrollData->itemIndex = -1;\n\t  double_escape = 1;\n\t  ch = K_ESCAPE;\n\t  locked = FALSE;\n\t   break;\n\t}   \n    } while(ch != K_ENTER);\n\n  } else {\n    //Scroll is not possible.\n    //Display all the elements and create selector\n    //\n    scrollData->scrollActive = SCROLL_INACTIVE;\n    scrollData->currentListIndex = 0;\n    scrollData->displayLimit = list_length;\t//Default to list_length\n    loadlist(head, scrollData, 0);\n     ch = selectorMenu(head, scrollData);\n\tif (double_escape == 1) {\n\t  scrollData->itemIndex = -1;\n\t  locked = FALSE;\n\t  ch= K_ESCAPE;\n\t  //break;\n\t}\n\n  }\n}\n  return ch;\n}\n\n\n"
  },
  {
    "path": "src/listbox.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule to implement a listBox integrated with LYNX.\n@author : Velorek\n@version : 1.0\nLast modified: 26/12/2022\n========================================================================\n*/\n\n#ifndef _LISTBOX_H_\n#define _LISTBOX_H_\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <stdio.h>\n#include \"scbuf.h\"\n/*====================================================================*/\n/* CONSTANTS */\n/*====================================================================*/\n//Scroll Control values.\n#define SCROLL_ACTIVE 1\n#define SCROLL_INACTIVE 0\n#define CONTINUE_SCROLL -1\n#define DOWN_SCROLL 1\n#define UP_SCROLL 0\n#define SELECT_ITEM 1\n#define UNSELECT_ITEM 0\n#define CIRCULAR_ACTIVE 1\n#define CIRCULAR_INACTIVE 0\n#define LOCKED 1\n#define NOT_LOCKED 0\n#define VERTICAL 0\n#define HORIZONTAL 1\n#define VERTICALWITHBREAK 2\n/*====================================================================*/\n/* TYPEDEF STRUCTS DEFINITIONS */\n/*====================================================================*/\n\ntypedef struct _listchoice {\n  unsigned index;\t\t// Item number\n  char   *item;\t\t\t// Item string\n  int setX;\t\t//X,Y position\n  int setY;\t\t//-1 to ignore\n  int foreColor;        //-1 to ignore\n  int backColor;        //-1 to ignore\n  struct _listchoice *next;\t// Pointer to next item\n  struct _listchoice *back;\t// Pointer to previous item\n} LISTCHOICE;\n\ntypedef struct _scrolldata {\n  unsigned scrollActive;\t//To know whether scroll is active or not.\n  unsigned scrollLimit;\t\t//Last index for scroll.\n  unsigned listLength;\t\t//Total no. of items in the list\n  unsigned currentListIndex;\t//Pointer to new sublist of items when scrolling.\n  unsigned displayLimit;\t//No. of elements to be displayed.\n  unsigned selectorLimit;       //how many items of string item can be displayed\n  unsigned scrollDirection;\t//To keep track of scrolling Direction.\n  unsigned wherex;\n  unsigned wherey;\n  unsigned selector;\t\t//Y++\n  unsigned backColor0;\t\t//0 unselected; 1 selected\n  unsigned foreColor0;\n  unsigned backColor1;\n  unsigned foreColor1;\n  unsigned addSpaces;          //whether to add spaces or not\n  unsigned orientation;\n  unsigned displayMetrics;     //to show metrics on screen/reuse code for text viewing\n  char   *item;\n  int      itemIndex;          //-1 means ESC was pressed\n  LISTCHOICE *head;\t\t//store head of the list\n} SCROLLDATA;\n\n/*====================================================================*/\n/* GLOBAL VARIABLES */\n/*====================================================================*/\nextern LISTCHOICE *listBox1;\t//Head pointer.\n\n\n/*====================================================================*/\n/* PROTOTYPES OF FUNCTIONS                                            */\n/*====================================================================*/\n\n//DYNAMIC LINKED LIST FUNCTIONS\nvoid    removeList(LISTCHOICE ** head);\nLISTCHOICE *addatend(LISTCHOICE * head, LISTCHOICE * newp);\nLISTCHOICE *newitem(char *text,unsigned setX, unsigned setY,unsigned foreColor, unsigned backColor);\n\n//LISTBOX FUNCTIONS\n//void    addItems(LISTCHOICE ** listBox1);\nchar    listBox(LISTCHOICE * selector, unsigned whereX, unsigned whereY,\n\t\tSCROLLDATA * scrollData, unsigned bColor0,\n\t\tunsigned fColor0, unsigned bColor1, unsigned fColor1,\n\t\tunsigned displayLimit,unsigned listorientation, unsigned addSpaces, unsigned locked);\nvoid    loadlist(LISTCHOICE * head, SCROLLDATA * scrollData,\n\t\t unsigned indexAt);\n\nvoid printlist(LISTCHOICE * head, SCROLLDATA * scrollData, unsigned displayLimit);\n\nvoid    gotoIndex(LISTCHOICE ** aux, SCROLLDATA * scrollData,\n\t\t  unsigned indexAt);\nint     query_length(LISTCHOICE ** head);\nint     move_selector(LISTCHOICE ** head, SCROLLDATA * scrollData);\nchar    selectorMenu(LISTCHOICE * aux, SCROLLDATA * scrollData);\nvoid    displayItem(LISTCHOICE * aux, SCROLLDATA * scrollData, int select);\nvoid    resetScrollData(SCROLLDATA *scrollData);\nvoid \tsetselectorLimit(int num);\n\n/*====================================================================*/\n/* FUNCTION PROTOTYPES                                                */\n/*====================================================================*/\n\n#endif\n"
  },
  {
    "path": "src/main.c",
    "content": "/* C-edit project\n* Last updated - 29/8/2024\n* New drop-down menu implementation\n* Added more modularisation: editor.c menu.c\n* Scrollbars added\n*/\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include \"listbox.h\"\n#include \"scbuf.h\"\n#include \"rterm.h\"\n#include \"tm.h\"\n#include \"global.h\" \n#include \"keyb.h\"\n#include \"edbuf.h\"\n#include \"ui.h\"\n#include \"menu.h\"\n#include \"editor.h\"\n#include \"opfile.h\"\n#include \"fileb.h\"\n//Prototypes\nvoid draw_screen();\nvoid cursor_tick();\nint special_keys();\nint control_keys(char ch);\nvoid _resizeScreen();\nwchar_t currentChar = 0;\nchar tempMessage[150];\nint displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration);\nvoid update_indicators();\nint oldPositionY = 4; \nint oldPositionX = 2; \nvoid draw_screen(){\n//BASE SCREEN IS STORED IN SCREEN 2\n     int i=0;\n     if (screen1 != NULL) deleteList(&screen1);\n     //if (screen2 != NULL) deleteList(&screen2);\n     //Init 2 : Create 2 Screens for a double buffer  approach  \n     old_rows=new_rows;\n     old_columns=new_columns;\n     create_screen(&screen1);\n     create_screen(&screen2);\n     //SCREEN 2\n     screen_color(screen1, EDITAREACOL, EDIT_FORECOLOR, FILL_CHAR);\n    //Failsafe just in case it can't find the terminal dimensions\n    if(old_rows == 0)\n      old_rows = ROWS_FAILSAFE;\n    if(old_columns == 0)\n    old_columns = COLUMNS_FAILSAFE;\n\n  //Draw upper and lower bars\n    for(i = 0; i < old_columns; i++) {\n     write_ch(screen1, i, 1, FILL_CHAR, MENU_PANEL, MENU_PANEL,0);\n    }\n\n  for(i = 0; i < old_columns; i++) {\n    write_ch(screen1, i, old_rows, FILL_CHAR, STATUSBAR, STATUSMSG,1);\n  }\n  // Text messages\n  write_str(screen1, 0, 1, \"File  Options  Help\", MENU_PANEL, MENU_FOREGROUND0,0);\n  write_str(screen1, 0, 1, \"F\", MENU_PANEL, F_RED,0);\n  write_str(screen1, 7, 1, \"p\", MENU_PANEL, F_RED,0);\n  write_str(screen1, 15, 1, \"H\", MENU_PANEL, F_RED,0);\n  write_str(screen1, 0, old_rows, STATUS_BAR_MSG1, STATUSBAR, STATUSMSG,0);\n\n  /* Frames */\n  //window appearance and scroll bar\n  for(i = 2; i < old_rows; i++) {\n    write_ch(screen1,old_columns-1, i, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,0);\t//Scroll bar\n    write_ch(screen1,0, i, VER_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//upper vertical line box-like char \n  }\n  for(i = 0; i < old_columns; i++) {\n    write_ch(screen1,i, 2, HOR_LINE, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//horizontal line box-like char\n    write_ch(screen1,i, old_rows - 1, ' ', EDITWINDOW_BACK, EDITWINDOW_FORE,0);\n  }\n  write_ch(screen1,0, 2, UPPER_LEFT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//upper-left box-like char\n  //horizontal scroll bar\n  for(i = 0; i < old_columns; i++) {\n    write_ch(screen1,i, old_rows - 1, FILL_CHAR, SCROLLBAR_BACK, SCROLLBAR_FORE,0);\n  }\n  //Window-appearance\n  write_ch(screen1,old_columns-1, 2, UPPER_RIGHT_CORNER, EDITWINDOW_BACK, EDITWINDOW_FORE,0);\t//right window corner\n  write_ch(screen1,old_columns-1, old_rows - 1, LOWER_RIGHT_CORNER, EDITWINDOW_BACK,\n\t   EDITWINDOW_FORE,0);\n  write_ch(screen1, 0, old_rows - 1, LOWER_LEFT_CORNER, EDITWINDOW_BACK,\n\t   EDITWINDOW_FORE,0);\n\n  //Scroll symbols\n  write_ch(screen1,old_columns-1, 3, '^', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  write_ch(screen1, old_columns-1, old_rows - 2, 'v', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  write_ch(screen1, old_columns-1, 4, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);\n  write_ch(screen1, 2, old_rows - 1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,0);\n  write_ch(screen1, 1, old_rows - 1, '<', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  write_ch(screen1, old_columns - 2, old_rows - 1, '>', SCROLLBAR_ARR, SCROLLBAR_FORE,0);\n  if (strlen(fileName) == 0) strcpy(fileName, \"UNTITLED\");\n  write_str(screen1,(new_columns / 2) - (strlen(fileName) / 2), 2, fileName,\n        MENU_PANEL, MENU_FOREGROUND0,0); \n\n  dump_screen(screen1);\n  //Save screen for later\n  //copy_screen(screen2,screen1);\n}\n\nvoid cursor_tick(void){\n//CURSOR ANIMATION\nchar drawChar=FILL_CHAR;\nchar drawChar0=FILL_CHAR;\nint attrib = 0;\nwchar_t code_point;\n    //GET CHAR BEING POINTED AT FROM EDIT BUFFER\n   if (edBuf1 != NULL)_dumpLine(edBuf1, posBufY, &tempLine);\n    drawChar = tempLine.linea[posBufX].ch; \n    drawChar0 = tempLine.linea[posBufX].specialChar; \n    attrib =  tempLine.linea[posBufX].attrib;\n    //CHECK FOR SPECIAL CHARACTERS AND CONVERT THEM TO UNICODE TO PRINT\n    //IF CURSOR IS ON A CHAR HIGHLIGHT IT IN YELLOW\n    if (drawChar0 != 0 && drawChar != '\\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F);\n    else {\n            if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR;\n\t    code_point = drawChar;\n    }\n    if (cursor_timer1.ticks % 2 == 0) update_ch(cursorX, cursorY, CURSOR_CHAR, B_BLUE, F_WHITE);\n    else update_ch(cursorX, cursorY, code_point, EDITAREACOL, FH_YELLOW);\n    \n    //REST ANSI VALUES TO HAVE HIGH INTENSITY COLORS\n    resetAnsi(0);\n\n    //CLEAR LAST POSITION OF CURSOR WITH FILL_CHAR OR GO BACK TO PREVIOUS CHAR\n    if ((old_cursorX != cursorX) || (old_cursorY != cursorY)){\n      //old?\n      if (edBuf1 != NULL)_dumpLine(edBuf1, oldposBufY, &tempLine);\n           drawChar = tempLine.linea[oldposBufX].ch; \n           drawChar0 = tempLine.linea[oldposBufX].specialChar; \n           attrib =  tempLine.linea[oldposBufX].attrib;\n    //always clear cursor cell (avoids false misprints)\n    update_ch(old_cursorX, old_cursorY, ' ', EDITAREACOL, EDIT_FORECOLOR);\n\n  \n    //then try to update to its previous state\n    if (drawChar0 != 0 && drawChar != '\\0') code_point = ((drawChar0 & 0x1F) << 6) | (drawChar & 0x3F);\n    else {\n            if (drawChar == 0 || drawChar == END_LINE_CHAR) drawChar = FILL_CHAR;\n\t    code_point = drawChar;\n    }\n       update_ch(old_cursorX, old_cursorY, code_point, EDITAREACOL, attrib);\n    } \n    if (old_cursorY != cursorY) {\n         //Point to line in buffer when Y position changes\n        if (edBuf1 != NULL) _dumpLine(edBuf1, posBufY, &tempLine);\n    }\n    //printf(\"\\n\");\n    //write_num(screen1, 10,10, cursorX, B_GREEN, F_WHITE,1);\n    //write_num(screen1, 10,11, cursorY, B_RED, F_WHITE,1);\n    //write_num(screen1, 10,12, old_cursorX, B_GREEN, F_WHITE,1);\n    //write_num(screen1, 10,12, old_cursorY, B_GREEN, F_WHITE,1);\n    //write_num(screen1, 10,14, posBufX, B_RED, F_WHITE,1);\n    //write_num(screen1, 10,15, posBufY, B_RED, F_WHITE,1);\n    //write_num(screen1, 10,16, findEndline(tempLine), BH_BLUE, F_WHITE,1);\n    //write_num(screen1, 10,17, _length(&edBuf1), B_RED, F_WHITE,1);\n    //for (int i=0; i<findEndline(tempLine);i++) write_ch(screen1, 10+i,16, code_point, B_RED, F_WHITE,1);\n    //dump_screen(screen1);\n   //Buffer pointer position\n   /*\n     update_str(new_columns - 24, new_rows, \"| L:        C:     \", STATUSBAR, STATUSMSG);\n    write_num(screen1, new_columns - 10, new_rows, posBufX, STATUSBAR, STATUSMSG,1);\n    write_num(screen1, new_columns - 20, new_rows, posBufY+1, STATUSBAR, STATUSMSG,1);\n    update_str(new_columns - 39, new_rows, \"| LINES:      \", STATUSBAR, STATUSMSG);\n    write_num(screen1, new_columns - 31, new_rows, _length(&edBuf1), STATUSBAR, STATUSMSG,1);\n*/\n    }\n\nvoid update_indicators() {\n/*\n   Update cursor position display on screen.\n   Values are float to save decimal points.\n- Formulas:\n   scrollRatio = totalFileLines / displayLength;\n   currentPosition = bufferY / scrollRatio;\n   percentage = (currentPosition * 100) / displayLength;\n   To adjust to the bar dimensions:\n   scrollBar = ((displayLength-3) * percentage) / 100;\n*/\n  char info[255];\n  int pep=0;\n  float scrollIndicator=1.0, positionY=0.0;\n  float hscrollIndicator=1.0, positionX=0.0;\n  float percentage=0.0, scrollBar=0.0, scrollRatio =0.0;\n  float hpercentage=0.0, hscrollBar=0.0, hscrollRatio =0.0;\n  pep = 100;\n\n  //Scroll indicator and percentage display\n if (_length(&edBuf1) > vdisplayArea ) {\n     write_ch(screen1,new_columns-1, oldPositionY, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1);\t \n     positionY = posBufY;\n     scrollRatio = _length(&edBuf1) / vdisplayArea;\n     scrollIndicator = positionY / scrollRatio;\n     percentage = (scrollIndicator * 100) / vdisplayArea;\n     scrollBar = ((vdisplayArea-3) * percentage)/100;\n     if (positionY == 1) percentage = 0;\n     if (percentage > 100) percentage = 100;\n     if (scrollBar+2>=new_rows-5) scrollBar = new_rows - 7;\n     write_ch(screen1,new_columns-1, 4+scrollBar, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1);\n     oldPositionY = 4+scrollBar;\n     pep = percentage;\n  }\n if (posBufX>0){\n     positionX = posBufX;\n     write_ch(screen1, oldPositionX,new_rows-1, ' ', SCROLLBAR_BACK, SCROLLBAR_FORE,1);\n     oldPositionX = 2+hscrollBar;\n     hscrollRatio = MAX_LINE_SIZE / hdisplayArea;\n     hscrollIndicator = positionX / hscrollRatio;\n     hpercentage = (hscrollIndicator * 100) / hdisplayArea;\n     hscrollBar = (((hdisplayArea) * hpercentage)/100);\n     if (hscrollBar+2>=new_columns-3) hscrollBar = new_columns-5;\n     write_ch(screen1, 2+hscrollBar,new_rows-1, '*', SCROLLBAR_SEL, SCROLLBAR_FORE,1);\n     oldPositionX = 2+hscrollBar;\n }\n  strcpy(info, \"\\0\");\n  sprintf(info, \"|LINES: %d| L: %ld C: %ld [%d%c]           \", _length(&edBuf1), posBufY, posBufX,pep,'%');\n  update_str(new_columns - 40, new_rows, info, STATUSBAR, STATUSMSG);\n}\n\n\nint main(int argc, char *argv[]) {\n\nchar ch=0;\nchar old_ch=0;\nint esc_key = 0;\nint keypressed = 0;\n\n    //Init Terminal\n    init_term();\n    initCEDIT();\n    draw_screen();\n    resetch();\n    strcpy(fileName, \"\\0\");\n    //tempLine.linea[0].ch = END_LINE_CHAR;\n    //tempLine.linea[posBufX].ch = END_LINE_CHAR;\n    //tempLine.linea[posBufX].specialChar = 0;\n    //tempLine.linea[posBufX].attrib = EDIT_FORECOLOR;\n    if(argc > 1) {\n     //Does the file exist? Open or create?\n      strcpy(fileName, argv[1]);\n      filetoBuffer(fileName);\n      flush_editarea(0);\n      buffertoScreen(0);\n      dump_screen(screen1);\n      fileModified= FILE_UNMODIFIED;\n    } \n    do{    \n\t //end flag from any part of the program\n\t if (programStatus == ENDSIGNAL) break;\n\t //Time animation & resize window \n\t  if (timerC(&timer3) == TRUE){\n\t\t   displayMessage(tempMessage,  (new_columns/2)-strlen(tempMessage)/2, 1, FH_WHITE, B_RED, 5);\n\t  }\n\t if (timerC(&timer2) == TRUE){\n           _animation();\n\t    //Refresh screen size buffers if terminal dimension changes\n\t    if (new_rows != old_rows || new_columns != old_columns)\n            {\n\t      _resizeScreen();\n            }\n\t  }\n         //Cursor Animation\t \n\t if (timerC(&cursor_timer1) == TRUE){\n\t      //Animation\n             cursor_tick();\n\t     //if (keypressed == FALSE) { esc_key = 0;}\n           }\n\t//PROCESS INPUT\n    \t keypressed = kbhit(1);\n          if (keypressed == TRUE) {\n\t   keypressed = FALSE;\n\t   //try to catch and avoid printing unwanted chars with cursor keys\n\t   old_ch = ch;\n\t   ch=readch();\n\t   if (old_ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;}\n\t   if (ch==ESC_KEY) {unwantedChars = 1; esc_key = 1;}\n\t   if (unwantedChars>0) esc_key = 1;\n\n\t   //Keys with a escape sequenece\n           if (ch == ESC_KEY) {//buffertoScreen(0, 0,FALSE); \n\t\t\t       esc_key = special_keys(); \n\t\t\t       cursor_tick(); \n\t\t\t       ch = 0;}       \n           else {\n\t\t//Capture control keys   \n\t\tif ((ch>0 && ch< 0x0F) && (ch!=K_ENTER && ch != K_TAB)){buffertoScreen(FALSE); esc_key= control_keys(ch); ch=0;}   \n\t\telse \n\t         //Process raw edit input from keyboard in editor.c\t\t\n\t\t{\n\t\t  //try to avoid printing unwanted chars with cursor keys\n\t\t  if (ch != 0 && esc_key==0 && unwantedChars == 0&& posBufX <MAX_LINE_SIZE) editor_section(ch);\n\t        }\n\t   }\n\t   update_indicators();\n        }else{\n\t//if not keypressed reset values for unwanted characters\n             esc_key=0; unwantedChars = 0;\n\t}//Check for ESC-related keys\n      } while (esc_key != ENDSIGNAL);     \n    //restore terminal\n     credits();    \n     return 0;\n}\n\n\n//CONTROL KEYS\nint control_keys(char ch){\n  char    returnMenuChar=0;\n  int menuCounter = 0;\n  int returnValue=0;\n  char countCh=0;\n  char tempfileName[MAXFILENAME];\n    if(ch == K_CTRL_L) {\n      //Akin to F2\n\thandlemenus(&returnMenuChar, &menuCounter,TRUE);\n    } \n    if(ch == K_CTRL_C) {\n      returnValue  = ENDSIGNAL;\n    }\n    if (ch == K_CTRL_A) {\n      flush_editarea(0);\n       buffertoScreen(0);\n      countCh=inputWindow(\"File:\", tempfileName,  \"Quick load...\",28,2,48);\n      if (countCh>0) {\n\t strcpy(fileName, tempfileName);\n\t filetoBuffer(fileName);\n         flush_editarea(0);\n         buffertoScreen(0);\n        dump_screen(screen1);\n     }//buffertoScreen(0, 0, 0);\n    }\n\n      if (ch == K_CTRL_N){\n        if (openFileDialog(fileName,fullPath) == 1){\n \t filetoBuffer(fileName);\n         flush_editarea(0);\n         buffertoScreen(0);\n     }\n        dump_screen(screen1);\n    \n    \n    }\n\t     \n\n \n  return returnValue;\n}\n\n//ESCAPE-RELATED KEYS\nint special_keys() {\n/* MANAGE SPECIAL KEYS */\n/*\n   New implementation: Trail of chars found in keyboard.c\n   If K_ESCAPE is captured read a trail up to 5 characters from the console.\n   This is to control the fact that some keys may change\n   according to the terminal and expand the editor's possibilities.\n   Eg: F2 can be either 27 79 81 or 27 91 91 82.\n*/\n      //cursorY : position on screen\n      //posBufY : position in buffer\n \n  int     esc_key = 0;\n  char    chartrail[5];\n  char    returnMenuChar=0;\n  int menuCounter = 0;\n  int countCh = 0;\n  int ok = -1;\n  char tempfileName[MAXFILENAME];\n    old_cursorX = cursorX;\n    old_cursorY = cursorY;\n    oldposBufX = posBufX;\n    oldposBufY = posBufY;\n\n\n    strcpy(chartrail, \"\\0\");\n    read_keytrail(chartrail);   //Read trail after ESC key\n    //only ESC key detected, finish program\n    if (chartrail[0] == ESC_KEY && chartrail[1]==0) {\n\n            buffertoScreen(0);\n\t    if (fileModified == FILE_MODIFIED) {\n\t\t    ok=yesnoWindow(WMODIFIED_MSG, \"Alert Window\");\n\t            switch (ok){\n\t\t       case 0: //save file and exit\n    \t\t\t    strcpy(chartrail, K_ALT_S);\n\t\t\t    break;\n\t\t       case 1: //don't save and exit\n\t                    return ENDSIGNAL;\n\t\t\t    break;  \n\n\t\t       case 2: //cancel keep running c-edit\n\t\t\t   buffertoScreen(0);\n\t\t\t   break;\n\t             }\n\t    } else\n            //regular escape with no modifications\n\t    return ENDSIGNAL;\n    }\n    \n    //Check key trails for special keys starting with ESC.\n    //FUNCTION KEYS : F1 - F4\n    if(strcmp(chartrail, K_F2_TRAIL) == 0 ||\n       strcmp(chartrail, K_F2_TRAIL2) == 0) {\n       handlemenus(&returnMenuChar, &menuCounter,TRUE);\n    } else if(strcmp(chartrail, K_F3_TRAIL) == 0 ||\n          strcmp(chartrail, K_F3_TRAIL2) == 0) {\n    } else if(strcmp(chartrail, K_F1_TRAIL) == 0 ||\n          strcmp(chartrail, K_F1_TRAIL2) == 0) {\n\t  flush_editarea(0);\n          buffertoScreen(0); \n\t    displayHelp();\n    } else if(strcmp(chartrail, K_F4_TRAIL) == 0 ||\n          strcmp(chartrail, K_F4_TRAIL2) == 0) {\n\n      // ARROW KEYS\n    } else if(strcmp(chartrail, K_LEFT_TRAIL) == 0) {\n      //Left-arrow key\n      unwantedChars++;\n      if(cursorX > 1){\n        cursorX = cursorX - 1;\n        //editScroll.bufferX--;\n      }\n      if (posBufX>0) posBufX--;\n      //adjust shiftH when going back to account for the fact that cursorX=1 is not enough\n      if (cursorX == new_columns - 4) shiftH++;\n      if (cursorX == 1 && shiftH>0) {shiftH--;buffertoScreen(1);}\n    } else if(strcmp(chartrail, K_RIGHT_TRAIL) == 0) {\n      //Right-arrow key\n      unwantedChars++;\n      if(cursorX < new_columns - 3){\n        cursorX = cursorX + 1;\n        //shiftH = 0;\n      } else{\n\tif (posBufX<MAX_LINE_SIZE) shiftH++;\n\tbuffertoScreen(1);      \n      }\n      if (posBufX<MAX_LINE_SIZE) posBufX++;\n\n    } else if(strcmp(chartrail, K_UP_TRAIL) == 0) {\n      //Up-arrow key\n      unwantedChars++;\n      if(cursorY > 2) {\n       cursorY = cursorY - 1;\n        \n      }else{\n\t      //scrolling up\n\t        if (currentLine>0) {\n\t\t\tcurrentLine--;\n\t               buffertoScreen(1);\n\t\t}\n      }\n      if (posBufY > 0) posBufY--;\n \n    } else if(strcmp(chartrail, K_DOWN_TRAIL) == 0) {\n      //Down-arrow key\n     //Check if there are more lines to go to\n      unwantedChars++;\n      if (posBufY<_length(&edBuf1)-1){\n        if(cursorY < new_rows - 3) {\n          //stay put if we are are the end of the viewing area\n          cursorY = cursorY + 1;\n        }\n\telse{  \n                //scrolling down\n\t        if (_length(&edBuf1) > vdisplayArea ) {\n\t\t  currentLine++;\n\t          buffertoScreen(1);\n\t\t}\n\t}  \n        posBufY++;\n      }\n    } else if(strcmp(chartrail, K_PAGEDOWN_TRAIL) == 0) {\n      //Page Down key\n          vdisplayLimit = _length(&edBuf1) - vdisplayArea;\n\t  if (_length(&edBuf1) > vdisplayArea ) {\n\t\tif (currentLine + vdisplayArea <= vdisplayLimit )\n                            currentLine =  currentLine + vdisplayArea;\n                else\n                            currentLine = vdisplayLimit;  // stop at the limit of our scroll\n               posBufY = currentLine;\n               cursorY = START_CURSOR_Y;\n\t       buffertoScreen(1);\n\t  }\n     } else if(strcmp(chartrail, K_PAGEUP_TRAIL) == 0) {\n      //Page Down key\n\t  if (_length(&edBuf1) > vdisplayArea ) {\n                          if (currentLine  >= vdisplayArea)\n                              currentLine = currentLine - vdisplayArea;\n                          else\n                             currentLine = 0;  // stop at the top\t\t\t  \n            posBufY = currentLine;\n            cursorY = START_CURSOR_Y;\n\t    buffertoScreen(1);\n\t  }\n     }else if(strcmp(chartrail, K_HOME_TRAIL) == 0 || strcmp(chartrail, K_HOME_TRAIL2) == 0 ) {\n\t  if (_length(&edBuf1) > vdisplayArea ) {\n\t    currentLine=0;\n            cursorY = START_CURSOR_Y;\n\t    posBufY=0;\n\t    buffertoScreen(1);\n\t  }  \n     }else if(strcmp(chartrail, K_END_TRAIL) == 0 || strcmp(chartrail, K_END_TRAIL2) == 0 ) {\t      \n\t  if (_length(&edBuf1) > vdisplayArea ) {\n\t    currentLine=_length(&edBuf1)-vdisplayArea;\n            cursorY = new_rows-3;\n\t    posBufY=_length(&edBuf1)-1;  \n\t    buffertoScreen(1);  \n\t  }\n    } else if(strcmp(chartrail, K_DELETE) == 0) {\n       deleteKeyPressed = 1;         \t    \n       editor_section(0);\n      //delete button;\n    } else if(strcmp(chartrail, K_ALT_F) == 0) {\n      returnMenuChar=FILE_MENU;\n      menuCounter=FILE_MENU;\n      handlemenus(&returnMenuChar, &menuCounter,FALSE);\n    } else if(strcmp(chartrail, K_ALT_P) == 0) {\n      returnMenuChar=OPT_MENU;\n      menuCounter=OPT_MENU;\n      handlemenus(&returnMenuChar, &menuCounter,FALSE);\n    } else if(strcmp(chartrail, K_ALT_H) == 0) {\n      returnMenuChar=HELP_MENU;\n      menuCounter=HELP_MENU;\n      handlemenus(&returnMenuChar, &menuCounter,FALSE);\n    } else if(strcmp(chartrail, K_ALT_O) == 0) {\n      //openFileHandler();    //Open file Dialog\n       buffertoScreen(0);\n       dump_screen(screen1);\n       if (openFileDialog(fileName,fullPath) == 1){\n\t       //is it a binary file?\n\t    filetoBuffer(fileName);\n            flush_editarea(0);\n            buffertoScreen(0);\n\t }\n        dump_screen(screen1);\n    } else if(strcmp(chartrail, K_ALT_N) == 0) {\n      //newDialog(currentFile);   // New file\n      //refresh_screen(-1);\n      resetch();\n    } else if(strcmp(chartrail, K_ALT_A) == 0) {\n      //saveasDialog(currentFile);    //Save as.. file\n      //refresh_screen(-1);\n    } else if(strcmp(chartrail, K_ALT_S) == 0) {\n      //Save file\n      flush_editarea(0);\n      buffertoScreen(0);\n      strcpy(tempMessage, \"[File saved!]\\0\");\n    \t   if (strcmp(fileName, \"UNTITLED\") == 0) {\n        countCh=inputWindow(\"File:\", tempfileName,  \"Save file as...\",28,2,48);\n        if (countCh>0) {\n\t   strcpy(fileName, tempfileName);\n\t   buffertoFile(fileName);\n\t   flush_editarea(0);\n\t   buffertoScreen(0);\n           dump_screen(screen1);\n           timer3.ticks=0; \n\t}\t\n       } else{\n\t   buffertoFile(fileName);\n\t   flush_editarea(0);\n\t   buffertoScreen(0);\n           dump_screen(screen1);\n           timer3.ticks=0; \n       }\n\t   //a bit convoluted but it works / exit if user selcts yes after saving\n        if (ok==0){printf(\"File saved!. Exiting...\\n\"); return ENDSIGNAL; }\n    } else if(strcmp(chartrail, K_ALT_W) == 0) {\n      //if(strcmp(currentFile, UNKNOWN) == 0)\n    //saveasDialog(currentFile);  //Write to file\n      //else {\n    //saveDialog(currentFile);\n      //}\n      //refresh_screen(-1);\n    } else if(strcmp(chartrail, K_ALT_X) == 0) {\n    /*  \n    if(fileModified == 1)\n      exitp = confirmation(); //Shall we exit? Global variable!\n      else\n    exitp = EXIT_FLAG;\n    } } \n    */\n    }\n    esc_key = 1;\n  return esc_key;\n\n}\n\n/*\nvoid linetoScreen(long whereY, VLINES tempLine, BOOL clean){\n//dump temporary Line to screen buffer\n   int i,j=0;\n   for (i=0; i<findEndline(tempLine); i++){\n   \tif(tempLine.linea[i].specialChar != 0) {\n\t  //Special char ? print the two values to screen buffer.\n\t  write_ch(i+START_CURSOR_X, whereY,  tempLine.linea[i].specialChar, EDITAREACOL,\n\t\t   EDIT_FORECOLOR);\n\t  write_ch(i+START_CURSOR_X, whereY,  tempLine.linea[i].ch, EDITAREACOL,   EDIT_FORECOLOR);\n\t} else {\n\t  write_ch(i+START_CURSOR_X, whereY, tempLine.linea[i].ch, EDITAREACOL,\n\t\t   EDIT_FORECOLOR);\n\t}\n\tif (clean == TRUE) \n\t  for (j=findEndline(tempLine); j<columns -2; j++)\n\t\twrite_ch(j+START_CURSOR_X, whereY, FILL_CHAR, EDITAREACOL, EDIT_FORECOLOR); \t  \n\t}\n\twrite_ch(findEndline(tempLine)+START_CURSOR_X, whereY, '|', B_GREEN,\n\t\t   F_WHITE);\n}\t\n*/\n\n/*---------*/\n/* Credits */\n/*---------*/\n\nvoid credits() {\n  //Frees memory and displays goodbye message \n  //Free selected path item/path from opfiledialog \n  size_t i; //to be compatible with strlen\n  char auth[27] =\"Coded by v3l0r3k 2018-2025\";\n  //int wherex=0,wherey=0;  \n\n  close_term();\t\t\t//restore terminal settings from failsafe\n  gotoxy(1,1);\n  printf(cedit_ascii_1);\n  gotoxy(1,2);\n  printf(cedit_ascii_2);\n  gotoxy(1,3);\n  printf(cedit_ascii_3);\n  gotoxy(1,4);\n  printf(cedit_ascii_4);\n  gotoxy(1,5);\n  printf(cedit_ascii_5);\n  gotoxy(1,6);\n  printf(cedit_ascii_6);\n  gotoxy(1,7);\n  outputcolor(0, 90);\n  printf(\"\\n%s\",auth);\n  outputcolor(0, 37);\n  timer2.ms=10;\n  timer2.ticks=0;\n  i=0;\n\n  outputcolor(0, 97);\n  do{\n    if (timerC(&timer2) == 1) { \n       gotoxy(i,8);\n       if (i==strlen(auth)) outputcolor(0,93);\n       if (i<10 || i>16) \n\tif (i<=strlen(auth)) printf(\"%c\", auth[i-1]);\n       printf(\"\\n\");\n       i++;\n     }\n    } while (timer2.ticks <30);\n//log\n// _printlist(&edBuf1);\n//  printf(\"%ld:%ld\\n\", posBufX, posBufY);\n//  printf(\"\\n%ld\\n\",sizeof(&edBuf1));\n \n  if (screen1 != NULL) deleteList(&screen1);\n  if (screen2 != NULL) deleteList(&screen2);\n  if (listBox1 != NULL) removeList(&listBox1);\n \n  _deletetheList(&edBuf1); //free edit Buffer\n  resetAnsi(0);\n  showcursor();\n  resetAnsi(0); \n}\n\nvoid _resizeScreen(){\n//redraw everything when screen size changes\n\tget_terminal_dimensions(&new_rows, &new_columns);\n\tif (screen1 != NULL) deleteList(&screen1);\n\tif (screen2 != NULL) deleteList(&screen2);\n\tcreate_screen(&screen1);\n\tcreate_screen(&screen1);\n\tdraw_screen();\n\tflush_editarea(0);\n\thdisplayArea = new_columns - 2;\t\n\tvdisplayArea = new_rows - 4;\n\t//if screen resizes file pointers are rewound to the beginning\n        currentLine = 0;\n\tposBufX = 0;\n\tposBufY = 0;\n\tshiftH = 0;\n\tbuffertoScreen(0);\n        dump_screen(screen1);\n\tcursorX = START_CURSOR_X;\n\tcursorY = START_CURSOR_Y;\n}\n\nint displayMessage(char *temporaryMessage, int x, int y, int fColor, int bColor, int timeDuration){\n//display a temporary nessage controlled by Timer3\n   if (timer3.ticks == -1) {\n           write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1);\n\t   return 0;\n   }\n  if (timer3.ticks  >= timeDuration) {\n\t  stop_timer(&timer3); \n          write_str(screen1, x,y, temporaryMessage, B_WHITE, F_WHITE,1);\n\t  return 0;\n  } \n   write_str(screen1, x,y, temporaryMessage, bColor, fColor,1);\n   return 1;\n}\n\n\n"
  },
  {
    "path": "src/menu.c",
    "content": "/* Module to display Menus on C·edit \n * for a Text User Interface\n * TextBox\n * Window\n * Last modified: 6/4/2024\n * @author:velorek\n */\n#include <stdio.h>\n#include \"rterm.h\"\n#include \"scbuf.h\"\n#include \"ui.h\"\n#include \"menu.h\"\n#include \"tm.h\"\n#include \"keyb.h\"\n#include \"global.h\"\n#include \"editor.h\"\n#include \"opfile.h\"\n#include \"fileb.h\"\n/*--------------------------------------------*/\n/* Load current menu into circular linked list*/\n/*--------------------------------------------*/\n\nvoid loadmenus(int choice) {\n\n  if(choice == HOR_MENU) {\n \tif (listBox1 != NULL) removeList(&listBox1);\n\tlistBox1 = addatend(listBox1, newitem(\"File\", 0, 1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Options\", 7, 1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Help\", 16, 1,-1,-1));\n    }\n  \n\n  if(choice == FILE_MENU) {\n \tif (listBox1 != NULL) removeList(&listBox1);\n\tlistBox1 = addatend(listBox1, newitem(\"New\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Open\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Quick load\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Save\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Save as...\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Exit\", -1, -1,-1,-1));\n }\n  if(choice == OPT_MENU) {\n \tif (listBox1 != NULL) removeList(&listBox1);\n\tlistBox1 = addatend(listBox1, newitem(\"File Info\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Find...\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"Colors\", -1, -1,-1,-1));\t\n  }\n  if(choice == HELP_MENU) {\n \tif (listBox1 != NULL) removeList(&listBox1);\n\tlistBox1 = addatend(listBox1, newitem(\"Help...\", -1, -1,-1,-1));\n\tlistBox1 = addatend(listBox1, newitem(\"About\", -1, -1,-1,-1));\t\n }\n/*\n  if(choice == YESNO_MENU) {\n    add_item(mylist, \"[YES]\", (columns / 2) - 11, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n    add_item(mylist, \"[NO]\", (columns / 2) - 3, (rows / 2) + 2,  MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n    add_item(mylist, \"[CANCEL]\", (columns / 2) + 4, (rows / 2) + 2,  MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n  }\n  if(choice == OK_MENU) {\n    add_item(mylist, \"[OK]\", (columns / 2) - 1, (rows / 2) + 2, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n  }\n  if(choice == OK_MENU2) {\n    add_item(mylist, \"[OK]\", (columns / 2) - 1, (rows / 2) + 3, MENU2_PANEL, MENU2_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n  }\n  if(choice == COLORS_MENU) {\n    add_item(mylist, \"C-Edit Theme\", (columns / 2) - 6, (rows / 2) - 2, \n        MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n    add_item(mylist, \"Classic Theme\", (columns / 2) - 6, (rows / 2) -1, \n        MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n    add_item(mylist, \"Dark Theme\", (columns / 2) - 6, (rows / 2), \n        MENU_PANEL, MENU_FOREGROUND0, MENU_SELECTOR, MENU_FOREGROUND1);\n  }\n*/\n}\n\n/*---------------\n Menu loop\nIt depends on two values passed by reference stored in the function from where this routine is called:\n-returnMenuChar\n-menuCounter\nIt does some tricky modulo operation to cycle back\n*/\nvoid handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu)\n{      \n\n      setselectorLimit(15);\n      copy_screen(screen2,screen1);\n      if (horizontalMenu) *returnMenuChar= horizontal_menu();  \n      do{\n      switch (*returnMenuChar) {\n\tcase 0: *menuCounter=FILE_MENU; *returnMenuChar=filemenu();  if (*returnMenuChar != DONT_UPDATE) xor_update(screen2,screen1); break;\n     \tcase 1: *menuCounter=OPT_MENU; *returnMenuChar=optionsmenu();  xor_update(screen2,screen1); break;\n\tcase 2: *menuCounter=HELP_MENU; *returnMenuChar=helpmenu(); xor_update(screen2,screen1);  break;\n\tdefault:\n\t\tbreak;\n      } \n      //convert -2 from right cursor to 1 to advance     \n      if (*returnMenuChar == -2 ) *returnMenuChar = 1; \n      *menuCounter=*menuCounter + *returnMenuChar;  \n      if (*returnMenuChar == K_ENTER) break;\n      if (*returnMenuChar == DONT_UPDATE) break;\n      if (*returnMenuChar != ESC_KEY ) {\n     \t\t\tcopy_screen(screen1,screen2);\n\t      \t\t//euclidian modulo, we circle back through the different switch cases\n\t                *returnMenuChar = ((*menuCounter % 3) + 3) % 3; \n\t }\n\n     } while (*returnMenuChar != ESC_KEY);\n     //xor_update(screen2,screen1);\n    if (*returnMenuChar != DONT_UPDATE){\n      copy_screen(screen1,screen2);\n      dump_screen(screen1);\n   }\n}\n//Entry menu- horizontal\nchar horizontal_menu() {\nchar ch=0;\n\n         dump_screen(screen1);\n         //Save current screen to screen2\n         loadmenus(HOR_MENU);\t\n\t//load menus from ui.c onto lisBox in (global.c)\n\t//dump_screen(screen1);\n        ch = listBox(listBox1, 0, 1 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  3, HORIZONTAL,0,1); \n        //delete listbox\n\tif(ch == ESC_KEY) scrollData.itemIndex = ch;; //to avoid warning\n\tremoveList(&listBox1);\n        //return option passed in scrollData (global.c)\n\treturn scrollData.itemIndex;\n}\n/*-------------------------*/\n/* Display File menu       */\n/*-------------------------*/\n\nchar filemenu() {  \n  char ch=0;\n  int countCh = 0;\n  char tempfileName[MAXFILENAME];\n  int ok2 = -1;\n  int retvalue = 0;\n  write_str(screen1,0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);\n  write_str(screen1,0, 1, \"File\", MENU_SELECTOR, MENU_FOREGROUND1,1);\n  loadmenus(FILE_MENU);\n  draw_window(screen1,0, 2, 13, 9, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1);\n  ch = listBox(listBox1, 3, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  -1, VERTICALWITHBREAK,0,1); \n    // copy_screen(screen1,screen2);\n    // dump_screen(screen1);\n      \n  //return if right and left arrow keys are pressed\n  if (ch == K_RIGHTMENU || ch == K_LEFTMENU) return ch;\n\n  if(scrollData.itemIndex == OPTION_1) {\n    flush_editarea(0);\n      buffertoScreen(0);\n      countCh=inputWindow(\"File:\", tempfileName,  \"[+] New file\",26,2,44);\n      if (countCh>0) {\n\t strcpy(fileName, tempfileName);\n\t filetoBuffer(fileName);\n         flush_editarea(0);\n         buffertoScreen(0);\n        dump_screen(screen1);\n     }//buffertoScreen(0, 0, 0);\n      ch=0;\n     return DONT_UPDATE;\n  }\n  \n  if(scrollData.itemIndex == OPTION_2) {\n     //openFile Dialog in opfile.c\n    flush_editarea(0);\n    buffertoScreen(0);\n     if (openFileDialog(fileName,fullPath) == 1){\n \t filetoBuffer(fileName);\n         flush_editarea(0);\n         buffertoScreen(0);\n     }\n\n        dump_screen(screen1);  \n     return DONT_UPDATE;\n  }\n  if(scrollData.itemIndex == OPTION_3) {\n    //External Module - Open file dialog.\n    //openFileHandler();\n      \n      flush_editarea(0);\n      buffertoScreen(0);\n      countCh=inputWindow(\"File:\", tempfileName,  \"Quick load...\",26,2,44);\n      if (countCh>0) {\n\t\t//check if it's a binary file\n\t    if (openandcheckFile(tempfileName) == 1){\n               ok2 = yesnoWindow(WCHECKFILE_MSG, \"Alert window\");\n\t       switch (ok2){\n\t        case 0: // open binary file anyway\n\t\t   retvalue=1;\n\t    \t   break;            \n\t        case 1: //don't open binary file\n\t \t  strcpy (fileName,\"\\0\");\n\t \t  strcpy (fullPath,\"\\0\");\n\t\t  retvalue=0;\n\t \t  break;\n\t    \tcase 2: //cancel is the same as no here\n\t\t  strcpy (fileName,\"\\0\");\n\t \t  strcpy (fullPath,\"\\0\");\n\t\t  retvalue=0;\n\t\tbreak;\n\t     } \n\t     }else{\n\t\t   retvalue = 1;\n\t     }\n         if (retvalue==1){\n     \t   strcpy(fileName, tempfileName);\n\t   filetoBuffer(fileName);\n           flush_editarea(0);\n           buffertoScreen(0);\n           dump_screen(screen1);\n\t }\n     }//buffertoScreen(0, 0, 0);\n     return DONT_UPDATE;\n\n  }\n  if(scrollData.itemIndex == OPTION_4) {\n       //Save file\n       flush_editarea(0);\n      buffertoScreen(0);\n    \t\n\tif (strcmp(fileName, \"UNTITLED\") == 0) {\n        countCh=inputWindow(\"File:\", tempfileName,  \"Save file as...\",26,2,44);\n        if (countCh>0) {\n\t     \t\n\t     strcpy(fileName, tempfileName);\n\t     buffertoFile(fileName);\n\t     flush_editarea(0);\n\t     buffertoScreen(0);\n            dump_screen(screen1);\n\t}\t\n       } else{\n\t   buffertoFile(fileName);\n\t   flush_editarea(0);\n\t   buffertoScreen(0);\n          dump_screen(screen1);\n       }\n\n\n     return DONT_UPDATE;\n  }\n  if(scrollData.itemIndex == OPTION_5) {\n    //Save as option\n       flush_editarea(0);\n      buffertoScreen(0);\n  \n    countCh=inputWindow(\"File:\", fileName,  \"Save file as...\",26,2,44);\n    if (countCh>0) {\n      buffertoFile(fileName);\n      flush_editarea(0);\n      buffertoScreen(0);\n      dump_screen(screen1);\n    }\n    return DONT_UPDATE;\n  }\n\n  if(scrollData.itemIndex == OPTION_6) {\n    //Exit option\n    //if(fileModified == 1)\n      //exitp = confirmation();\t//Shall we exit? Global variable!\n    //else\n      programStatus  = ENDSIGNAL;\n  }\n //restore previous screen\n //dump_screen(screen1);\n\t\nreturn ch;\n}\n\n/*--------------------------*/\n/* Display Options menu     */\n/*--------------------------*/\n\nchar optionsmenu() {\n  //int  setColor;\n  char ch=0;\n\n  write_str(screen1,6, 1, \"Options\", MENU_SELECTOR, MENU_FOREGROUND1,1);\n  write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);\n  loadmenus(OPT_MENU);\n  draw_window(screen1,6, 2, 19, 6, MENU_PANEL, MENU_FOREGROUND0,0, 1,0,1,1);\n  ch = listBox(listBox1, 9, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  -1, VERTICALWITHBREAK,0,1); \n  if(scrollData.itemIndex == OPTION_1) {\n    //File Info\n    //fileInfoDialog();\n  }\n  if(scrollData.itemIndex == OPTION_3) {\n    //Set Colors\n  /*  setColor = colorsWindow(mylist,COLORSWTITLE);\n    setColorScheme(setColor);\n    checkConfigFile(setColor);\t//save new configuration in config file\n    *///refresh_screen(1);\n  }\nreturn ch;\n\n}\n\n/*--------------------------*/\n/* Display Help menu        */\n/*--------------------------*/\n\nchar helpmenu() { \n  char ch= 0;\n\n  write_str(screen1,15, 1, \"Help\", MENU_SELECTOR, MENU_FOREGROUND1,1);\n  write_str(screen1, 0, new_rows, STATUS_BAR_MSG2, STATUSBAR, STATUSMSG,1);\n  loadmenus(HELP_MENU);\n  draw_window(screen1,15, 2, 25, 5, MENU_PANEL, MENU_FOREGROUND0, 0,1,0,1,1);\n  ch = listBox(listBox1, 18, 3 , &scrollData, MENU_PANEL, MENU_FOREGROUND0,  MENU_SELECTOR, MENU_FOREGROUND1,  -1, VERTICALWITHBREAK,0,1); \n  if(scrollData.itemIndex == OPTION_1 && ch>0) {\n    //Help dialog\n    //help_info();\n    flush_editarea(0);\n    buffertoScreen(0); \n     displayHelp();\n  }\n  if(scrollData.itemIndex == OPTION_2 && ch>0) {\n    //About info\n    flush_editarea(0);\n    buffertoScreen(0);\n  \n   displayAbout();\n  }\n  return ch;\n}\n\n//ABOUT\n\nint displayAbout(void)\n{\n\tchar ch = 0;\n\tint i = 0;\n\tint colAnimation = F_BLACK;\n\tint keypressed = 0;\n        int colCounter = 0;\n\tcopy_screen(screen2, screen1);\n\n\twindow(screen1, (new_columns / 2) - 18, (new_rows / 2) - 6,\n\t       (new_columns / 2) + 17, (new_rows) / 2 + 3, B_WHITE, F_BLACK,\n\t       B_BLACK, 1, 1, 1);\n\t\n\tfor (i = 0; i < 6; i++) {\n\t\twrite_str(screen1, (new_columns / 2) - 15,\n\t\t\t  (new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE,\n\t\t\t  F_BLACK, 0);\n\t}\n\t\n\twrite_str(screen1, (new_columns / 2) - 11, (new_rows / 2) - 7,\n\t\t \"[+] ABOUT INFORMATION\", B_BLACK, FH_WHITE, 1);\n\t\t \n//\twrite_str(screen1, (new_columns / 2) - 25, (new_rows / 2) + 2,\n\t\t  //aboutMSG[3], B_YELLOW, F_BLACK, 0);\n\twrite_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 2, \"[OK]\",\n\t\t  B_RED, FH_WHITE, 1);\n\t\n\tdump_screen(screen1);\n\t\n\tif (kbhit(100) == 1)\n\t\tch = readch();\n\tch = 0;\n\ti = 0;\n\tcolCounter = 0;\n\t//pulsating animation\n\tdo {\n\t\tkeypressed = kbhit(30);\n\t\tif (timerC(&timer2) == TRUE) {\n\t\t\t//About animation            \n\t\t\twrite_str(screen1, (new_columns / 2) - 15,\n\t\t\t\t  (new_rows / 2) - 5 + i, aboutMSG[i], B_WHITE,\n\t\t\t\t  colAnimation, 1);\n\t\t\ti++;\n\t\t\tif (i == 6) {\n\t\t\t\ti = 0;\n\t\t\t\tswitch (colCounter){\n\t\t\t\tcase 1:\n\t\t\t\t\tcolAnimation = FH_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2: \n\t\t\t\t\tcolAnimation = FH_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3: \n\t\t\t\t\tcolAnimation = FH_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4: \n\t\t\t\t\tcolAnimation = FH_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 5: \n\t\t\t\t\tcolAnimation = FH_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6: \n\t\t\t\t\tcolAnimation = FH_WHITE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 7: \n\t\t\t\t\tcolAnimation = FH_WHITE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8: \n\t\t\t\t\tcolAnimation = FH_WHITE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 9: \n\t\t\t\t\tcolAnimation = F_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 10: \n\t\t\t\t\tcolAnimation = F_BLACK;\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\n\t\t\t\t}\n\t\t\t\tcolCounter++;\n\t\t\t\tif (colCounter ==11) colCounter = 0;\n\t\t\t}\n\t\t\t//if terminal resizes\n\t\t\tif (_animation() == -1)\n\t\t\t\tbreak;\n\t\t}\n\t\t//Process keys\n\t\tif (keypressed == 1) {\n\t\t\tch = readch();\n\t\t\tkeypressed = 0;\n\n\t\t\t//Read special keys\n\t\t\tif (ch == K_ESCAPE) {\n\t\t\t\tch = readch();\n\t\t\t\tif (ch == ESC_KEY)\n\t\t\t\t  break;\n\t\t\t}\n\n\t\t}\n\t} while (ch != K_ENTER);\n        resetch();\n\tcopy_screen(screen1, screen2);\n\tif (listBox1 != NULL)\n\t\tremoveList(&listBox1);\n\tdump_screen(screen1);\n\treturn ch;\n}\nvoid addItemsHelp(LISTCHOICE **listBox1, char textarray[][MAXLINE], int rows)\n{\n\tint h=0;\n//Load items into the list.  \n\t//if (*listBox1 != NULL) removeList(listBox1);\n\tfor (h = 0; h < rows-1; h++) {\n\t\t//*ch = textarray[h];\n\t\t*listBox1 = addatend(*listBox1, newitem(textarray[h],-1,-1,-1,-1));\n\t}\n\t\t*listBox1 = addatend(*listBox1, newitem(textarray[rows-1],-1,-1,B_WHITE,FH_BLUE));\n}\nint displayHelp(void)\n{\n\tchar ch = 0;\n\tresetScrollData(&scrollData);\n\tif (listBox1 != NULL)\n\t\tremoveList(&listBox1);\n\t\n\tsetselectorLimit(26*2-1);\n\t//scrollData.selectorLimit = (26 * 2) - 1;\t//No. of chars per item display\n\t//scrollData.selectorLimit = 100;\t//No. of chars per item display\n //create_screen(&screen2);\n\tcopy_screen(screen2, screen1);\n\twindow(screen1, (new_columns / 2) - 26, (new_rows / 2) - 8,\n\t\t    (new_columns / 2) + 26, (new_rows) / 2 + 8, B_WHITE, F_BLACK,\n\t\t    B_BLACK, 1, 1, 1);\n\twrite_str(screen1, (new_columns / 2) - 12, (new_rows / 2) - 9,\n\t\t \"[+] MAIN HELP INFORMATION\", B_BLACK, FH_WHITE, 1);\n\t\n\twrite_str(screen1, (new_columns / 2) - 1, (new_rows / 2) + 7, \"[OK]\",\n\t\t  B_RED, F_WHITE, 1);\n\tdump_screen(screen1);\n\taddItemsHelp(&listBox1, help, HELPLINES);\n\tif (listBox1 != NULL)\n\t\tch = listBox(listBox1, (new_columns / 2) - 24,\n\t\t\t     (new_rows / 2) - 7, &scrollData, B_WHITE, F_BLACK,\n\t\t\t     B_WHITE, FH_WHITE, 14, VERTICAL,1,LOCKED);\n\tcopy_screen(screen1, screen2);\n//\tif (screen2 != NULL)\n//\t\tdeleteList(&screen2);\n\tif (listBox1 != NULL)\n\t\tremoveList(&listBox1);\n\tdump_screen(screen1);\n\treturn ch;\n}\n\n"
  },
  {
    "path": "src/menu.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule with all menus on C·EDIT\n@author : Velorek\n@version : 1.0\nLast modified: 06/04/2024\n========================================================================\n*/\n\n#ifndef _MENU_H_\n#define _MENU_H_\n\n#include \"scbuf.h\"\n#include <stdio.h>\n\nvoid loadmenus(int choice);\nchar horizontal_menu();\nchar filemenu();\nchar optionsmenu();\nchar helpmenu();\nvoid credits();\nvoid handlemenus(char *returnMenuChar, int *menuCounter, BOOL horizontalMenu);\nint displayAbout();\nint displayHelp(void);\n\n#endif\n\n\n"
  },
  {
    "path": "src/opfile.c",
    "content": "/*====================================================================*/\n/* OPEN FILE MODULE\n   +ListFiles with double linked list and selection menu in C.\n   +Scroll function added.\n   +Integrated with C-EDIT\n   A window is drawn to the buffer and all of the scroll animations\n   are drawn to the terminal on raw mode to have a better scrolling\n   animation. Once the file is selected, the window is closed and the\n   previous screen is painted to the terminal again.\n   Last modified : 11/1/2019 - Switch to readch() instead of getch()\n                   06/04/2019 - Corrected all memory leaks\n\t\t   14/04/2019 - Rename headers\n\t\t   22/04/2020 - Added Set File to Open\n\t\t   23/04/2023 - Merged with Lynx and vastly simplified\n   Coded by Velorek.\n   Target OS: Linux.                                                  */\n/*====================================================================*/\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES */\n/*====================================================================*/\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <dirent.h>\n#include \"rterm.h\"\n#include \"scbuf.h\"\n#include \"listbox.h\"\n#include \"tm.h\"\n#include \"keyb.h\"\n#include \"global.h\"\n#include \"opfile.h\"\n#include \"ui.h\"\n#include \"fileb.h\"\n/*====================================================================*/\n/* GLOBAL VARIABLES */\n/*====================================================================*/\n\nint     window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;\nint ndirs=0, nfiles=0;\n\n/*====================================================================*/\n/* CODE */\n/*====================================================================*/\n\nint listFiles(LISTCHOICE ** listBox1, char *directory) {\n  DIR    *d;\n  struct dirent *dir;\n  int     i;\n  char    temp[MAX_ITEM_LENGTH];\n  int     lenDir;       //length of directory\n  ndirs=0;\n  nfiles=0;\n  if (*listBox1 != NULL) removeList(listBox1);\n  *listBox1 = addatend(*listBox1, newitem(\"[..]\",-1,-1,FH_BLUE,B_WHITE));    // \"..\"\n\n  //Start at current directory\n  d = opendir(directory);\n  //Find directories and add them to list first\n  if(d) {\n    while((dir = readdir(d)) != NULL) {\n      if(dir->d_type == DT_DIR) {\n\n    lenDir = strlen(dir->d_name);\n\n    //Check length of directory\n    //Directories are displayed between brackets [directory]\n    if(lenDir > MAX_ITEM_LENGTH - 2) {\n      //Directory name is long. CROP\n      memset(&temp, '\\0',sizeof(temp)); //Clear memory for temporary line\n      strcpy(temp,\"\\0\");\n      strcpy(temp, \"[\");\n      for(i = 1; i < MAX_ITEM_LENGTH - 1; i++) {\n        temp[i] = dir->d_name[i - 1];\n      }\n      temp[MAX_ITEM_LENGTH - 1] = ']';\n    } else {\n      //Directory's name is shorter than display\n      //Add spaces to item string.\n      memset(&temp, '\\0',sizeof(temp)); //Clear memory for temporary line\n      strcpy(temp,\"\\0\");\n      strcpy(temp, \"[\");\n      for(i = 1; i < lenDir + 1; i++) {\n        temp[i] = dir->d_name[i - 1];\n      }\n      temp[lenDir + 1] = ']';\n    }\n    //Add all directories except CURRENTDIR and CHANGEDIR\n    if(strcmp(dir->d_name, \".\") != 0\n       && strcmp(dir->d_name, \"..\") != 0)\n    { ndirs++;\n      *listBox1 =\n          addatend(*listBox1, newitem(temp, -1,-1,FH_BLUE,B_WHITE));}\n      }\n    }\n  }\n  closedir(d);\n\n  //Find files and add them to list after directories\n  d = opendir(directory);\n  if(d) {\n    while((dir = readdir(d)) != NULL) {\n      if(dir->d_type == DT_REG) {\n    //only list valid fiels\n    if(strlen(dir->d_name) > MAX_ITEM_LENGTH) {\n      for(i = 0; i < MAX_ITEM_LENGTH; i++) {\n        temp[i] = dir->d_name[i];\n      }\n    } else {\n      memset(&temp, '\\0',sizeof(temp)); //Clear memory for temporary line\n      strcpy(temp,\"\\0\");\n      strcpy(temp, dir->d_name);\n    }\n    nfiles++;\n    *listBox1 =\n        addatend(*listBox1, newitem(temp, -1,-1,-1,-1));\n      }\n    }\n    closedir(d);\n  }\n  \n  return 0;\n}\n\nvoid addItems(LISTCHOICE **listBox1)\n{\n\tint h=0;\n//Load items into the list.  \n        //if (listBox1 != NULL) removeList(listBox1);\n\tfor (h = 0; h <10; h++) {\n\t\t//*ch = textarray[h];\n\t\t*listBox1 = addatend(*listBox1, newitem(\"Test\",-1,-1,-1,-1));\n\t}\n}\n\nint openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]){\nchar ch=0;\nchar path[MAXFILENAME];\nchar bit[MAXFILENAME];\nchar ndirstr[100];\nsize_t i=0;\nint ok2 =0;\nint retvalue=0;\nchar nfilestr[100];\nchar currentPath[4] = \"./\\0\";\n    retvalue =0;\n    setselectorLimit(23);\n    window_y1 = (new_rows / 2) - 10;\n    window_y2 = (new_rows / 2) + 10;\n    window_x1 = (new_columns / 2) - 13;\n    window_x2 = (new_columns / 2) + 13;   \n   copy_screen(screen2,screen1);\n   old_rows = new_rows;\n   old_columns = new_columns; \n   do{\n     draw_window(screen1,window_x1, window_y1, window_x2, window_y2,B_WHITE,F_BLACK,B_BLACK,1,1,1,0);\n     draw_window(screen1,window_x1, window_y2-3, window_x2, window_y2,B_CYAN,F_WHITE,B_BLACK,1,0,0,0);\n     dump_screen(screen1);\n      listFiles(&listBox1,currentPath);\n      sprintf(ndirstr, \"[%d] Directories\", ndirs);\n      sprintf(nfilestr, \"[%d] Files\", nfiles);\n      write_str(screen1,window_x1+2,window_y2-2,ndirstr,B_CYAN,FH_WHITE,1);\n      write_str(screen1,window_x1+2,window_y2-1,nfilestr,B_CYAN,F_WHITE,1);\n      write_str(screen1,window_x1+1,window_y2-4, \"   PRESS [ESC] TO EXIT   \",B_BLACK,FH_WHITE,1);\n      write_str(screen1,window_x1+2,window_y1,\"Select file...\",B_BLACK,FH_WHITE,1);\n      ch = listBox(listBox1, window_x1+3,window_y1+1, &scrollData, B_WHITE, F_BLACK,B_RED, FH_WHITE, 15, VERTICAL,1,LOCKED);\n      if (_animation() == -1) {ch=K_ESCAPE; break;} \n      if (ch == 0x27) {break;} \n      if (ch == K_ENTER){\n\n        if (scrollData.item[0] == '[') {\n\t //directory   \n            memset(&path, '\\0',sizeof(path)); //Clear memory for temporary line\n            memset(&bit, '\\0',sizeof(bit)); //Clear memory for temporary line\n    \t    strcpy(bit,\"\\0\");\n            strcpy(path,\"\\0\");\n            for (i=1; i<strlen(scrollData.item)-1; i++) bit[i-1] = scrollData.item[i];\n\t    getcwd(path, sizeof(path));\n\t    strcat(path, \"/\");\n\t    strcat(path, bit);\n\t    chdir(path);\n\t    ch=0;\n      }\n      else {\n\t     break;\n      }\t \n    } \n   } while (ch!=ESC_KEY);   \n    setselectorLimit(15);\n   \n\n    if (ch!=27){\n    \t    //we pass the values\n            //memset(&fullPath, '\\0',sizeof(fullPath)); //Clear memory for temporary line\n            memset(fileName, '\\0', strlen(fileName) + 1); // Clear memory for temporary line\n            memset(fullPath, '\\0', strlen(fullPath) + 1); // Clear memory for temporary line\n           // memset(&fileName, '\\0',sizeof(fileName)); //Clear memory for temporary line\n    \t    strcpy(bit,\"\\0\");\n            strcpy(path,\"\\0\");\n            strcpy(fileName, scrollData.item);\n            strcpy(fullPath, path);\n\t    //reset scroll values\n\t    cursorX=START_CURSOR_X;\n\t    cursorY=START_CURSOR_Y;\n\t    currentLine=0;\n\t    shiftH=0;\n\t    posBufX=0;\n\t    posBufY = 0;\n\t    retvalue = 1;\n    }\n    if (listBox1 != NULL) removeList(&listBox1);\n   copy_screen(screen1,screen2); \n   //Finally check if it is a binary file\n   if (openandcheckFile(fileName) == 1){\n           ok2 = yesnoWindow(WCHECKFILE_MSG, \"Alert window\");\n\t switch (ok2){\n\t    case 0: // open binary file anyway\n\t\tretvalue=1;\n\t    \tbreak;            \n\t    case 1: //don't open binary file\n\t \tstrcpy (fileName,\"\\0\");\n\t \tstrcpy (fullPath,\"\\0\");\n\t\tretvalue=0;\n\t \tbreak;\n\t    case 2: //cancel is the same as no here\n\t\tstrcpy (fileName,\"\\0\");\n\t \tstrcpy (fullPath,\"\\0\");\n\t\tretvalue=0;\n\t\tbreak;\n\t   }\n\t } else{\n\t\t //file is a text file\n    }\n   return retvalue;\n}\n\n\n\n\n"
  },
  {
    "path": "src/opfile.h",
    "content": "/*\n========================================================================\n- HEADER - \nModule to open a file by showing a dialogue that allows you to navigate \nthrough directories with a list with scroll.\n@author : Velorek\n@version : 1.0  \nLast modified: 23/04/2024 Vastly simplified and integraed with lynx\n========================================================================\n*/\n\n#ifndef _OPFILE_H_\n#define _OPFILE_H_\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <dirent.h>\n#include \"rterm.h\"\n#include \"scbuf.h\"\n#include \"listbox.h\"\n#include \"tm.h\"\n#include \"keyb.h\"\n#include \"global.h\"\n\n/*====================================================================*/\n/* CONSTANTS */\n/*====================================================================*/\n#define MAX_ITEM_LENGTH 15\n\n\n/*====================================================================*/\n/* CONSTANT VALUES                                                    */\n/*====================================================================*/\n\n/*====================================================================*/\n/* FUNCTION PROTOTYPES                                                */\n/*====================================================================*/\n\nint listFiles(LISTCHOICE ** listBox1, char *directory);\nvoid addItems(LISTCHOICE **listBox1);\nint openFileDialog(char fileName[MAXFILENAME], char fullPath[MAXFILENAME]);\n\n\n#endif\n"
  },
  {
    "path": "src/rterm.c",
    "content": "/*\n======================================================================\nModule to control some display routines that implement ANSI functions.\non LINUX Terminals\n\n@author : Velorek (routines extracted from the internet)\n@version : 1.0\n\nLAST MODIFIED : 18/01/2023 Kbhit with poll control added\n======================================================================\n*/\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <termios.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <locale.h>\n#include <sys/ioctl.h>\n#include <poll.h>\n#include \"rterm.h\"\n#include \"keyb.h\"\n/*====================================================================*/\n/* GLOBAL VARIABLES                                                   */\n/*====================================================================*/\n\nstruct winsize max;\nstatic struct termios term, failsafe;\nstatic int peek_character = -1;\n\n/*====================================================================*/\n/* FUNCTIONS - CODE                                                   */\n/*====================================================================*/\n\n/*-------------------------------------*/\n/* Initialize new terminal i/o settings*/\n/*-------------------------------------*/\nvoid pushTerm() {\n//Save terminal settings in failsafe to be retrived at the end\n  tcgetattr(0, &failsafe);\n}\n\n/*---------------------------*/\n/* Reset terminal to failsafe*/\n/*---------------------------*/\nint resetTerm() {\n  //tcsetattr(0, TCSANOW, &failsafe);\n  /* flush and reset */\n  if (tcsetattr(0,TCSAFLUSH,&failsafe) < 0) return -1;\n  return 0;\n}\n\n\n/*--------------------------------------.*/\n/* Detect whether a key has been pressed.*/\n/*---------------------------------------*/\n\nint kbhit(int timeout_ms)\n{\n    struct pollfd fds = {STDIN_FILENO, POLLIN, 0};\n    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);\n    int ret = poll(&fds, 1, timeout_ms);\n    fcntl(STDIN_FILENO, F_SETFL, 0);\n    if (ret > 0) {\n        return 1;\n    } else if (ret == 0) {\n        return 0; // timeout occurred\n    } else {\n        return -1; // error occurred\n    }\n}\n\n/*----------------------*/\n/*Read char with control*/\n/*----------------------*/\nchar readch() {\n  char    ch;\n if(peek_character != -1) {\n    ch = peek_character;\n    peek_character = -1;\n    return ch;\n  }\n  read(0, &ch, 1);\n  return ch;\n}\n\nvoid resetch() {\n//Clear ch\n  term.c_cc[VMIN] = 0;\n  tcsetattr(0, TCSANOW, &term);\n  peek_character = 0;\n}\n\n/*----------------------------------*/\n/* Move cursor to specified position*/\n/*----------------------------------*/\nvoid gotoxy(int x, int y) {\n  printf(\"%c[%d;%df\", 0x1B, y, x);\n}\n\n/*---------------------*/\n/* Change colour output*/\n/*---------------------*/\nvoid outputcolor(int foreground, int background) {\n  printf(\"%c[%d;%dm\", 0x1b, foreground, background);\n}\n\n/*-----------------------------------------------------*/\n/* Change the whole color of the screen by applying CLS*/\n/*-----------------------------------------------------*/\nvoid screencol(int x) {\n  gotoxy(0, 0);\n  outputcolor(0, x);\n  printf(\"%c[2J\", 0x1b);\n  outputcolor(0, 0);\n}\n\n/*-----------------------*/\n/* Reset ANSI ATTRIBUTES */\n/*-----------------------*/\nvoid resetAnsi(int x) {\n  switch (x) {\n    case 0:         //reset all colors and attributes\n      printf(\"%c[0m\", 0x1b);\n      break;\n    case 1:         //reset only attributes\n      printf(\"%c[20m\", 0x1b);\n      break;\n    case 2:         //reset foreg. colors and not attrib.\n      printf(\"%c[39m\", 0x1b);\n      break;\n    case 3:         //reset back. colors and not attrib.\n      printf(\"%c[49m\", 0x1b);\n      break;\n    default:\n      break;\n  }\n}\n\n/*------------------------*/\n/* Get terminal dimensions*/\n/*------------------------*/\nint get_terminal_dimensions(int *rows, int *columns) {\n  ioctl(0, TIOCGWINSZ, &max);\n  *columns = max.ws_col;\n  *rows = max.ws_row;\n  return 0;\n}\n\n/*--------------------------*/\n/* Ansi function hide cursor*/\n/*--------------------------*/\nvoid hidecursor() {\n  printf(\"\\e[?25l\");\n}\n\n/*--------------------------*/\n/* Ansi function show cursor*/\n/*--------------------------*/\nvoid showcursor() {\n  printf(\"\\e[?25h\");\n}\n/*----------------------------------*/\n/* Get cursor  position             */\n/*----------------------------------*/\n\nint get_pos(int *y, int *x) {\n\n char buf[30]={0};\n int ret, i, pow;\n char ch;\n\n*y = 0; *x = 0;\n\n struct termios term, restore;\n\n tcgetattr(0, &term);\n tcgetattr(0, &restore);\n term.c_lflag &= ~(ICANON|ECHO);\n tcsetattr(0, TCSANOW, &term);\n\n write(1, \"\\033[6n\", 4);\n\n for( i = 0, ch = 0; ch != 'R'; i++ )\n {\n    ret = read(0, &ch, 1);\n    if ( !ret ) {\n       tcsetattr(0, TCSANOW, &restore);\n       //fprintf(stderr, \"getpos: error reading response!\\n\");\n       return 1;\n    }\n    buf[i] = ch;\n    //printf(\"buf[%d]: \\t%c \\t%d\\n\", i, ch, ch);\n }\n\n if (i < 2) {\n    tcsetattr(0, TCSANOW, &restore);\n    //printf(\"i < 2\\n\");\n    return(1);\n }\n\n for( i -= 2, pow = 1; buf[i] != ';'; i--, pow *= 10)\n     *x = *x + ( buf[i] - '0' ) * pow;\n\n for( i-- , pow = 1; buf[i] != '['; i--, pow *= 10)\n     *y = *y + ( buf[i] - '0' ) * pow;\n\n tcsetattr(0, TCSANOW, &restore);\n return 0;\n}\n/*--------------------------*/\n/* Set up terminal          */\n/*--------------------------*/\n\n//For code simplification purposes\nvoid init_term(void)\n\n{\n        //switch to alternate screen buffer\n        printf(\"\\033[?1049h\");\n\thidecursor();\n\tpushTerm();\n\tresetch();\n\t//Setup unicode  \n\tsetlocale(LC_ALL, \"\");\n}\n\nvoid close_term(void)\n{\n\tshowcursor();\n\tresetTerm();\n\tresetAnsi(0);\n\t//restore previous screen\n        printf(\"\\033[?1049l\");\n\t//cls\n\tgotoxy(0,0);\n\tprintf(\"%c[2J\\r\", 0x1b);\n\n}\n/*\nvoid init_term(){\n  hidecursor();\n  pushTerm();\n  resetch();\n  //Setup unicode  \n  setlocale(LC_ALL, \"\");\n}\n\n\nvoid close_term(){\n  showcursor();\n  resetTerm();\n  outputcolor(F_WHITE, B_BLACK);\n  screencol(B_BLACK);\n  resetAnsi(0);\n  printf(\"\\n\");\n}\n*/\n\n"
  },
  {
    "path": "src/rterm.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule to control some display routines that implement ANSI functions.\n@author : Velorek\n@version : 1.0\nLast modified: 15/09/2021 + Linux Term\n========================================================================\n*/\n\n#ifndef _RTERM_H_\n#define _RTERM_H_\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <termios.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/ioctl.h>\n\n/*====================================================================*/\n/* COLOR CONSTANTS                                                    */\n/*====================================================================*/\n\n// Background colors low intensity\n#define B_BLACK 40\n#define B_RED 41\n#define B_GREEN 42\n#define B_YELLOW 43\n#define B_BLUE 44\n#define B_MAGENTA 45\n#define B_CYAN 46\n#define B_WHITE 47\n\n// Foreground colors low intensity\n#define F_BLACK 30\n#define F_RED 31\n#define F_GREEN 32\n#define F_YELLOW 33\n#define F_BLUE 34\n#define F_MAGENTA 35\n#define F_CYAN 36\n#define F_WHITE 37\n//#define F_WHITE 37\n#define F_GREY 90\n\n// Background colors high intensity\n#define BH_BLACK 100\n#define BH_RED 101\n#define BH_GREEN 102\n#define BH_YELLOW 103\n#define BH_BLUE 104\n#define BH_MAGENTA 105\n#define BH_CYAN 106\n#define BH_WHITE 107\n\n// Foreground colors high intensity\n#define FH_BLACK 90\n#define FH_RED 91\n#define FH_GREEN 92\n#define FH_YELLOW 93\n#define FH_BLUE 94\n#define FH_MAGENTA 95\n#define FH_CYAN 96\n#define FH_WHITE 97\n\n#define TRUE 1\n#define FALSE 0\n\n//Keys used.\n#define K_ENTER 13\n#define K_ENTER2 10\n#define K_ESCAPE 27\n#define K_UP_TRAIL \"\\e[A\\0\\0\"\n#define K_DOWN_TRAIL \"\\e[B\\0\\0\"\n#define K_RIGHT_TRAIL \"\\e[C\\0\\0\"\n#define K_LEFT_TRAIL \"\\e[D\\0\\0\"\n\n\n//#define K_UP_ARROW 'A'      // K_ESCAPE + 'A' -> UP_ARROW\n//#define K_DOWN_ARROW 'B'    // K_ESCAPE + 'B' -> DOWN_ARROW\ntypedef int BOOL;\n\n/*====================================================================*/\n/* FUNCTION PROTOTYPES                                                */\n/*====================================================================*/\n\nvoid    pushTerm();\nint     resetTerm();\nint kbhit(int timeout_ms);\n\t\nchar     readch();\nchar     getch();\nvoid    resetch();\n//char    getch(void);\nvoid    gotoxy(int x, int y);\nvoid    outputcolor(int foreground, int background);\nvoid    screencol(int x);\nvoid    resetAnsi(int x);\nint     get_terminal_dimensions(int *rows, int *columns);\nint get_pos(int *y, int *x);\nvoid    showcursor();\nvoid    hidecursor();\nvoid    init_term();\nvoid    close_term();\n#endif\n"
  },
  {
    "path": "src/scbuf.c",
    "content": "/* Module to create a screen buffer\n * to act as an intermediate step between screen output and\n * the display so as to create a Text User Interface.\n * @author:velorek\n * Last modified: 1/02/2019\n */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"rterm.h\"\n#include \"scbuf.h\"\n\n#define ROWS_FAILSAFE 25\n#define COLUMNS_FAILSAFE 80\n#define FILL_CHAR 32\n\n  int     sc_rows=0, sc_columns=0;\n  int     buffersize=0;\n \n\n/* SINGLE LINKED LIST ROUTINES */\n// create new list element of type SCREENCELL from the supplied text string\nSCREENCELL *newelement(SCREENCELL temp)\n{\n\tSCREENCELL *newp;\n\tnewp = (SCREENCELL *) malloc (sizeof(SCREENCELL));\n\tnewp->index = temp.index;\n\tnewp->backColor = temp.backColor;\n\tnewp->foreColor = temp.foreColor;\n        newp->toUpdate = 0;\n\tnewp->ch = temp.ch;\n        newp->next = NULL;\n\treturn newp;\n}\n\n\nvoid deleteList(SCREENCELL **head) \n{ \n   /* deref head_ref to get the real head */\n   SCREENCELL *current = *head; \n   SCREENCELL *next = NULL;\n   while (current != NULL)  \n   { \n       next = current->next; \n       free(current);\n       current = next; \n   }\n  \n   free(current);\n   free(next);\n   current = NULL;\n   next = NULL;\n   *head = NULL; \n} \n\n/* addfront: add new SCREENCELL to front of list  */\n/* example usage: start = (addfront(start, newelement(\"burgers\")); */\n\nSCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp)\n{\n\tnewp -> next = head;\n\treturn newp;\n}\n\n/* addend: add new SCREENCELL to the end of a list  */\n/* usage example: start = (addend(start, newelement(\"wine\")); */\n\nSCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp)\n{\n\tSCREENCELL *p2; \t\n\tif (head == NULL)\n\t\treturn newp;\n// now find the end of list\n\tfor (p2 = head; p2 -> next != NULL; p2 = p2 -> next)\n\t\t;\n\tp2 -> next = newp;\n\treturn head;\n}\n\n\nint length(SCREENCELL **head)\n// this routine uses pointer-to-pointer techniques :-)\n{\n\n\tint count=0;\n\tSCREENCELL **tracer = head;\n\twhile ((*tracer) != NULL) {\n\t\tcount = count +1;\t\n\t\ttracer = &(*tracer)->next;\n\t}\n       return count;\n}\n\nvoid reindex(SCREENCELL **head)\n{\n\tint count=0;\t\n\tSCREENCELL *p=NULL;\n\tSCREENCELL **tracer = head;\n\twhile ((*tracer) != NULL) {\n\t\tp = *tracer;\n\t\tp->index=count;\n\t\tcount = count +1;\n\t\ttracer = &(*tracer)->next;\n\t}           \n}\n\n/* SCREEN BUFFER ROUTINES */\n\nint create_screen(SCREENCELL **newScreen){\n /*\n     Get terminal dimensions and create a dynamic list with the size of the screen.\n     if it is not possible to determine screen dimensions default is set to 80x25.\n     Insertion happens at the end of the list.   */\n  int     i=0;\n  SCREENCELL   temp;\n  SCREENCELL  **aux = newScreen;\n\n  //We attempt to get terminal dimensions. If not\n  //successful failsafe values (80x25) apply.\n  get_terminal_dimensions(&sc_rows, &sc_columns);\n  if(sc_rows == 0)\n    sc_rows = ROWS_FAILSAFE;\n  if(sc_columns == 0)\n    sc_columns = COLUMNS_FAILSAFE;\n  buffersize = sc_rows * sc_columns;\n\n  // Assign dummy data to Screen buffer\n   if(*aux == NULL) {\n    //All cells have the same init data\n       temp.ch = FILL_CHAR;\n       temp.backColor = B_BLACK;\n       temp.foreColor = F_WHITE; \n     for(i = 0; i < buffersize; i++) {\n      //Except for their index\n      temp.index = buffersize - 1 - i;\n      *aux = addfront(*aux, newelement(temp)); \n     }\n     return 1; \n   } else{\n      //Pointer is not void\n     return 0;\n   }\n}\nvoid copy_screen(SCREENCELL *destination,SCREENCELL *source){\n  int     i=0;\n  SCREENCELL *aux1=destination;\n  SCREENCELL *aux2=source;\n   //We attempt to get terminal dimensions. If not\n  //successful failsafe values (80x25) apply.\n if((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2)) ) {\n   for(i = 0; i < buffersize; i++) {\n      aux1->backColor = aux2->backColor;\n      aux1->foreColor = aux2->foreColor;\n      aux1->ch = aux2->ch;\n      aux1 = aux1->next;\n      aux2 = aux2->next;\n    }\n   }\n}\n\n\n/*------------------------------------------*/\n/* Update single char to screen for display */\n/*------------------------------------------*/\nvoid update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor) {\n//Write Unicode char to screen raw\n   resetAnsi(0);\n   gotoxy(x+1, y+1);\n   outputcolor(forecolor, backcolor);\n   printf(\"%lc\", ch);  //unicode\n}\n\nvoid write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor,BOOL raw) {\n/* Update cell on screenbuffer. It will be shown on screen when it is updated by calling update_screen */\n  int     i, pos;\n\n  SCREENCELL *aux = newScreen;\n  resetAnsi(0);\n  if (aux != NULL && buffersize <= length(&aux)){\n\n    pos = (y - 1) * sc_columns + x;   //This is the formula to calculate the position index in the screen buffer\n    if(pos < buffersize) {\n      // If it is within buffer limits, otherwise do nothing.\n      for(i = 0; i <= pos; i++) {\n        //Run through the buffer until reaching desired position\n        if (aux->index == pos)\n      break;\n        aux = aux->next;\n      }\n      //Update cell info at position selected.\n      //Manage special charaters as well.\n\t  aux->ch = ch;\n          aux->backColor = backcolor;\n          aux->foreColor = forecolor;\n          aux->toUpdate = 1;\n\n        if(raw==TRUE) {\n   \t\tgotoxy(x+1, y);\n   \t\toutputcolor(forecolor, backcolor);\n   \t\tif (ch>31) printf(\"%lc\", ch);  //unicode\n         }\n    }\n  }\n}\n\nSCREENCELL read_cell(SCREENCELL *newScreen, int x, int y) {\n/* read specific character with attributes from buffer */\n  int     i=0, pos=0;\n  SCREENCELL *aux=newScreen;\n  SCREENCELL ret ={};\n  if (aux != NULL && buffersize <= length(&aux)){\n    pos = (y - 1) * sc_columns + x;\t//this is the formula to calculate the position index in the screen buffer\n   if(pos < buffersize) {\n    for(i = 0; i <= pos; i++) {\n        //run through the buffer until reaching desired position\n        if(aux->index == pos)\n\t  break;\n        aux = aux->next;\n    }\n    ret.index = aux->index;\n    ret.ch = aux->ch;\n    //for some unknown reason these values have to be inverted\n    ret.backColor = aux->foreColor;\n    ret.foreColor = aux->backColor;\n    ret.next = NULL;\n   }\n }\n  return ret;\n}\n\n\nwchar_t read_char(SCREENCELL *newScreen, int x, int y) {\n/* read specific character from buffer */\n  int     i=0, pos=0;\n  wchar_t ch = FILL_CHAR;\n  SCREENCELL *aux=newScreen;\n  if (aux != NULL && buffersize <= length(&aux)){\n    pos = (y - 1) * sc_columns + x;\t//this is the formula to calculate the position index in the screen buffer\n   if(pos < buffersize) {\n    for(i = 0; i <= pos; i++) {\n        //run through the buffer until reaching desired position\n        if(aux->index == pos)\n\t  break;\n        aux = aux->next;\n    }\n    ch = aux->ch; \n   }\n }\n  return ch;\n}\n\n/*------------------------------------------*/\n/* Writes a string of characters to buffer. */\n/*------------------------------------------*/\n\nvoid write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw) {\n  //Writes a string of characters to buffer.\n  char   *astr=NULL;\n  size_t     i=0;\n  int wherex=0;\n  SCREENCELL *aux = newScreen;\n\n  if (aux!=NULL){\n    wherex = x;\n    astr = str;\n    for(i = 0; i <= strlen(str) - 1; i++) {\n      write_ch(aux, wherex, y, astr[i], backcolor, forecolor,raw);\n      wherex = wherex + 1;\n    }\n }\n}\n\n/*------------------------------------------*/\n/* Writes a string of characters to screen. */\n/*------------------------------------------*/\n\nvoid update_str(int x, int y, char *str, char backcolor, char forecolor) {\n  //Writes a string of characters to buffer.\n  char   *astr=NULL;\n  size_t     i=0;\n  int wherex=0;\n\n    resetAnsi(0);\n    wherex = x;\n    astr = str;\n    for(i = 0; i <= strlen(str) - 1; i++) {\n      update_ch(wherex, y, astr[i], backcolor, forecolor);\n      wherex = wherex + 1;\n    }\n}\n\n/*-----------------------------------------------*/\n/* Writes an integer value as a string on screen */\n/*-----------------------------------------------*/\n\nint write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,\n\t       char forecolor, BOOL raw) {\n  //the length of the string must be passed on the function\n  char   astr[30];\n  char len=0;\n  SCREENCELL *aux = newScreen;\n\n  if (aux!=NULL){\n    sprintf(astr, \"%d\", num);\n    write_str(newScreen, x, y, astr, backcolor, forecolor,raw);\n    len = strlen(astr);\n  }\n  return len;\n}\n\nvoid screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch) {\n/* Changes the color of all the cells to create the effect of changing color in the background */\n  int     i=0;\n  SCREENCELL *aux=newScreen;\n  resetAnsi(0);\n  //screen should be updated twice to get round the last row glitch\n  if (aux != NULL && buffersize <= length(&aux)){ \n   for(i = 0; i < buffersize; i++) {\n      aux->backColor = bcolor;\n      aux->foreColor = fcolor;\n      aux->ch = ch;\n      aux->toUpdate = 1;\n      aux = aux->next;\n    }\n }\n}\n\n/*------------------------------------*/\n/* Dumps buffer to screen for display */\n/*------------------------------------*/\n\n\nvoid dump_screen(SCREENCELL *newScreen) {\n/* UPDATES ALL SCREEN CELLS TO DISPLAY */\n  int     i=0;\n  int     wherex=0, wherey=0;\n  SCREENCELL *aux=newScreen;\n  if (aux!=NULL && buffersize <= length(&aux)){\n  for(i = 0; i < buffersize; i++) {\n      update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor); \n      wherex = wherex + 1; //line counter\n      if(wherex == sc_columns) {\n        //new line\n        wherex = 0;\n        wherey = wherey + 1;\n      }\n      aux = aux->next;\n    }\n  }\n}\n\nvoid update_screen(SCREENCELL *newScreen) {\n/* UPDATES ALL SCREEN CELLS TO DISPLAY */\n  int     i=0;\n  int     wherex=0, wherey=0;\n  SCREENCELL *aux=newScreen;\n  if (aux!=NULL && buffersize <= length(&aux)){\n  for(i = 0; i < buffersize; i++) {\n      if (aux->toUpdate ==1) {aux->toUpdate = 0; update_ch(wherex,wherey,aux->ch,aux->backColor,aux->foreColor);} \n      wherex = wherex + 1; //line counter\n      if(wherex == sc_columns) {\n        //new line\n        wherex = 0;\n        wherey = wherey + 1;\n      }\n      aux = aux->next;\n    }\n  }\n}\n\n\nvoid xor_update(SCREENCELL *screen1, SCREENCELL *screen2) {\n/* UPDATE only the cells that are different */\n  int     i=0;\n  int     wherex=0, wherey=0;\n  SCREENCELL *aux1=screen1;\n  SCREENCELL *aux2=screen2;\n  if ((aux1!=NULL && aux2!=NULL) && (length(&aux1) == length(&aux2))){\n   for(i = 0; i < buffersize; i++) {\n     if (aux1->ch != aux2->ch || aux1-> backColor != aux2 -> backColor || aux1-> foreColor != aux2 -> foreColor){ \n       update_ch(wherex,wherey,aux1->ch,aux1->backColor,aux1->foreColor);\n      } \n      wherex = wherex + 1; //line counter\n      if(wherex == sc_columns) {\n        //new line\n        wherex = 0;\n        wherey = wherey + 1;\n      }\n      aux1 = aux1->next;\n      aux2 = aux2->next;\n    }\n  }\n}\n\n\nvoid xor_copy(SCREENCELL *screen1, SCREENCELL *screen2)\n{\n/* UPDATES ALL SCREEN CELLS TO DISPLAY */\n\tint i = 0;\n\tint wherex = 0, wherey = 0;\n\tSCREENCELL *aux1 = screen1;\n\tSCREENCELL *aux2 = screen2;\n\tif ((aux1 != NULL && aux2 != NULL) && (length(&aux1) == length(&aux2))) {\n\t\tfor (i = 0; i < buffersize; i++) {\n\n\t\t\tif (aux1->ch != aux2->ch\n\t\t\t    || aux1->backColor != aux2->backColor\n\t\t\t    || aux1->foreColor != aux2->foreColor) {\n\t\t\t\taux1->ch = aux2->ch;\n\t\t\t\taux1->backColor = aux2->backColor;\n\t\t\t\taux1->foreColor = aux2->foreColor;\n\t\t\t\twherex = wherex + 1;\t//line counter\n\n\t\t\t\tif (wherex == sc_columns) {\n\t\t\t\t\t//new line\n\t\t\t\t\twherex = 0;\n\t\t\t\t\twherey = wherey + 1;\n\t\t\t\t}\n\n\t\t\t\taux1 = aux1->next;\n\t\t\t\taux2 = aux2->next;\n\t\t\t}\n\t\t}\n\t}\n}\n/*------------------------------------------*/\n/* Draw window area with or without border. */\n/*------------------------------------------*/\n\nvoid 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) {\n/*\n   Draw a box on screen\n */\n  SCREENCELL *aux = newScreen;\n  int     i, j;\n  wchar_t ch=FILL_CHAR;\n  i = x1;\n  j = y1;\n  //shadow\n  resetAnsi(0);\n  if (shadow == TRUE){\n  for(j = y1 + 1; j <= y2 + 1; j++)\n    for(i = x1 + 1; i <= x2 + 1; i++)\n    {\n      ch=read_char(aux, i,j); //dynamic shadow\n      if ((ch=='\\0') || (ch == UNICODEBAR1) || (ch<0)) ch=FILL_CHAR;\n      //ch=FILL_CHAR;\n      //if (ch<0) ch = (tempLine.linea[i].specialChar << 8) | tempLine.linea[i].ch;\n      write_ch(aux, i, j, ch, B_BLACK, F_WHITE,raw);\n    }\n  }\n  //window\n  for(j = y1; j <= y2; j++)\n    for(i = x1; i <= x2; i++)\n      write_ch(aux, i, j, FILL_CHAR, backcolor, bordercolor,raw);\n \n //borders\n  if(border == TRUE) {\n    for(i = x1; i <= x2; i++) {\n      //upper and lower borders\n      write_ch(aux, i, y1, HOR_LINE, backcolor, bordercolor,raw);   //horizontal line box-like char\n      write_ch(aux, i, y2, HOR_LINE, backcolor, bordercolor,raw);\n    }\n    for(j = y1; j <= y2; j++) {\n      //left and right borders\n      write_ch(aux, x1, j, VER_LINE, backcolor, bordercolor,raw);   //vertical line box-like char\n      write_ch(aux, x2, j, VER_LINE, backcolor, bordercolor,raw);\n    }\n    write_ch(aux, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,raw);   //upper-left corner box-like char\n    write_ch(aux, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,raw);   //lower-left corner box-like char\n    write_ch(aux, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,raw);  //upper-right corner box-like char\n    write_ch(aux, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,raw);  //lower-right corner box-like char\n  }\n\n  if (title == TRUE) {\n    for(i = x1+1; i <= x2-1; i++)\n      write_ch(aux, i, y1, ' ', titlecolor, titlecolor,raw);\n  }\n}\n\n\n"
  },
  {
    "path": "src/scbuf.h",
    "content": "#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#include <locale.h>\n#include <wchar.h>\n#include \"rterm.h\"\n\n#define HOR_LINE 9472\n#define VER_LINE 9474\n#define UPPER_LEFT_CORNER 9484\n#define LOWER_LEFT_CORNER 9492\n#define UPPER_RIGHT_CORNER 9488\n#define LOWER_RIGHT_CORNER 9496\n#define UNICODEBAR1 0x2592\n\ntypedef struct _screencell \n{ \n\tint index;\n   \tchar backColor;\n        char foreColor;\n        unsigned char toUpdate;\n        //int char attrib; \n        wchar_t ch;\n\tstruct _screencell *next;\n} SCREENCELL;\n\n\n/* Adapted from Kernighan and Pike's \"The Practice of Programming\"  pp.46 et \nseq. (Addison-Wesley 1999) - computerPhile */\n\n// create new list element of type SCREENCELL from the supplied text string\nSCREENCELL *newelement(SCREENCELL temp);\nSCREENCELL *addfront(SCREENCELL *head, SCREENCELL *newp);\nSCREENCELL *addend (SCREENCELL *head, SCREENCELL *newp);\nvoid deleteList(SCREENCELL **head);\nint length(SCREENCELL **head);\nvoid reindex(SCREENCELL **head);\n//SCREEN BUFFER ROUTINES\nint create_screen(SCREENCELL **newScreen);\nvoid update_ch(int x, int y, wchar_t ch, char backcolor, char forecolor);\nvoid update_screen(SCREENCELL *newScreen);\nvoid dump_screen(SCREENCELL *newScreen);\nvoid write_ch(SCREENCELL *newScreen, int x, int y, wchar_t ch, char backcolor, char forecolor, BOOL raw);\nwchar_t read_char(SCREENCELL *newScreen, int x, int y);\nSCREENCELL read_cell(SCREENCELL *newScreen, int x, int y);\nvoid write_str(SCREENCELL *newScreen, int x, int y, char *str, char backcolor, char forecolor, BOOL raw);\nvoid update_str(int x, int y, char *str, char backcolor, char forecolor);\nint write_num(SCREENCELL *newScreen, int x, int y, int num, char backcolor,\n\t       char forecolor, BOOL raw);\nvoid screen_color(SCREENCELL *newScreen, char bcolor, char fcolor, wchar_t ch);\nvoid copy_screen(SCREENCELL *destination,SCREENCELL *source);\nvoid xor_update(SCREENCELL *screen1, SCREENCELL *screen2);\nvoid xor_copy(SCREENCELL *screen1, SCREENCELL *screen2);\nvoid 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);\n#endif\n"
  },
  {
    "path": "src/t.txt",
    "content": "Hello \n\n\nthere\n\n\n"
  },
  {
    "path": "src/tm.c",
    "content": "/* Module to create a milisecond timer\n * @author: velorek\n * Last modified: 10/08/2020\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n#include \"tm.h\"\n\n#include <sys/time.h>\n#include <poll.h>\n\nlong long epoch_ms(void)\n{\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return tv.tv_sec * 1000LL + (tv.tv_usec + 500) / 1000;\n}\nint timerC(NTIMER *mytimer1){\n    long long difference = 0;\n    long long res;\n    if (mytimer1->ticks == -1) return 0;\n    if (mytimer1->ticks == 0){\n        // First tick, set up values\n        mytimer1->oldtime = epoch_ms();\n        mytimer1->ticks = 1;\n        return 1;\n    } else {\n        // Subsequent ticks\n        long long now = epoch_ms();\n        difference = now - mytimer1->oldtime;\n        res = difference;\n        if (res < mytimer1->ms) {\n            return 0;\n        } else {\n            mytimer1->oldtime = now;\n            mytimer1->ticks = mytimer1->ticks + 1;\n            return 1;\n        }\n    }\n}\n\nvoid init_timer(NTIMER *mytimer1, int ms){\n    // Init routine\n    mytimer1->ticks = 0;\n    mytimer1->ms = ms;\n}\n\nvoid stop_timer(NTIMER *mytimer1){\n    // Stop routine\n    mytimer1->ticks = -1;\n}\n\nvoid resume_timer(NTIMER *mytimer1){\n    // Resume routine\n    mytimer1->ticks = 0;\n}\n\n"
  },
  {
    "path": "src/tm.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule to implement a millisecond TIMER in C.\n@author : Velorek\n@version : 1.0\nLast modified: 15/09/2021 + New technique + init timer\n========================================================================\n*/\n\n#ifndef _TM_H_\n#define _TM_H_\n\n/*====================================================================*/\n/* COMPILER DIRECTIVES AND INCLUDES                                   */\n/*====================================================================*/\n\n#include <time.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n/*====================================================================*/\n/* FUNCTION PROTOTYPES                                                */\n/*====================================================================*/\ntypedef struct nTimer{\n        int  ms; //milliseconds\n    long oldtime; //to calculate increment in time\n    long ticks; //how many ticks have been made\n} NTIMER;\n\n/* Miliseconds timer */\nint timerC(NTIMER *mytimer1);\nvoid init_timer(NTIMER *mytimer, int ms);\nvoid stop_timer(NTIMER *mytimer);\nvoid resume_timer(NTIMER *mytimer);\n\n#endif\n"
  },
  {
    "path": "src/ui.c",
    "content": "/* Module to create different widgets/gadgets \n * for a Text User Interface\n * TextBox\n * Window\n * Last modified: 15/04/2023\n * @author:velorek\n */\n#include <stdio.h>\n#include \"rterm.h\"\n#include \"scbuf.h\"\n#include \"ui.h\"\n#include \"tm.h\"\n#include \"keyb.h\"\n#include \"global.h\"\n/*----------------------------*/\n/* User Interface - Text Box. */\n/*----------------------------*/\nint textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength,\n        char *label, char text[MAX_TEXT], int backcolor,\n        int labelcolor, int textcolor, BOOL raw, BOOL locked) {\n  int     charCount = 0;\n  int     exitFlag = 0;\n  int     cursorON = 1;\n  int     i;\n  int     limitCursor = 0;\n  int     positionx = 0;\n  int     posCursor = 0;\n  int     keypressed = 0;\n  char    chartrail[5];\n // char    accentchar[2];\n  char    displayChar;\n  char    ch;\n  NTIMER  cursorTime;\n  SCREENCELL *aux = newScreen;\n  resetAnsi(0); \n  init_timer(&cursorTime,150);\n  positionx = wherex + strlen(label);\n  limitCursor = wherex+strlen(label)+displayLength+1;\n  write_str(aux,wherex, wherey, label, backcolor, labelcolor,raw);\n  write_ch(aux,positionx, wherey, '[', backcolor, textcolor,raw);\n  for(i = positionx + 1; i <= positionx + displayLength; i++) {\n    write_ch(aux,i, wherey, '.', backcolor, textcolor,raw);\n  }\n  write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor,\n       textcolor,raw);\n  if (raw != TRUE) dump_screen(aux);\n  //Reset keyboard\n  if(kbhit(1) == 1) ch = readch();\n  ch = 0;\n\n  do {\n\t if (locked == 0) break;\n      keypressed = kbhit(1);\n       if (timerC(&timer2) == TRUE) _animation();\n    //Cursor Animation\n   if (keypressed == 0){\n    \n    if (timerC(&cursorTime) == TRUE){\n      switch (cursorON) {\n    case 1:\n      posCursor = positionx + 1;\n          displayChar = '.';\n          if (posCursor == limitCursor) {\n            posCursor = posCursor - 1;\n            displayChar = ch;\n          }\n          write_ch(aux,posCursor, wherey, displayChar, backcolor, textcolor,raw);\n          //update_screen(aux);\n          if (raw != TRUE) dump_screen(aux);\n          cursorON = 0;\n      break;\n    case 0:\n          posCursor = positionx + 1;\n          if (posCursor == limitCursor) posCursor = posCursor - 1;\n          write_ch(aux,posCursor, wherey, '|', backcolor, textcolor,raw);\n          //update_screen(aux);\n          if (raw != TRUE) dump_screen(aux);\n          cursorON = 1;\n      break;\n      }\n     }\n    }\n    //Process keys\n    if(keypressed == 1) {\n      ch = readch();\n      keypressed = 0;\n      //Read special keys\n      if (ch==K_ESCAPE) {\n               read_keytrail(chartrail);\n      }\n      //Read accents\n      //if (ch==SPECIAL_CHARSET_1) read_accentchar(&ch, accentchar);\n      //if (ch==SPECIAL_CHARSET_2) read_accentchar(&ch, accentchar);\n\n      if(charCount < displayLength) {\n     if(ch > 31 && ch < 127) {\n      write_ch(aux,positionx + 1, wherey, ch, backcolor, textcolor,raw);\n      text[charCount] = ch;\n      positionx++;\n      charCount++;\n      //update_screen(aux);\n      if (raw != TRUE) dump_screen(aux);\n    }\n      }\n    }\n    if (ch==K_CTRL_C){\n\t    return ENDSIGNAL;\n    }\n    if (ch==K_BACKSPACE){\n      if (positionx>0 && charCount>0){\n       ch=0;\n       positionx--;\n       charCount--;\n       text[charCount] = '\\0';\n       write_ch(aux,positionx + 1, wherey, '.', backcolor, textcolor,raw);\n       if (positionx < limitCursor-2) write_ch(aux,positionx + 2, wherey, '.', backcolor, textcolor,raw);\n       //update_screen(aux);\n       if (raw != TRUE) dump_screen(aux);\n       //resetch();\n      }\n    }\n    if(ch == K_ENTER || ch == K_TAB || ch == K_ESCAPE)\n      exitFlag = 1;\n\n    //ENTER OR TAB FINISH LOOP\n  } while(exitFlag != 1);\n  text[charCount] = '\\0';\n  //Clear field\n  positionx = wherex + strlen(label);\n  for(i = positionx + 1; i <= positionx + displayLength; i++) {\n    write_ch(aux,i, wherey, '.', backcolor, textcolor,raw);\n  }\n  write_ch(aux,positionx + displayLength + 1, wherey, ']', backcolor,\n       textcolor,raw);\n \n  //resetch();\n  if (ch == K_ESCAPE) charCount = 0;\n  return charCount;\n}\n\n\nvoid window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor,\n         int bordercolor, int titlecolor, int border, int title, int shadow) {\n/*\n   Chars for drawing box-like characters will be passed as negative values.\n   When the update_screen routine is called, it will check for negative\n   values and map these chars to Unicode characters.\n */\n  int     i, j;\n  //char ch=0x20;\n  wchar_t ch=0x20;\n  i = x1;\n  j = y1;\n  \n  resetAnsi(0);\n  //shadow\n  if (shadow==1){\n   for(j = y1 + 1; j <= y2 + 1; j++)\n    for(i = x1 + 1; i <= x2 + 1; i++)\n    {\n      ch=read_char(screen1, i,j); //dynamic shadow\n      if ((ch=='\\0') || (ch==UNICODEBAR1)) ch=0x20;\n      write_ch(screen1, i, j, ch, B_BLACK, F_WHITE,0);\n    }\n  }\n  //window\n  for(j = y1; j <= y2; j++)\n    for(i = x1; i <= x2; i++)\n      write_ch(screen1, i, j, ' ', backcolor, bordercolor,0);\n  //borders\n  if(border == 1) {\n    //with borders. ANSI-ASCII 106-121\n    for(i = x1; i <= x2; i++) {\n      //upper and lower borders\n      write_ch(screen1, i, y1, HOR_LINE, backcolor, bordercolor,0);   //horizontal line box-like char\n      write_ch(screen1, i, y2, HOR_LINE, backcolor, bordercolor,0);\n    }\n    for(j = y1; j <= y2; j++) {\n      //left and right borders\n      write_ch(screen1,x1, j, VER_LINE, backcolor, bordercolor,0);   //vertical line box-like char\n      write_ch(screen1,x2, j, VER_LINE, backcolor, bordercolor,0);\n    }\n    write_ch(screen1, x1, y1, UPPER_LEFT_CORNER, backcolor, bordercolor,0);   //upper-left corner box-like char\n    write_ch(screen1, x1, y2, LOWER_LEFT_CORNER, backcolor, bordercolor,0);   //lower-left corner box-like char\n    write_ch(screen1, x2, y1, UPPER_RIGHT_CORNER, backcolor, bordercolor,0);  //upper-right corner box-like char\n    write_ch(screen1, x2, y2, LOWER_RIGHT_CORNER, backcolor, bordercolor,0);  //lower-right corner box-like char\n  }\n  if (title == 1) {\n    for(i = x1; i <= x2; i++)\n      write_ch(screen1, i, y1-1, ' ', titlecolor, titlecolor,0);\n  }\n // dump_screen(screen1);\n}\n\nint inputWindow(char *label, char *tempFile, char *windowTitle,  int offsetX, int offsetY, int length) {\n  int     window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;\n  int     count = 0;\n  resetAnsi(0);\n  copy_screen(screen2,screen1);\n  window_y1 = (new_rows / 2) - offsetY;\n  window_y2 = (new_rows / 2);\n  window_x1 = (new_columns / 2) - offsetX;\n  window_x2 = (new_columns / 2) + offsetX;\n  \n  window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0,\n          WINDOW_TITLEB,1,1,1);\n  write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1-1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,0);\n  dump_screen(screen1);\n  count =\n      textbox(screen1, window_x1 + 1, window_y1 + 1, length, label, tempFile, MENU_PANEL,\n          MENU_FOREGROUND0, MENU_FOREGROUND0,1,1);\n  copy_screen(screen1,screen2);\n  dump_screen(screen1);\n  return count;\n}\n\nint yesnoWindow(char *message, char *windowTitle) {\n\n  int     window_x1 = 0, window_y1 = 0, window_x2 = 0, window_y2 = 0;\n  char ch = 0;\n  int ok = 0;\n  size_t i=0;\n  int j = 0;\n  int ix = 0;\n  char tempChar=0;\n  resetAnsi(0);\n  copy_screen(screen2,screen1);\n \n  window_y1 = (new_rows / 2) - 4;\n  window_y2 = (new_rows / 2) + 4;\n  window_x1 = (new_columns / 2) - 16;\n  window_x2 = (new_columns / 2) + 16;\n  window(screen1,window_x1, window_y1, window_x2, window_y2, MENU_PANEL, MENU_FOREGROUND0, WINDOW_TITLEB,1,0,1);\n  dump_screen(screen1);\n  write_str(screen1, (window_x2-window_x1) /2 + window_x1 - (strlen(windowTitle)/2) , window_y1, windowTitle, WINDOW_TITLEB, WINDOW_TITLEF,1);\n //'|' is used as line separator\n \n  for(i = 0; i < strlen(message); i++) {\n    tempChar = message[i];\n    if (tempChar != '|'){\n      write_ch(screen1,window_x1 + 1 + ix, window_y1 + 1 + j, tempChar, MENU_PANEL,MENU_FOREGROUND0,1);\n    ix++;\n    }else {\n\t    j++;\n\t    ix = 0;\n    }\n    }\n  printf(\"\\n\");\n  if (listBox1 != NULL) removeList(&listBox1);\n  listBox1 = addatend(listBox1, newitem(\"[  YES ]\",window_x1+3,window_y2-1,-1,-1));\n  listBox1 = addatend(listBox1, newitem(\"[  NO  ]\",window_x1+13,window_y2-1,-1,-1));\n  listBox1 = addatend(listBox1, newitem(\"[CANCEL]\",window_x1+23,window_y2-1,-1,-1));\n\n  setselectorLimit(8);\n  ch = listBox(listBox1, window_x1+2,window_y2, &scrollData, MENU_PANEL, MENU_FOREGROUND0,MENU_SELECTOR, MENU_FOREGROUND1, 3, HORIZONTAL,1,LOCKED);\n  ok = scrollData.itemIndex;\n  if (listBox1 != NULL) removeList(&listBox1);\n  ch++;\n  copy_screen(screen1,screen2);\n  dump_screen(screen1);\n  resetScrollData(&scrollData); \n  return ok;\n}\n"
  },
  {
    "path": "src/ui.h",
    "content": "/*\n========================================================================\n- HEADER -\nModule with different UI gadgets for LYNX.\n@author : Velorek\n@version : 1.0\nLast modified: 06/02/2022\n========================================================================\n*/\n\n#ifndef _UI_H_\n#define _UI_H_\n#define MAX_TEXT 255\n\n#include \"scbuf.h\"\n#include <stdio.h>\n\nint textbox(SCREENCELL *newScreen,int wherex, int wherey, int displayLength,\n        char *label, char text[MAX_TEXT], int backcolor,\n        int labelcolor, int textcolor, BOOL raw, BOOL locked);\n\nvoid window(SCREENCELL *screen1, int x1, int y1, int x2, int y2, int backcolor,\n         int bordercolor, int titlecolor, int border, int title, int shadow);\n\nint inputWindow(char *label, char *tempFile, char *windowTitle, int offsetX, int offsetY, int length);\nint yesnoWindow(char *message, char *windowTitle);\n#endif\n\n\n"
  }
]