mirror of
https://github.com/cyring/CoreFreq.git
synced 2025-07-23 04:12:59 +02:00
2339 lines
44 KiB
C
2339 lines
44 KiB
C
/*
|
|
* CoreFreq
|
|
* Copyright (C) 2015-2023 CYRIL COURTIAT
|
|
* Licenses: GPL2
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#include <locale.h>
|
|
#include <poll.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <libgen.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
|
|
#include "bitasm.h"
|
|
#include "coretypes.h"
|
|
#include "corefreq-ui.h"
|
|
#include "corefreq-cli-rsc.h"
|
|
|
|
const char LCD[0x6][0x10][3][3] = {
|
|
{
|
|
{/* 0x20 */
|
|
" ",
|
|
" ",
|
|
" "
|
|
},
|
|
{/* 0x21 */
|
|
" | ",
|
|
" | ",
|
|
" o "
|
|
},
|
|
{/* 0x22 */
|
|
"|| ",
|
|
" ",
|
|
" "
|
|
},
|
|
{/* 0x23 */
|
|
" //",
|
|
"=/=",
|
|
"// "
|
|
},
|
|
{/* 0x24 */
|
|
" _ ",
|
|
"(|`",
|
|
"_) "
|
|
},
|
|
{/* 0x25 */
|
|
" ",
|
|
"O/ ",
|
|
"/O "
|
|
},
|
|
{/* 0x26 */
|
|
"_ ",
|
|
"\\' ",
|
|
"(\\ "
|
|
},
|
|
{/* 0x27 */
|
|
" | ",
|
|
" ",
|
|
" "
|
|
},
|
|
{/* 0x28 */
|
|
" / ",
|
|
"| ",
|
|
" \\ "
|
|
},
|
|
{/* 0x29 */
|
|
" \\ ",
|
|
" |",
|
|
" / "
|
|
},
|
|
{/* 0x2a */
|
|
" ",
|
|
"\\|/",
|
|
"/|\\"
|
|
},
|
|
{/* 0x2b */
|
|
" ",
|
|
"_|_",
|
|
" | "
|
|
},
|
|
{/* 0x2c */
|
|
" ",
|
|
" ",
|
|
" / "
|
|
},
|
|
{/* 0x2d */
|
|
" ",
|
|
"___",
|
|
" "
|
|
},
|
|
{/* 0x2e */
|
|
" ",
|
|
" ",
|
|
" o "
|
|
},
|
|
{/* 0x2f */
|
|
" /",
|
|
" / ",
|
|
"/ "
|
|
}
|
|
},{
|
|
{/* 0x30 */
|
|
" _ ",
|
|
"| |",
|
|
"|_|"
|
|
},
|
|
{/* 0x31 */
|
|
" ",
|
|
" | ",
|
|
" | "
|
|
},
|
|
{/* 0x32 */
|
|
" _ ",
|
|
" _|",
|
|
"|_ "
|
|
},
|
|
{/* 0x33 */
|
|
" _ ",
|
|
" _|",
|
|
" _|"
|
|
},
|
|
{/* 0x34 */
|
|
" ",
|
|
"|_|",
|
|
" |"
|
|
},
|
|
{/* 0x35 */
|
|
" _ ",
|
|
"|_ ",
|
|
" _|"
|
|
},
|
|
{/* 0x36 */
|
|
" _ ",
|
|
"|_ ",
|
|
"|_|"
|
|
},
|
|
{/* 0x37 */
|
|
" _ ",
|
|
" |",
|
|
" |"
|
|
},
|
|
{/* 0x38 */
|
|
" _ ",
|
|
"|_|",
|
|
"|_|"
|
|
},
|
|
{/* 0x39 */
|
|
" _ ",
|
|
"|_|",
|
|
" _|"
|
|
},
|
|
{/* 0x3a */
|
|
" ",
|
|
" o ",
|
|
" o "
|
|
},
|
|
{/* 0x3b */
|
|
" ",
|
|
" o ",
|
|
"/ "
|
|
},
|
|
{/* 0x3c */
|
|
" / ",
|
|
"< ",
|
|
" \\ "
|
|
},
|
|
{/* 0x3d */
|
|
"___",
|
|
"___",
|
|
" "
|
|
},
|
|
{/* 0x3e */
|
|
" \\ ",
|
|
" >",
|
|
" / "
|
|
},
|
|
{/* 0x3f */
|
|
" _ ",
|
|
"'_)",
|
|
" ! "
|
|
}
|
|
},{
|
|
{/* 0x40 */
|
|
" _ ",
|
|
"(()",
|
|
" ``"
|
|
},
|
|
{/* 0x41 */
|
|
" _ ",
|
|
"|_|",
|
|
"| |"
|
|
},
|
|
{/* 0x42 */
|
|
"__ ",
|
|
"[_)",
|
|
"[_)"
|
|
},
|
|
{/* 0x43 */
|
|
" _ ",
|
|
"| ",
|
|
"|_ "
|
|
},
|
|
{/* 0x44 */
|
|
"__ ",
|
|
"| |",
|
|
"|_|"
|
|
},
|
|
{/* 0x45 */
|
|
" _ ",
|
|
"|_ ",
|
|
"|_ "
|
|
},
|
|
{/* 0x46 */
|
|
" __",
|
|
"|- ",
|
|
"| "
|
|
},
|
|
{/* 0x47 */
|
|
" _ ",
|
|
"| ",
|
|
"|_]"
|
|
},
|
|
{/* 0x48 */
|
|
" ",
|
|
"|_|",
|
|
"| |"
|
|
},
|
|
{/* 0x49 */
|
|
" . ",
|
|
" | ",
|
|
" | "
|
|
},
|
|
{/* 0x4a */
|
|
" . ",
|
|
" | ",
|
|
"_| "
|
|
},
|
|
{/* 0x4b */
|
|
" ",
|
|
"|/ ",
|
|
"|\\ "
|
|
},
|
|
{/* 0x4c */
|
|
" ",
|
|
"| ",
|
|
"|_ "
|
|
},
|
|
{/* 0x4d */
|
|
" ",
|
|
"|||",
|
|
"| |"
|
|
},
|
|
{/* 0x4e */
|
|
" ",
|
|
"|\\|",
|
|
"| |"
|
|
},
|
|
{/* 0x4f */
|
|
" _.",
|
|
"| |",
|
|
"|_|"
|
|
}
|
|
},{
|
|
{/* 0x50 */
|
|
" _ ",
|
|
"|_|",
|
|
"| "
|
|
},
|
|
{/* 0x51 */
|
|
" _ ",
|
|
"|\\|",
|
|
"|_!"
|
|
},
|
|
{/* 0x52 */
|
|
" _ ",
|
|
"|_|",
|
|
"| \\"
|
|
},
|
|
{/* 0x53 */
|
|
" _ ",
|
|
"( ",
|
|
"_) "
|
|
},
|
|
{/* 0x54 */
|
|
"___",
|
|
" | ",
|
|
" | "
|
|
},
|
|
{/* 0x55 */
|
|
" ",
|
|
"| |",
|
|
"|_|"
|
|
},
|
|
{/* 0x56 */
|
|
" ",
|
|
"\\ /",
|
|
" v "
|
|
},
|
|
{/* 0x57 */
|
|
" ",
|
|
"| |",
|
|
"!^!"
|
|
},
|
|
{/* 0x58 */
|
|
" ",
|
|
"\\/ ",
|
|
"/\\ "
|
|
},
|
|
{/* 0x59 */
|
|
" ",
|
|
"\\ /",
|
|
" | "
|
|
},
|
|
{/* 0x5a */
|
|
"__ ",
|
|
" / ",
|
|
"/_ "
|
|
},
|
|
{/* 0x5b */
|
|
" _",
|
|
" | ",
|
|
" |_"
|
|
},
|
|
{/* 0x5c */
|
|
"\\ ",
|
|
" \\ ",
|
|
" \\"
|
|
},
|
|
{/* 0x5d */
|
|
"_ ",
|
|
" | ",
|
|
"_| "
|
|
},
|
|
{/* 0x5e */
|
|
"/\\ ",
|
|
" ",
|
|
" "
|
|
},
|
|
{/* 0x5f */
|
|
" ",
|
|
" ",
|
|
"___"
|
|
}
|
|
},{
|
|
{/* 0x60 */
|
|
" \\ ",
|
|
" ",
|
|
" "
|
|
},
|
|
{/* 0x61 */
|
|
" ",
|
|
" _ ",
|
|
"(_("
|
|
},
|
|
{/* 0x62 */
|
|
" ",
|
|
"|_ ",
|
|
"|_)"
|
|
},
|
|
{/* 0x63 */
|
|
" ",
|
|
" _ ",
|
|
"(_ "
|
|
},
|
|
{/* 0x64 */
|
|
" ",
|
|
" _|",
|
|
"(_|"
|
|
},
|
|
{/* 0x65 */
|
|
" ",
|
|
" _ ",
|
|
"(-'"
|
|
},
|
|
{/* 0x66 */
|
|
" ",
|
|
",- ",
|
|
"|' "
|
|
},
|
|
{/* 0x67 */
|
|
" ",
|
|
",- ",
|
|
"|] "
|
|
},
|
|
{/* 0x68 */
|
|
" ",
|
|
"|_ ",
|
|
"| |"
|
|
},
|
|
{/* 0x69 */
|
|
" ",
|
|
" . ",
|
|
" | "
|
|
},
|
|
{/* 0x6a */
|
|
" ",
|
|
" . ",
|
|
" ] "
|
|
},
|
|
{/* 0x6b */
|
|
" ",
|
|
"., ",
|
|
"|\\ "
|
|
},
|
|
{/* 0x6c */
|
|
" ",
|
|
"| ",
|
|
"|_ "
|
|
},
|
|
{/* 0x6d */
|
|
" ",
|
|
" ",
|
|
"|'|"
|
|
},
|
|
{/* 0x6e */
|
|
" ",
|
|
" ",
|
|
"|\\|"
|
|
},
|
|
{/* 0x6f */
|
|
" ",
|
|
" _ ",
|
|
"|_|"
|
|
}
|
|
},{
|
|
{/* 0x70 */
|
|
" ",
|
|
" _ ",
|
|
"|-'"
|
|
},
|
|
{/* 0x71 */
|
|
" ",
|
|
" _ ",
|
|
"|_!"
|
|
},
|
|
{/* 0x72 */
|
|
" ",
|
|
" _ ",
|
|
"|\\'"
|
|
},
|
|
{/* 0x73 */
|
|
" ",
|
|
" _ ",
|
|
"_) "
|
|
},
|
|
{/* 0x74 */
|
|
" ",
|
|
":_ ",
|
|
"| "
|
|
},
|
|
{/* 0x75 */
|
|
" ",
|
|
" ",
|
|
"|_|"
|
|
},
|
|
{/* 0x76 */
|
|
" ",
|
|
" ",
|
|
"\\/ "
|
|
},
|
|
{/* 0x77 */
|
|
" ",
|
|
" ",
|
|
"V^V"
|
|
},
|
|
{/* 0x78 */
|
|
" ",
|
|
" ",
|
|
">< "
|
|
},
|
|
{/* 0x79 */
|
|
" ",
|
|
" ",
|
|
"`/ "
|
|
},
|
|
{/* 0x7a */
|
|
" ",
|
|
"_ ",
|
|
"/_ "
|
|
},
|
|
{/* 0x7b */
|
|
" _",
|
|
"_| ",
|
|
" |_"
|
|
},
|
|
{/* 0x7c */
|
|
" | ",
|
|
" | ",
|
|
" | "
|
|
},
|
|
{/* 0x7d */
|
|
"_ ",
|
|
" |_",
|
|
"_| "
|
|
},
|
|
{/* 0x7e */
|
|
" ",
|
|
" ",
|
|
" ~ "
|
|
},
|
|
{/* 0x7f */
|
|
" ",
|
|
".^.",
|
|
"DEL"
|
|
}
|
|
}
|
|
};
|
|
|
|
ASCII hSpace[] = HSPACE,
|
|
hBar[] = HBAR,
|
|
hLine[] = HLINE;
|
|
|
|
Layer *sLayer = NULL,
|
|
*dLayer = NULL,
|
|
*wLayer = NULL,
|
|
*Fuse = NULL;
|
|
|
|
StockList stockList = {.head = NULL, .tail = NULL};
|
|
|
|
WinList winList = {.head = NULL};
|
|
|
|
void *StreamBuf = NULL;
|
|
char *Console = NULL;
|
|
|
|
enum LOCALES AppLoc = LOC_EN;
|
|
locale_t SysLoc = (locale_t) 0;
|
|
|
|
typedef char I18N[5];
|
|
|
|
I18N i18n_FR[] = {
|
|
"fr_FR",
|
|
"br_FR",
|
|
"fr_BE",
|
|
"fr_CA",
|
|
"fr_CH",
|
|
"fr_LU",
|
|
"ca_FR",
|
|
"ia_FR",
|
|
"oc_FR",
|
|
{0,0,0,0,0}
|
|
};
|
|
|
|
struct LOCALE_LOOKUP {
|
|
enum LOCALES apploc;
|
|
I18N *i18n;
|
|
} LocaleLookUp[] = {
|
|
{
|
|
.apploc = LOC_FR,
|
|
.i18n = i18n_FR
|
|
},
|
|
{
|
|
.apploc = LOC_EN,
|
|
.i18n = NULL
|
|
}
|
|
};
|
|
|
|
enum THEMES AppThm = THM_DFLT;
|
|
|
|
struct termios oldt, newt;
|
|
|
|
struct {
|
|
union {
|
|
Bit64 Reset __attribute__ ((aligned (8)));
|
|
struct {
|
|
Bit32 Status;
|
|
int Tick;
|
|
};
|
|
};
|
|
time_t StartedAt;
|
|
FILE *Handle;
|
|
char *Buffer;
|
|
void (*Header)(void);
|
|
void (*Write)(char*, int);
|
|
void (*Break)(void);
|
|
} Dump __attribute__ ((aligned (8))) = {
|
|
.StartedAt = 0,
|
|
.Reset = 0x0,
|
|
.Handle = NULL,
|
|
.Buffer = NULL,
|
|
.Header = JSON_Header,
|
|
.Write = JSON_Page,
|
|
.Break = JSON_Break
|
|
};
|
|
|
|
int GetKey(SCANKEY *scan, struct timespec *tsec)
|
|
{
|
|
struct pollfd fds = {.fd = STDIN_FILENO, .events = POLLIN};
|
|
register int rp, rz;
|
|
|
|
if ((rp = ppoll(&fds, 1, tsec, NULL)) > 0) {
|
|
if (fds.revents & POLLIN) {
|
|
ssize_t lc = read(STDIN_FILENO, &scan->key, 8);
|
|
for (rz = lc; rz < 8; rz++)
|
|
scan->code[rz] = 0;
|
|
}
|
|
}
|
|
return rp;
|
|
}
|
|
|
|
SCREEN_SIZE GetScreenSize(void)
|
|
{
|
|
SCREEN_SIZE _screenSize = {.width = 0, .height = 0};
|
|
struct winsize ts;
|
|
|
|
ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);
|
|
_screenSize.width = (int) ts.ws_col;
|
|
_screenSize.height = (int) ts.ws_row;
|
|
|
|
return _screenSize;
|
|
}
|
|
|
|
TGrid *GridHover(TGrid *pGrid, const char *comment)
|
|
{
|
|
if ((pGrid != NULL) && (comment != NULL))
|
|
{
|
|
size_t length = strlen(comment);
|
|
if (length > 0)
|
|
{
|
|
ASCII *comm = malloc(1 + length);
|
|
if (comm != NULL)
|
|
{
|
|
StrCopy(comm, comment, (1 + length));
|
|
pGrid->hover.comm = comm;
|
|
pGrid->hover.length = length;
|
|
}
|
|
}
|
|
}
|
|
return pGrid;
|
|
}
|
|
|
|
__inline__
|
|
void Set_Data(TGrid *pGrid, DATA_TYPE data, unsigned int order)
|
|
{
|
|
pGrid->data[order] = data;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pVOID(TGrid *pGrid, void *pVOID, unsigned int order)
|
|
{
|
|
pGrid->data[order].pvoid = pVOID;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pULLONG(TGrid *pGrid, unsigned long long *pULLONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].pullong = pULLONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pSLLONG(TGrid *pGrid, signed long long *pSLLONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].psllong = pSLLONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pULONG(TGrid *pGrid, unsigned long *pULONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].pulong = pULONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pSLONG(TGrid *pGrid, signed long *pSLONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].pslong = pSLONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pUINT(TGrid *pGrid, unsigned int *pUINT, unsigned int order)
|
|
{
|
|
pGrid->data[order].puint = pUINT;
|
|
}
|
|
|
|
__inline__
|
|
void Set_pSINT(TGrid *pGrid, signed int *pSINT, unsigned int order)
|
|
{
|
|
pGrid->data[order].psint = pSINT;
|
|
}
|
|
|
|
__inline__
|
|
void Set_ULLONG(TGrid *pGrid, unsigned long long _ULLONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].ullong = _ULLONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_SLLONG(TGrid *pGrid, signed long long _SLLONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].sllong = _SLLONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_ULONG(TGrid *pGrid, unsigned long _ULONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].ulong = _ULONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_SLONG(TGrid *pGrid, signed long _SLONG, unsigned int order)
|
|
{
|
|
pGrid->data[order].slong = _SLONG;
|
|
}
|
|
|
|
__inline__
|
|
void Set_UINT(TGrid *pGrid, unsigned int _UINT, unsigned int order)
|
|
{
|
|
pGrid->data[order].uint[0] = _UINT;
|
|
pGrid->data[order].uint[1] = 0;
|
|
}
|
|
|
|
__inline__
|
|
void Set_SINT(TGrid *pGrid, signed int _SINT, unsigned int order)
|
|
{
|
|
pGrid->data[order].sint[0] = _SINT;
|
|
pGrid->data[order].sint[1] = 0;
|
|
}
|
|
|
|
void HookCellFunc(TCELLFUNC *with, TCELLFUNC what) { *with=what; }
|
|
|
|
void HookKeyFunc(KEYFUNC *with, KEYFUNC what) { *with=what; }
|
|
|
|
void HookWinFunc(WINFUNC *with, WINFUNC what) { *with=what; }
|
|
|
|
void HookAttrib(ATTRIBUTE *with, ATTRIBUTE what) { with->value=what.value; }
|
|
|
|
void HookString(REGSTR *with, REGSTR what) { strcpy(*with, what); }
|
|
|
|
void HookPointer(REGPTR *with, REGPTR what)
|
|
{
|
|
if ((*with = realloc(*with, 1 + strlen(what))) != NULL) {
|
|
strcpy(*with, what);
|
|
}
|
|
}
|
|
|
|
void DestroyLayer(Layer *layer)
|
|
{
|
|
if (layer != NULL) {
|
|
if (layer->attr != NULL) {
|
|
free(layer->attr);
|
|
layer->attr = NULL;
|
|
}
|
|
if (layer->code != NULL) {
|
|
free(layer->code);
|
|
layer->code = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CreateLayer(Layer *layer, CoordSize size)
|
|
{
|
|
if (layer != NULL) {
|
|
layer->size.wth = size.wth;
|
|
layer->size.hth = size.hth;
|
|
size_t len = layer->size.wth * layer->size.hth;
|
|
|
|
layer->attr = calloc(len, sizeof(ATTRIBUTE));
|
|
layer->code = calloc(len, sizeof(ASCII));
|
|
}
|
|
}
|
|
|
|
void FillLayerArea(Layer *layer,CUINT col, CUINT row,
|
|
CUINT width, CUINT height,
|
|
ASCII *source, ATTRIBUTE attrib)
|
|
{
|
|
CUINT _row;
|
|
for (_row = row; _row < row + height; _row++) {
|
|
LayerFillAt(layer, col, _row, width, source, attrib);
|
|
}
|
|
}
|
|
|
|
void AllocCopyAttr(TCell *cell, ATTRIBUTE attrib[])
|
|
{
|
|
if ((attrib != NULL) && (cell->attr = malloc(cell->length)) != NULL) {
|
|
memcpy(&cell->attr->value, &attrib->value, cell->length);
|
|
}
|
|
}
|
|
|
|
void AllocFillAttr(TCell *cell, ATTRIBUTE attrib)
|
|
{
|
|
if ((cell->attr = malloc(cell->length)) != NULL) {
|
|
memset(&cell->attr->value, attrib.value, cell->length);
|
|
}
|
|
}
|
|
|
|
void AllocCopyItem(TCell *cell, ASCII *item)
|
|
{
|
|
if ((cell->item = malloc(cell->length)) != NULL) {
|
|
strncpy((char *)cell->item, (char *)item, cell->length);
|
|
}
|
|
}
|
|
|
|
void FreeAllTCells(Window *win)
|
|
{
|
|
if (win->grid != NULL) {
|
|
CUINT i;
|
|
for (i = 0; i < win->dim; i++)
|
|
{
|
|
free(win->grid[i].cell.attr);
|
|
free(win->grid[i].cell.item);
|
|
|
|
if (win->grid[i].hover.comm != NULL) {
|
|
free(win->grid[i].hover.comm);
|
|
}
|
|
}
|
|
free(win->grid);
|
|
win->grid = NULL;
|
|
}
|
|
}
|
|
|
|
Stock *CreateStock(unsigned long long id, Coordinate origin)
|
|
{
|
|
Stock *stock = malloc(sizeof(Stock));
|
|
if (stock != NULL) {
|
|
GetNext(stock) = NULL;
|
|
stock->id = id;
|
|
stock->geometry.origin = origin;
|
|
}
|
|
return stock;
|
|
}
|
|
|
|
Stock *AppendStock(Stock *stock)
|
|
{
|
|
if (stock != NULL) {
|
|
if (stockList.head == NULL) {
|
|
stockList.head = stockList.tail = stock;
|
|
} else {
|
|
GetNext(stockList.tail) = stock;
|
|
stockList.tail = stock;
|
|
}
|
|
}
|
|
return stock;
|
|
}
|
|
|
|
void DestroyFullStock(void)
|
|
{
|
|
Stock *stock = stockList.head;
|
|
while (stock != NULL) {
|
|
Stock *_next = GetNext(stock);
|
|
free(stock);
|
|
stock = _next;
|
|
}
|
|
stockList.head = stockList.tail = NULL;
|
|
}
|
|
|
|
Stock *SearchStockById(unsigned long long id)
|
|
{
|
|
Stock *walker = stockList.head;
|
|
while (walker != NULL) {
|
|
if (walker->id == id) {
|
|
break;
|
|
}
|
|
walker = GetNext(walker);
|
|
}
|
|
return walker;
|
|
}
|
|
|
|
#define ComputeLazyBottomRow(_win, withBorder) \
|
|
({ \
|
|
if (_win->lazyComp.rowLen == 0) \
|
|
{ \
|
|
CUINT _col; \
|
|
for ( _col = 0, _win->lazyComp.rowLen = 2 * withBorder; \
|
|
_col < _win->matrix.size.wth; \
|
|
_col++ ) \
|
|
{ \
|
|
_win->lazyComp.rowLen += TCellAt(_win, _col, 0).length; \
|
|
} \
|
|
} \
|
|
})
|
|
|
|
CSINT LazyCompBottomRow(Window *win)
|
|
{
|
|
if ((win->dim > 0) && win->matrix.size.wth) {
|
|
return (win->dim / win->matrix.size.wth) - win->matrix.size.hth;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void DestroyWindow(Window *win)
|
|
{
|
|
if (win != NULL) {
|
|
if (!(win->flag & WINFLAG_NO_STOCK)) {
|
|
if (win->stock == NULL)
|
|
{
|
|
win->stock=AppendStock(CreateStock(win->id,win->matrix.origin));
|
|
} else {
|
|
win->stock->geometry.origin = win->matrix.origin;
|
|
}
|
|
}
|
|
if (win->hook.title != NULL) {
|
|
free(win->hook.title);
|
|
win->hook.title = NULL;
|
|
win->lazyComp.titleLen = 0;
|
|
}
|
|
FreeAllTCells(win);
|
|
free(win);
|
|
win = NULL;
|
|
}
|
|
}
|
|
|
|
Window *_CreateWindow( Layer *layer, unsigned long long id,
|
|
CUINT width, CUINT height,
|
|
CUINT oCol, CUINT oRow, WINDOW_FLAG flag )
|
|
{
|
|
ATTRIBUTE select[2] = {
|
|
MAKE_SELECT_UNFOCUS,
|
|
MAKE_SELECT_FOCUS
|
|
},
|
|
border[2] = {
|
|
MAKE_BORDER_UNFOCUS,
|
|
MAKE_BORDER_FOCUS
|
|
},
|
|
title[2] = {
|
|
MAKE_TITLE_UNFOCUS,
|
|
MAKE_TITLE_FOCUS
|
|
};
|
|
unsigned int idx;
|
|
|
|
Window *win = calloc(1, sizeof(Window));
|
|
if (win != NULL) {
|
|
win->layer = layer;
|
|
win->id = id;
|
|
|
|
win->matrix.size.wth = width;
|
|
win->matrix.size.hth = height;
|
|
|
|
win->flag = flag;
|
|
if (win->flag & WINFLAG_NO_STOCK)
|
|
{
|
|
win->matrix.origin.col = oCol;
|
|
win->matrix.origin.row = oRow;
|
|
} else {
|
|
if ((win->stock = SearchStockById(win->id)) != NULL) {
|
|
win->matrix.origin = win->stock->geometry.origin;
|
|
} else {
|
|
win->matrix.origin.col = oCol;
|
|
win->matrix.origin.row = oRow;
|
|
}
|
|
}
|
|
for (idx = 0; idx < 2; idx++) {
|
|
win->hook.color[idx].select = select[idx];
|
|
win->hook.color[idx].border = border[idx];
|
|
win->hook.color[idx].title = title[idx];
|
|
}
|
|
}
|
|
return win;
|
|
}
|
|
|
|
Window *CreateWindow_7xArg( Layer *layer, unsigned long long id,
|
|
CUINT width, CUINT height,
|
|
CUINT oCol, CUINT oRow, WINDOW_FLAG flag )
|
|
{
|
|
return _CreateWindow(layer, id, width, height, oCol, oRow, flag);
|
|
}
|
|
|
|
Window *CreateWindow_6xArg( Layer *layer, unsigned long long id,
|
|
CUINT width, CUINT height,
|
|
CUINT oCol, CUINT oRow )
|
|
{
|
|
return _CreateWindow(layer, id, width, height, oCol, oRow,
|
|
WINFLAG_NO_FLAGS);
|
|
}
|
|
|
|
void RemoveWindow(Window *win, WinList *list)
|
|
{
|
|
RemoveWinList(win, list);
|
|
|
|
if (IsCycling(GetHead(list))) {
|
|
SetDead(list);
|
|
} else if (IsHead(list, win)) {
|
|
/*Auto shift*/ SetHead(list, GetPrev(win));
|
|
}
|
|
DestroyWindow(win);
|
|
}
|
|
|
|
void AppendWindow(Window *win, WinList *list)
|
|
{
|
|
if (win != NULL) {
|
|
if (!IsDead(list))
|
|
AppendWinList(win, list);
|
|
else {
|
|
/* Dead head, now cycling */
|
|
GetPrev(win) = win;
|
|
GetNext(win) = win;
|
|
}
|
|
SetHead(list, win);
|
|
}
|
|
}
|
|
|
|
void DestroyAllWindows(WinList *list)
|
|
{
|
|
while (!IsDead(list)) {
|
|
RemoveWindow(GetHead(list), list);
|
|
}
|
|
}
|
|
|
|
void AnimateWindow(int rotate, WinList *list)
|
|
{
|
|
if (!IsDead(list)) {
|
|
SetHead( list, rotate == 1 ? GetNext(GetHead(list))
|
|
: GetPrev(GetHead(list)) );
|
|
}
|
|
}
|
|
|
|
Window *SearchWinListById(unsigned long long id, WinList *list)
|
|
{
|
|
Window *win = NULL;
|
|
if (!IsDead(list)) {
|
|
Window *walker = GetHead(list);
|
|
do {
|
|
if (walker->id == id)
|
|
win = walker;
|
|
|
|
walker = GetPrev(walker);
|
|
} while (!IsHead(list, walker) && (win == NULL));
|
|
}
|
|
return win;
|
|
}
|
|
|
|
void PrintContent(Window *win, WinList *list, CUINT col, CUINT row)
|
|
{
|
|
CUINT horzCol = win->matrix.scroll.horz + col,
|
|
vertRow = win->matrix.scroll.vert + row;
|
|
|
|
if ((win->matrix.select.col == col)
|
|
&& (win->matrix.select.row == row)) {
|
|
LayerFillAt(win->layer,
|
|
(win->matrix.origin.col
|
|
+ (col * TCellAt(win, horzCol, vertRow).length)),
|
|
(win->matrix.origin.row + row),
|
|
TCellAt(win, horzCol, vertRow).length,
|
|
TCellAt(win, horzCol, vertRow).item,
|
|
win->hook.color[(GetFocus(list) == win)].select);
|
|
} else if (GetFocus(list) == win) {
|
|
LayerCopyAt(win->layer,
|
|
(win->matrix.origin.col
|
|
+ (col * TCellAt(win, horzCol, vertRow).length)),
|
|
(win->matrix.origin.row + row),
|
|
TCellAt(win, horzCol, vertRow).length,
|
|
TCellAt(win, horzCol, vertRow).attr,
|
|
TCellAt(win, horzCol, vertRow).item);
|
|
} else {
|
|
LayerFillAt(win->layer,
|
|
(win->matrix.origin.col
|
|
+ (col * TCellAt(win, horzCol, vertRow).length)),
|
|
(win->matrix.origin.row + row),
|
|
TCellAt(win, horzCol, vertRow).length,
|
|
TCellAt(win, horzCol, vertRow).item,
|
|
win->hook.color[0].select);
|
|
}
|
|
}
|
|
|
|
void PrintComment(Window *win)
|
|
{ /* The cell comment is positioned at the bottom border center */
|
|
CUINT horzCol = win->matrix.scroll.horz + win->matrix.select.col,
|
|
vertRow = win->matrix.scroll.vert + win->matrix.select.row;
|
|
|
|
if (TGridAt(win, horzCol, vertRow).hover.comm != NULL)
|
|
{
|
|
size_t pos;
|
|
pos = win->lazyComp.rowLen - TGridAt(win,horzCol,vertRow).hover.length;
|
|
pos = pos >> 1;
|
|
pos = pos + (1 & TGridAt(win, horzCol, vertRow).hover.length);
|
|
|
|
memcpy(&LayerAt(win->layer, code,
|
|
(win->matrix.origin.col + pos),
|
|
(win->matrix.origin.row + win->matrix.size.hth)),
|
|
TGridAt(win, horzCol, vertRow).hover.comm,
|
|
TGridAt(win, horzCol, vertRow).hover.length);
|
|
}
|
|
}
|
|
|
|
void ForEachCellPrint(Window *win, WinList *list)
|
|
{
|
|
CUINT col, row;
|
|
ATTRIBUTE border = win->hook.color[(GetFocus(list) == win)].border;
|
|
|
|
/* Top, Left Border Corner */
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col - 1),
|
|
(win->matrix.origin.row - 1)) = border;
|
|
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col - 1),
|
|
(win->matrix.origin.row - 1)) = 0x20;
|
|
/* Top Border Line */
|
|
if (win->hook.title == NULL) {
|
|
LayerFillAt( win->layer,
|
|
win->matrix.origin.col,
|
|
(win->matrix.origin.row - 1),
|
|
(win->lazyComp.rowLen - 2), hLine, border );
|
|
} else {
|
|
if (win->lazyComp.titleLen == 0) {
|
|
win->lazyComp.titleLen = strlen(win->hook.title);
|
|
}
|
|
size_t halfLeft=(win->lazyComp.rowLen - win->lazyComp.titleLen) / 2;
|
|
size_t halfRight = halfLeft
|
|
+ (win->lazyComp.rowLen - win->lazyComp.titleLen) % 2;
|
|
/* Top, Half-Left Border Line */
|
|
LayerFillAt( win->layer,
|
|
win->matrix.origin.col,
|
|
(win->matrix.origin.row - 1),
|
|
halfLeft, hLine, border );
|
|
/* Top, Centered Border Title */
|
|
LayerFillAt( win->layer,
|
|
(halfLeft + (win->matrix.origin.col - 1)),
|
|
(win->matrix.origin.row - 1),
|
|
win->lazyComp.titleLen, win->hook.title,
|
|
((GetFocus(list) == win) ?
|
|
win->hook.color[1].title
|
|
: win->hook.color[0].title) );
|
|
/* Top, Half-Right Border Line */
|
|
LayerFillAt( win->layer,
|
|
(halfLeft + win->lazyComp.titleLen
|
|
+ (win->matrix.origin.col - 1)),
|
|
(win->matrix.origin.row - 1),
|
|
(halfRight - 1), hLine, border );
|
|
}
|
|
/* Top, Right Border Corner */
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col + win->lazyComp.rowLen - 2),
|
|
(win->matrix.origin.row - 1)) = border;
|
|
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col + win->lazyComp.rowLen - 2),
|
|
(win->matrix.origin.row - 1)) = 0x20;
|
|
|
|
for (row = 0; row < win->matrix.size.hth; row++) {
|
|
/* Left Side Border Column */
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col - 1),
|
|
(win->matrix.origin.row + row)) = border;
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col - 1),
|
|
(win->matrix.origin.row + row)) = 0x20;
|
|
|
|
for (col = 0; col < win->matrix.size.wth; col++) {
|
|
PrintContent(win, list, col, row);
|
|
}
|
|
/* Right Side Border Column */
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col
|
|
+ col * TCellAt(win, 0, 0).length),
|
|
(win->matrix.origin.row + row)) = border;
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col
|
|
+ col * TCellAt(win, 0, 0).length),
|
|
(win->matrix.origin.row + row)) = 0x20;
|
|
}
|
|
/* Bottom, Left Border Corner */
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col - 1),
|
|
(win->matrix.origin.row + win->matrix.size.hth)) = border;
|
|
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col - 1),
|
|
(win->matrix.origin.row + win->matrix.size.hth)) = 0x20;
|
|
/* Bottom Border Line */
|
|
LayerFillAt(win->layer,
|
|
win->matrix.origin.col,
|
|
(win->matrix.origin.row + win->matrix.size.hth),
|
|
(win->lazyComp.rowLen - 2), hLine, border);
|
|
/* Bottom, Right Border Corner */
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col + win->lazyComp.rowLen - 2),
|
|
(win->matrix.origin.row + win->matrix.size.hth)) = border;
|
|
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col + win->lazyComp.rowLen - 2),
|
|
(win->matrix.origin.row + win->matrix.size.hth)) = 0x20;
|
|
/* Vertical Scrolling Bar */
|
|
if (!(win->flag & WINFLAG_NO_VSB)) {
|
|
if (win->dim / win->matrix.size.wth > win->matrix.size.hth)
|
|
{
|
|
CUINT vScrollbar = win->matrix.origin.row
|
|
+ (win->matrix.size.hth - 1)
|
|
* win->matrix.scroll.vert
|
|
/ LazyCompBottomRow(win);
|
|
|
|
ATTRIBUTE attrBar=GetFocus(list) == win ? MAKE_TITLE_FOCUS
|
|
: border;
|
|
|
|
LayerAt(win->layer, attr,
|
|
(win->matrix.origin.col + win->lazyComp.rowLen - 2),
|
|
vScrollbar) = attrBar;
|
|
|
|
LayerAt(win->layer, code,
|
|
(win->matrix.origin.col + win->lazyComp.rowLen - 2),
|
|
vScrollbar) = '=';
|
|
}
|
|
}
|
|
}
|
|
|
|
void EraseWindowWithBorder(Window *win)
|
|
{ /* Care about the four window side borders. */
|
|
CUINT row;
|
|
for (row = 0; row < win->matrix.size.hth + 2; row++) {
|
|
Coordinate origin = {
|
|
.col = win->matrix.origin.col - 1,
|
|
.row = (win->matrix.origin.row
|
|
- !(win->flag & WINFLAG_NO_BORDER)) + row
|
|
};
|
|
size_t len = win->lazyComp.rowLen + 1;
|
|
|
|
memset(&LayerAt(win->layer, attr, origin.col,origin.row),0,len);
|
|
memset(&LayerAt(win->layer, code, origin.col,origin.row),0,len);
|
|
}
|
|
}
|
|
|
|
void PrintLCD( Layer *layer, CUINT col, CUINT row,
|
|
int len, char *pStr, ATTRIBUTE lcdColor)
|
|
{
|
|
register int j = len;
|
|
do {
|
|
register int offset = col + (len - j) * 3,
|
|
lo = pStr[len - j] & 0b00001111,
|
|
hi = pStr[len - j] & 0b11110000;
|
|
hi = (hi >> 4) - 0x2;
|
|
|
|
LayerFillAt(layer, offset, row, \
|
|
3, LCD[hi][lo][0], \
|
|
lcdColor);
|
|
|
|
LayerFillAt(layer, offset, (row + 1), \
|
|
3, LCD[hi][lo][1], \
|
|
lcdColor);
|
|
|
|
LayerFillAt(layer, offset, (row + 2), \
|
|
3, LCD[hi][lo][2], \
|
|
lcdColor);
|
|
j--;
|
|
} while (j > 0) ;
|
|
}
|
|
|
|
void LazyCompWindow(Window *win)
|
|
{
|
|
if (win->matrix.scroll.vert > LazyCompBottomRow(win)) {
|
|
win->matrix.scroll.vert = LazyCompBottomRow(win);
|
|
}
|
|
if (win->matrix.select.row > win->matrix.size.hth - 1) {
|
|
win->matrix.select.row = win->matrix.size.hth - 1;
|
|
}
|
|
}
|
|
|
|
void MotionReset_Win(Window *win)
|
|
{
|
|
win->matrix.scroll.horz = 0; win->matrix.select.col = 0;
|
|
win->matrix.scroll.vert = 0; win->matrix.select.row = 0;
|
|
}
|
|
|
|
void MotionLeft_Win(Window *win)
|
|
{
|
|
if (win->matrix.select.col > 0) {
|
|
win->matrix.select.col--;
|
|
} else {
|
|
win->matrix.select.col = win->matrix.size.wth - 1;
|
|
}
|
|
}
|
|
|
|
void MotionRight_Win(Window *win)
|
|
{
|
|
if (win->matrix.select.col < win->matrix.size.wth - 1) {
|
|
win->matrix.select.col++;
|
|
} else {
|
|
win->matrix.select.col = 0;
|
|
}
|
|
}
|
|
|
|
void MotionUp_Win(Window *win)
|
|
{
|
|
if (win->matrix.select.row > 0) {
|
|
win->matrix.select.row--;
|
|
} else if (win->matrix.scroll.vert > 0) {
|
|
win->matrix.scroll.vert--;
|
|
}
|
|
}
|
|
|
|
void MotionDown_Win(Window *win)
|
|
{
|
|
if (win->matrix.select.row < win->matrix.size.hth - 1) {
|
|
win->matrix.select.row++;
|
|
} else if (win->matrix.scroll.vert < LazyCompBottomRow(win)) {
|
|
win->matrix.scroll.vert++;
|
|
}
|
|
}
|
|
|
|
void MotionHome_Win(Window *win)
|
|
{
|
|
win->matrix.select.col = 0;
|
|
}
|
|
|
|
void MotionEnd_Win(Window *win)
|
|
{
|
|
win->matrix.select.col = win->matrix.size.wth - 1;
|
|
}
|
|
|
|
void MotionTop_Win(Window *win)
|
|
{
|
|
win->matrix.scroll.vert = 0; win->matrix.select.row = 0;
|
|
}
|
|
|
|
void MotionBottom_Win(Window *win)
|
|
{
|
|
win->matrix.scroll.vert = LazyCompBottomRow(win);
|
|
win->matrix.select.row = win->matrix.size.hth - 1;
|
|
}
|
|
|
|
void MotionPgUp_Win(Window *win)
|
|
{
|
|
if (win->matrix.scroll.vert >= win->matrix.size.hth) {
|
|
win->matrix.scroll.vert -= win->matrix.size.hth;
|
|
} else {
|
|
win->matrix.scroll.vert = 0;
|
|
}
|
|
}
|
|
|
|
void MotionPgDw_Win(Window *win)
|
|
{
|
|
if(win->matrix.scroll.vert + win->matrix.size.hth < LazyCompBottomRow(win))
|
|
{
|
|
win->matrix.scroll.vert += win->matrix.size.hth;
|
|
} else {
|
|
win->matrix.scroll.vert = LazyCompBottomRow(win);
|
|
}
|
|
}
|
|
|
|
void MotionOriginLeft_Win(Window *win)
|
|
{
|
|
if (win->matrix.origin.col > 1) {
|
|
EraseWindowWithBorder(win);
|
|
win->matrix.origin.col--;
|
|
}
|
|
}
|
|
|
|
void MotionOriginRight_Win(Window *win)
|
|
{ /* Care about the right-side window border. */
|
|
const CUINT
|
|
maxVisibleCol = CUMIN(MAX_WIDTH - 1, (CUINT) GetScreenSize().width)
|
|
- win->lazyComp.rowLen;
|
|
|
|
if (win->matrix.origin.col <= maxVisibleCol) {
|
|
EraseWindowWithBorder(win);
|
|
win->matrix.origin.col++;
|
|
}
|
|
}
|
|
|
|
void MotionOriginUp_Win(Window *win)
|
|
{
|
|
if (win->matrix.origin.row > 1) {
|
|
EraseWindowWithBorder(win);
|
|
win->matrix.origin.row--;
|
|
}
|
|
}
|
|
|
|
void MotionOriginDown_Win(Window *win)
|
|
{ /* Care about the bottom window border */
|
|
const CUINT maxVisibleRow = CUMIN(MAX_HEIGHT-1, GetScreenSize().height)
|
|
- win->matrix.size.hth - 1;
|
|
|
|
if (win->matrix.origin.row < maxVisibleRow) {
|
|
EraseWindowWithBorder(win);
|
|
win->matrix.origin.row++;
|
|
}
|
|
}
|
|
|
|
void MotionShrink_Win(Window *win)
|
|
{
|
|
if (win->matrix.size.hth > 1) {
|
|
EraseWindowWithBorder(win);
|
|
win->matrix.size.hth--;
|
|
LazyCompWindow(win);
|
|
}
|
|
}
|
|
|
|
void MotionExpand_Win(Window *win)
|
|
{
|
|
const CUINT maxVisibleRow = GetScreenSize().height - 1,
|
|
winBottomRow = win->matrix.origin.row + win->matrix.size.hth,
|
|
winMaxHeight = win->dim / win->matrix.size.wth;
|
|
|
|
if ((winBottomRow < maxVisibleRow)&&(win->matrix.size.hth < winMaxHeight))
|
|
{
|
|
EraseWindowWithBorder(win);
|
|
win->matrix.size.hth++;
|
|
LazyCompWindow(win);
|
|
}
|
|
}
|
|
|
|
void MotionUp_Wheel(Window *win)
|
|
{
|
|
const ssize_t dim = win->dim >> 1;
|
|
if (win->matrix.scroll.vert > 0) {
|
|
win->matrix.scroll.vert--;
|
|
} else {
|
|
win->matrix.scroll.vert = dim - 1;
|
|
}
|
|
}
|
|
|
|
void MotionDown_Wheel(Window *win)
|
|
{
|
|
const ssize_t dim = win->dim >> 1;
|
|
if (win->matrix.scroll.vert < dim) {
|
|
win->matrix.scroll.vert++;
|
|
} else {
|
|
win->matrix.scroll.vert = 1;
|
|
}
|
|
}
|
|
|
|
void MotionPgUp_Wheel(Window *win)
|
|
{
|
|
const ssize_t dim = win->dim >> 1;
|
|
if (win->matrix.scroll.vert > win->matrix.select.row) {
|
|
win->matrix.scroll.vert -= win->matrix.select.row;
|
|
} else {
|
|
win->matrix.scroll.vert = dim - win->matrix.scroll.vert;
|
|
}
|
|
}
|
|
|
|
void MotionPgDw_Wheel(Window *win)
|
|
{
|
|
const ssize_t dim = win->dim >> 1;
|
|
if (win->matrix.scroll.vert + win->matrix.select.row < dim) {
|
|
win->matrix.scroll.vert += win->matrix.select.row;
|
|
} else {
|
|
win->matrix.scroll.vert = dim - win->matrix.scroll.vert;
|
|
}
|
|
}
|
|
|
|
void MotionHome_Wheel(Window *win)
|
|
{
|
|
const ssize_t dim = win->dim >> 1;
|
|
win->matrix.scroll.vert = dim - win->matrix.select.row;
|
|
}
|
|
|
|
void MotionEnd_Wheel(Window *win)
|
|
{
|
|
const ssize_t dim = win->dim >> 1;
|
|
win->matrix.scroll.vert = dim - win->matrix.select.row - 1;
|
|
}
|
|
|
|
void MotionReScale(Window *win)
|
|
{
|
|
CSINT col = -1, row = -1, height = -1;
|
|
CSINT rightSide = CUMAX(MIN_WIDTH, (CUINT) GetScreenSize().width)
|
|
- win->lazyComp.rowLen,
|
|
bottomSide = GetScreenSize().height - win->matrix.size.hth;
|
|
|
|
if (rightSide > 0 && win->matrix.origin.col > rightSide)
|
|
{
|
|
col = rightSide + !(win->flag & WINFLAG_NO_BORDER);
|
|
}
|
|
if (bottomSide <= 0 && !(win->flag & WINFLAG_NO_SCALE))
|
|
{
|
|
height = win->matrix.size.hth + bottomSide
|
|
- !(win->flag & WINFLAG_NO_BORDER) * 2;
|
|
|
|
bottomSide = GetScreenSize().height - height;
|
|
}
|
|
if (bottomSide > 0 && win->matrix.origin.row >= bottomSide)
|
|
{
|
|
row = bottomSide - !(win->flag & WINFLAG_NO_BORDER);
|
|
}
|
|
if (col > 0 && win->matrix.origin.col != col) {
|
|
win->matrix.origin.col = (CUINT) col;
|
|
}
|
|
if (row > 0 && win->matrix.origin.row != row) {
|
|
win->matrix.origin.row = (CUINT) row;
|
|
} else if (row == 0 && win->matrix.origin.row != row) {
|
|
win->matrix.origin.row = 1;
|
|
height = win->matrix.size.hth - 1;
|
|
}
|
|
if (height > 0 && win->matrix.size.hth != height) {
|
|
win->matrix.size.hth = (CUINT) height;
|
|
LazyCompWindow(win);
|
|
}
|
|
}
|
|
|
|
int Motion_Trigger(SCANKEY *scan, Window *win, WinList *list)
|
|
{
|
|
switch (scan->key) {
|
|
case SCANKEY_ESC:
|
|
{
|
|
Layer *thisLayer = win->layer;
|
|
|
|
if (win->hook.key.Escape != NULL)
|
|
win->hook.key.Escape(win);
|
|
else
|
|
RemoveWindow(win, list);
|
|
|
|
ResetLayer(thisLayer, RSC(UI).ATTR()[UI_FUSE_RESET_LAYER]);
|
|
}
|
|
break;
|
|
case SCANKEY_TAB:
|
|
AnimateWindow(1, list);
|
|
break;
|
|
case SCANKEY_SHIFT_TAB:
|
|
case SCANCON_SHIFT_TAB:
|
|
AnimateWindow(0, list);
|
|
break;
|
|
case SCANKEY_LEFT:
|
|
if (win->hook.key.Left != NULL)
|
|
win->hook.key.Left(win);
|
|
break;
|
|
case SCANKEY_RIGHT:
|
|
if (win->hook.key.Right != NULL)
|
|
win->hook.key.Right(win);
|
|
break;
|
|
case SCANKEY_DOWN:
|
|
if (win->hook.key.Down != NULL)
|
|
win->hook.key.Down(win);
|
|
break;
|
|
case SCANKEY_UP:
|
|
if (win->hook.key.Up != NULL)
|
|
win->hook.key.Up(win);
|
|
break;
|
|
case SCANKEY_HOME:
|
|
case SCANCON_HOME:
|
|
case SCANSYM_HOME:
|
|
if (win->hook.key.Home != NULL)
|
|
win->hook.key.Home(win);
|
|
break;
|
|
case SCANKEY_END:
|
|
case SCANCON_END:
|
|
case SCANSYM_END:
|
|
if (win->hook.key.End != NULL)
|
|
win->hook.key.End(win);
|
|
break;
|
|
case SCANKEY_PGUP:
|
|
if (win->hook.key.PgUp != NULL)
|
|
win->hook.key.PgUp(win);
|
|
break;
|
|
case SCANKEY_PGDW:
|
|
if (win->hook.key.PgDw != NULL)
|
|
win->hook.key.PgDw(win);
|
|
break;
|
|
case SCANKEY_SHIFT_RIGHT:
|
|
case SCANSYM_SHIFT_RIGHT:
|
|
case SCANKEY_SHIFT_d:
|
|
if (win->hook.key.WinRight != NULL)
|
|
win->hook.key.WinRight(win);
|
|
break;
|
|
case SCANKEY_SHIFT_LEFT:
|
|
case SCANSYM_SHIFT_LEFT:
|
|
case SCANKEY_SHIFT_a: /* AZERTY */
|
|
case SCANKEY_SHIFT_q: /* QWERTY */
|
|
if (win->hook.key.WinLeft != NULL)
|
|
win->hook.key.WinLeft(win);
|
|
break;
|
|
case SCANKEY_SHIFT_UP:
|
|
case SCANSYM_SHIFT_UP:
|
|
case SCANKEY_SHIFT_s:
|
|
if (win->hook.key.WinUp != NULL)
|
|
win->hook.key.WinUp(win);
|
|
break;
|
|
case SCANKEY_SHIFT_DOWN:
|
|
case SCANSYM_SHIFT_DOWN:
|
|
case SCANKEY_SHIFT_x:
|
|
if (win->hook.key.WinDown != NULL)
|
|
win->hook.key.WinDown(win);
|
|
break;
|
|
case SCANKEY_ALT_UP:
|
|
case SCANSYM_ALT_UP:
|
|
case SCANKEY_ALT_SHIFT_s:
|
|
case SCANKEY_ALT_s:
|
|
case SCANCON_ALT_s:
|
|
if (win->hook.key.Shrink != NULL)
|
|
win->hook.key.Shrink(win);
|
|
break;
|
|
case SCANKEY_ALT_DOWN:
|
|
case SCANSYM_ALT_DOWN:
|
|
case SCANKEY_ALT_SHIFT_x:
|
|
case SCANKEY_ALT_x:
|
|
case SCANCON_ALT_x:
|
|
if (win->hook.key.Expand != NULL)
|
|
win->hook.key.Expand(win);
|
|
break;
|
|
case SCANKEY_ENTER:
|
|
if (win->hook.key.Enter != NULL)
|
|
return win->hook.key.Enter(scan, win);
|
|
fallthrough;
|
|
default:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void ForEachCellPrint_Drop(Window *win, void *plist)
|
|
{
|
|
WinList *list = (WinList *) plist;
|
|
CUINT col, row;
|
|
for (row = 0; row < win->matrix.size.hth; row++) {
|
|
for (col = 0; col < win->matrix.size.wth; col++) {
|
|
if (TCellAt(win,
|
|
(win->matrix.scroll.horz + col),
|
|
(win->matrix.scroll.vert + row)).quick.key != SCANKEY_VOID)
|
|
{
|
|
PrintContent(win, list, col, row);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int Enter_StickyCell(SCANKEY *scan, Window *win)
|
|
{
|
|
if ((scan->key = TCellAt(win,
|
|
( win->matrix.select.col
|
|
+ win->matrix.scroll.horz),
|
|
( win->matrix.select.row
|
|
+ win->matrix.scroll.vert)
|
|
).quick.key) != SCANKEY_NULL)
|
|
{
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int MotionEnter_Cell(SCANKEY *scan, Window *win)
|
|
{
|
|
if ((scan->key = TCellAt(win,
|
|
( win->matrix.select.col
|
|
+ win->matrix.scroll.horz),
|
|
( win->matrix.select.row
|
|
+ win->matrix.scroll.vert)
|
|
).quick.key) != SCANKEY_NULL)
|
|
{
|
|
SCANKEY closeKey = {.key = SCANKEY_ESC};
|
|
Motion_Trigger(&closeKey, win,&winList);
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void MotionEnd_Cell(Window *win)
|
|
{
|
|
win->matrix.scroll.vert = LazyCompBottomRow(win);
|
|
win->matrix.select.row = win->matrix.size.hth - 1;
|
|
}
|
|
|
|
void MotionLeft_Menu(Window *win)
|
|
{
|
|
CUINT row;
|
|
for (row = 1; row < win->matrix.size.hth; row++) {
|
|
EraseTCell_Menu(win);
|
|
}
|
|
if (win->matrix.select.col > 0) {
|
|
win->matrix.select.col--;
|
|
} else {
|
|
win->matrix.select.col = win->matrix.size.wth - 1;
|
|
}
|
|
win->matrix.select.row = 0;
|
|
}
|
|
|
|
void MotionRight_Menu(Window *win)
|
|
{
|
|
CUINT row;
|
|
for (row = 1; row < win->matrix.size.hth; row++) {
|
|
EraseTCell_Menu(win);
|
|
}
|
|
if (win->matrix.select.col < win->matrix.size.wth - 1) {
|
|
win->matrix.select.col++;
|
|
} else {
|
|
win->matrix.select.col = 0;
|
|
}
|
|
win->matrix.select.row = 0;
|
|
}
|
|
|
|
void MotionUp_Menu(Window *win)
|
|
{
|
|
CUINT row = win->matrix.select.row;
|
|
|
|
if (win->matrix.select.row > 0) {
|
|
row--;
|
|
}
|
|
if (TCellAt(win,
|
|
(win->matrix.scroll.horz + win->matrix.select.col),
|
|
(win->matrix.scroll.vert + row)).quick.key != SCANKEY_VOID)
|
|
{
|
|
win->matrix.select.row = row;
|
|
}
|
|
}
|
|
|
|
void MotionDown_Menu(Window *win)
|
|
{
|
|
CUINT row = win->matrix.select.row;
|
|
|
|
if (row < win->matrix.size.hth - 1) {
|
|
row++;
|
|
}
|
|
if (TCellAt(win,
|
|
(win->matrix.scroll.horz + win->matrix.select.col),
|
|
(win->matrix.scroll.vert + row)).quick.key != SCANKEY_VOID)
|
|
{
|
|
win->matrix.select.row = row;
|
|
}
|
|
}
|
|
|
|
void MotionHome_Menu(Window *win)
|
|
{
|
|
if (TCellAt(win,
|
|
(win->matrix.scroll.horz + win->matrix.select.col),
|
|
(win->matrix.scroll.vert + 1)).quick.key != SCANKEY_VOID)
|
|
{
|
|
win->matrix.select.row = 1;
|
|
} else {
|
|
win->matrix.select.row = 0;
|
|
}
|
|
}
|
|
|
|
void MotionEnd_Menu(Window *win)
|
|
{
|
|
CUINT row = 0;
|
|
for (row = win->matrix.size.hth - 1; row > 1; row--) {
|
|
if (TCellAt(win,
|
|
(win->matrix.scroll.horz + win->matrix.select.col),
|
|
(win->matrix.scroll.vert + row)).quick.key != SCANKEY_VOID)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
win->matrix.select.row = row;
|
|
}
|
|
|
|
#define Call_PrintHook(_win, _list) \
|
|
({ \
|
|
ComputeLazyBottomRow(_win, !(_win->flag & WINFLAG_NO_BORDER)); \
|
|
\
|
|
if (_win->hook.Print != NULL) { \
|
|
MotionReScale(_win); \
|
|
_win->hook.Print(_win, _list); \
|
|
} else { \
|
|
MotionReScale(_win); \
|
|
ForEachCellPrint(_win, _list); \
|
|
PrintComment(_win); \
|
|
} \
|
|
})
|
|
|
|
void PrintWindowStack(WinList *winList)
|
|
{
|
|
Window *walker;
|
|
if ((walker = GetHead(winList)) != NULL) {
|
|
do {
|
|
walker = GetNext(walker);
|
|
Call_PrintHook(walker, winList);
|
|
}
|
|
while (!IsHead(winList, walker)) ;
|
|
}
|
|
}
|
|
|
|
void WindowsUpdate(WinList *winList)
|
|
{
|
|
Window *walker, *marker = NULL;
|
|
if ((walker = GetFocus(winList)) != NULL)
|
|
{
|
|
CUINT col, row;
|
|
do
|
|
{
|
|
walker = GetNext(walker);
|
|
for (row = 0; row < walker->matrix.size.hth; row++) {
|
|
for (col = 0; col < walker->matrix.size.wth; col++)
|
|
{
|
|
CUINT horzCol = walker->matrix.scroll.horz + col,
|
|
vertRow = walker->matrix.scroll.vert + row;
|
|
|
|
if (TGridAt(walker, horzCol, vertRow).Update != NULL)
|
|
{
|
|
TGridAt(walker, horzCol, vertRow).Update(
|
|
&TGridAt(walker, horzCol, vertRow),
|
|
TGridAt(walker, horzCol, vertRow).data);
|
|
if (marker == NULL) {
|
|
marker = GetPrev(walker);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (!IsHead(winList, walker)) ;
|
|
}
|
|
if ((walker = marker) != NULL)
|
|
{
|
|
do
|
|
{
|
|
walker = GetNext(walker);
|
|
Call_PrintHook(walker, winList);
|
|
}
|
|
while (!IsHead(winList, walker)) ;
|
|
}
|
|
}
|
|
|
|
void ReScaleAllWindows(WinList *list)
|
|
{
|
|
if (!IsDead(list)) {
|
|
Window *walker = GetHead(list);
|
|
do
|
|
{
|
|
EraseWindowWithBorder(walker);
|
|
MotionReScale(walker);
|
|
Call_PrintHook(walker, list);
|
|
|
|
walker = GetNext(walker);
|
|
} while (!IsHead(list, walker)) ;
|
|
}
|
|
}
|
|
|
|
void HookCardFunc(CARDFUNC *with, CARDFUNC what) { *with=what; }
|
|
|
|
Card *CreateCard(void)
|
|
{
|
|
Card *card = calloc(1, sizeof(Card));
|
|
if (card != NULL) {
|
|
GetNext(card) = NULL;
|
|
}
|
|
return card;
|
|
}
|
|
|
|
void AppendCard(Card *card, CardList *list)
|
|
{
|
|
if (card != NULL) {
|
|
if (GetHead(list) == NULL) {
|
|
GetHead(list) = GetTail(list) = card;
|
|
} else {
|
|
GetNext(GetTail(list)) = card;
|
|
GetTail(list) = card;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DestroyAllCards(CardList *list)
|
|
{
|
|
Card *card = GetHead(list);
|
|
while (card != NULL) {
|
|
Card *_next = GetNext(card);
|
|
free(card);
|
|
card = _next;
|
|
}
|
|
GetHead(list) = GetTail(list) = NULL;
|
|
}
|
|
|
|
void FreeAll(char *buffer)
|
|
{
|
|
DestroyAllWindows(&winList);
|
|
DestroyFullStock();
|
|
|
|
if (Console != NULL) {
|
|
free(Console);
|
|
}
|
|
if (StreamBuf != NULL) {
|
|
setbuf(stdout, NULL);
|
|
free(StreamBuf);
|
|
}
|
|
if (buffer != NULL) {
|
|
free(buffer);
|
|
}
|
|
DestroyLayer(sLayer);
|
|
DestroyLayer(dLayer);
|
|
DestroyLayer(wLayer);
|
|
DestroyLayer(Fuse);
|
|
|
|
if (sLayer != NULL) {
|
|
free(sLayer);
|
|
}
|
|
if (dLayer != NULL) {
|
|
free(dLayer);
|
|
}
|
|
if (wLayer != NULL) {
|
|
free(wLayer);
|
|
}
|
|
if (Fuse != NULL) {
|
|
free(Fuse);
|
|
}
|
|
if (Dump.Handle != NULL) {
|
|
fclose(Dump.Handle);
|
|
Dump.Handle = NULL;
|
|
}
|
|
if (Dump.Buffer != NULL) {
|
|
free(Dump.Buffer);
|
|
Dump.Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
UBENCH_DECLARE()
|
|
|
|
#define MAX_ANSI_WIDTH (10 * MAX_WIDTH)
|
|
#define MAX_ANSI_SCREEN (MAX_ANSI_WIDTH * MAX_HEIGHT)
|
|
__typeof__ (errno) AllocAll(char **buffer)
|
|
{ /* Alloc 10 times to include the ANSI cursor strings. */
|
|
|
|
if ((*buffer = malloc(MAX_ANSI_WIDTH)) == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
if ((Console = malloc(MAX_ANSI_SCREEN)) == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
if ((StreamBuf = malloc(MAX_ANSI_SCREEN)) == NULL) {
|
|
return ENOMEM;
|
|
} else {
|
|
setvbuf(stdout, StreamBuf, _IOFBF, MAX_ANSI_SCREEN);
|
|
}
|
|
const CoordSize layerSize = {
|
|
.wth = MAX_WIDTH,
|
|
.hth = MAX_HEIGHT
|
|
};
|
|
|
|
if ((sLayer = calloc(1, sizeof(Layer))) == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
if ((dLayer = calloc(1, sizeof(Layer))) == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
if ((wLayer = calloc(1, sizeof(Layer))) == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
if ((Fuse = calloc(1, sizeof(Layer))) == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
CreateLayer(sLayer, layerSize);
|
|
CreateLayer(dLayer, layerSize);
|
|
CreateLayer(wLayer, layerSize);
|
|
CreateLayer(Fuse, layerSize);
|
|
|
|
UBENCH_SETUP(1, 0);
|
|
return 0;
|
|
}
|
|
|
|
signed int FuseAll(ASCII stream[], SCREEN_SIZE drawSize)
|
|
{
|
|
register ATTRIBUTE *fa, *sa, *da, *wa;
|
|
register ASCII *fc, *sc, *dc, *wc;
|
|
register signed int _col, _row, cursor;
|
|
register signed int idx, sdx = 0;
|
|
register ATTRIBUTE attr = {.value = 0};
|
|
|
|
for (_row = 0; _row < drawSize.height; _row++)
|
|
{
|
|
stream[sdx++] = 0x1b;
|
|
stream[sdx++] = '[';
|
|
|
|
cursor = _row + 1;
|
|
sdx += cursor >= 100 ? 3 : cursor >= 10 ? 2 : 1;
|
|
for (idx = sdx; cursor > 0; cursor /= 10) {
|
|
stream[--idx] = '0' + (ASCII) (cursor % 10);
|
|
}
|
|
stream[sdx++] = ';';
|
|
stream[sdx++] = '1';
|
|
stream[sdx++] = 'H';
|
|
|
|
cursor = _row * Fuse->size.wth;
|
|
for (_col = 0; _col < drawSize.width; _col++)
|
|
{
|
|
idx = _col + cursor;
|
|
fa = &Fuse->attr[idx];
|
|
sa = &sLayer->attr[idx];
|
|
da = &dLayer->attr[idx];
|
|
wa = &wLayer->attr[idx];
|
|
fc = &Fuse->code[idx];
|
|
sc = &sLayer->code[idx];
|
|
dc = &dLayer->code[idx];
|
|
wc = &wLayer->code[idx];
|
|
/* STATIC LAYER */
|
|
fa->value = sa->value;
|
|
*fc = *sc;
|
|
/* DYNAMIC LAYER */
|
|
fa->value = da->value ? da->value : fa->value;
|
|
*fc = *dc ? *dc : *fc;
|
|
/* WINDOWS LAYER */
|
|
fa->value = wa->value ? wa->value : fa->value;
|
|
*fc = *wc ? *wc : *fc;
|
|
/* FUSED LAYER */
|
|
if ((fa->fg ^ attr.fg) || (fa->bg ^ attr.bg) || (fa->bf ^ attr.bf))
|
|
{
|
|
stream[sdx++] = 0x1b;
|
|
stream[sdx++] = '[';
|
|
stream[sdx++] = '0' + fa->bf;
|
|
stream[sdx++] = ';';
|
|
stream[sdx++] = fa->bf ? '9' : '3';
|
|
stream[sdx++] = '0' + fa->fg;
|
|
#ifndef UI_TRANSPARENCY
|
|
stream[sdx++] = ';';
|
|
stream[sdx++] = '4';
|
|
stream[sdx++] = '0' + fa->bg;
|
|
#endif /* UI_TRANSPARENCY */
|
|
stream[sdx++] = 'm';
|
|
}
|
|
if (fa->un ^ attr.un)
|
|
{
|
|
stream[sdx++] = 0x1b;
|
|
stream[sdx++] = '[';
|
|
if (fa->un) {
|
|
stream[sdx++] = '4';
|
|
stream[sdx++] = 'm';
|
|
} else {
|
|
stream[sdx++] = '2';
|
|
stream[sdx++] = '4';
|
|
stream[sdx++] = 'm';
|
|
}
|
|
}
|
|
attr.value = fa->value;
|
|
|
|
switch (*fc) {
|
|
case 0x0:
|
|
stream[sdx++] = 0x20;
|
|
break;
|
|
case 0xc0 ... 0xdf:
|
|
stream[sdx++] = 0xc2; /* Control C2 Unicode UTF-8 */
|
|
stream[sdx++] = *fc ^ 0x60;
|
|
break;
|
|
case 0x80 ... 0xbf:
|
|
stream[sdx++] = 0xc3; /* Control C3 Unicode UTF-8 */
|
|
fallthrough;
|
|
default:
|
|
stream[sdx++] = *fc;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return sdx;
|
|
}
|
|
|
|
__typeof__ (errno) StartDump( char *dumpFormat, int tickReset,
|
|
enum DUMP_METHOD method )
|
|
{
|
|
__typeof__ (errno) rc = EBUSY;
|
|
|
|
if (!BITVAL(Dump.Status, 0))
|
|
{
|
|
char *dumpFileName = malloc(64);
|
|
if (dumpFileName != NULL)
|
|
{
|
|
if ((Dump.Buffer = malloc(MAX_ANSI_SCREEN)) != NULL)
|
|
{
|
|
Bit64 tsc __attribute__ ((aligned (8)));
|
|
RDTSC64(tsc);
|
|
|
|
snprintf(dumpFileName, 64, dumpFormat, tsc);
|
|
if ((Dump.Handle = fopen(dumpFileName, "w")) != NULL)
|
|
{
|
|
setvbuf(Dump.Handle,Dump.Buffer,_IOFBF,MAX_ANSI_SCREEN);
|
|
|
|
switch (method) {
|
|
case DUMP_TO_JSON:
|
|
Dump.Header= JSON_Header;
|
|
Dump.Write = JSON_Page;
|
|
Dump.Break = JSON_Break;
|
|
break;
|
|
case DUMP_TO_ANSI:
|
|
Dump.Header= ANSI_Header;
|
|
Dump.Write = ANSI_Page;
|
|
Dump.Break = ANSI_Break;
|
|
break;
|
|
};
|
|
Dump.Tick = tickReset;
|
|
Dump.Header();
|
|
BITSET(LOCKLESS, Dump.Status, 0);
|
|
rc = 0;
|
|
} else {
|
|
rc = errno;
|
|
free(Dump.Buffer);
|
|
Dump.Buffer = NULL;
|
|
}
|
|
} else {
|
|
rc = ENOMEM;
|
|
}
|
|
free(dumpFileName);
|
|
} else {
|
|
rc = ENOMEM;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
void AbortDump(void)
|
|
{
|
|
Dump.Tick = 0;
|
|
}
|
|
|
|
unsigned char DumpStatus(void)
|
|
{
|
|
return BITVAL(Dump.Status, 0);
|
|
}
|
|
|
|
unsigned int WriteConsole(SCREEN_SIZE drawSize)
|
|
{
|
|
signed int writeSize;
|
|
unsigned int layout = 0;
|
|
|
|
UI_Draw_uBenchmark(dLayer);
|
|
|
|
UBENCH_RDCOUNTER(1);
|
|
|
|
writeSize = FuseAll((ASCII*) Console, drawSize);
|
|
|
|
UBENCH_RDCOUNTER(2);
|
|
UBENCH_COMPUTE();
|
|
|
|
if (writeSize > 0)
|
|
{
|
|
if (fwrite(Console, (size_t) writeSize, 1, stdout) > 0) {
|
|
fflush(stdout);
|
|
}
|
|
if (BITVAL(Dump.Status, 0))
|
|
{
|
|
Dump.Write(Console, writeSize);
|
|
|
|
if (Dump.Tick > 0) {
|
|
Dump.Tick--;
|
|
|
|
Dump.Break();
|
|
} else {
|
|
BITCLR(LOCKLESS, Dump.Status, 0);
|
|
|
|
if (fclose(Dump.Handle) == 0) {
|
|
Dump.Handle = NULL;
|
|
}
|
|
if (Dump.Buffer != NULL) {
|
|
free(Dump.Buffer);
|
|
Dump.Buffer = NULL;
|
|
}
|
|
layout = 1;
|
|
}
|
|
}
|
|
}
|
|
return layout;
|
|
}
|
|
|
|
void ANSI_Header(void)
|
|
{
|
|
}
|
|
|
|
void ANSI_Page(char *inStr, int outSize)
|
|
{
|
|
fwrite(inStr, (size_t) outSize, 1, Dump.Handle);
|
|
}
|
|
|
|
void ANSI_Break(void)
|
|
{
|
|
fwrite( _LF _FF, 1, 1, Dump.Handle);
|
|
}
|
|
|
|
void JSON_Header(void)
|
|
{
|
|
SCREEN_SIZE terminalSize = GetScreenSize();
|
|
|
|
time(&Dump.StartedAt);
|
|
fprintf(Dump.Handle,
|
|
"{\"version\": %d, \"width\": %d, \"height\": %d," \
|
|
" \"timestamp\": %ld, \"title\": \"%s\", " \
|
|
"\"env\": {\"TERM\": \"%s\"}}\n",
|
|
2, terminalSize.width, terminalSize.height,
|
|
Dump.StartedAt, "CoreFreq", "xterm");
|
|
}
|
|
|
|
void JSON_Page(char *inStr, int outSize)
|
|
{
|
|
double integral, fractional;
|
|
unsigned char *pLast = (unsigned char *) &inStr[outSize],
|
|
*pFirst= (unsigned char *) &inStr[0], *pChr;
|
|
time_t now;
|
|
time(&now);
|
|
|
|
fractional = modf(difftime(now, Dump.StartedAt), &integral);
|
|
fprintf(Dump.Handle, "[%lld.%lld, \"o\", \"",
|
|
(signed long long) integral,
|
|
(signed long long) fractional);
|
|
|
|
for (pChr = pFirst; pChr < pLast; pChr++) {
|
|
switch (*pChr) {
|
|
case 0x1b:
|
|
fprintf(Dump.Handle, "\\u001b");
|
|
break;
|
|
case 0xc2:
|
|
fprintf(Dump.Handle, "\\u00%x", *(++pChr));
|
|
break;
|
|
case 0xc3:
|
|
fprintf(Dump.Handle, "\\u00%x", *(++pChr) ^ 0x40);
|
|
break;
|
|
case '\\':
|
|
fprintf(Dump.Handle, "\\u005c");
|
|
break;
|
|
default:
|
|
fputc((*pChr), Dump.Handle);
|
|
break;
|
|
}
|
|
}
|
|
fprintf(Dump.Handle, "\"]\n");
|
|
}
|
|
|
|
void JSON_Break(void)
|
|
{
|
|
}
|
|
#undef MAX_ANSI_SCREEN
|
|
#undef MAX_ANSI_WIDTH
|
|
|
|
void _TERMINAL_IN(void)
|
|
{
|
|
printf(SCP SCR1 CUH CLS HIDE);
|
|
|
|
tcgetattr(STDIN_FILENO, &oldt);
|
|
newt = oldt;
|
|
__typeof__(newt.c_lflag) flags = ICANON | ECHO;
|
|
flags = ~flags;
|
|
newt.c_lflag &= flags;
|
|
newt.c_cc[VTIME] = 0;
|
|
newt.c_cc[VMIN] = 0;
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
|
}
|
|
|
|
void _TERMINAL_OUT(void)
|
|
{
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
|
|
|
printf(SHOW SCR0 RCP COLOR(0,9,9));
|
|
}
|
|
|
|
void _LOCALE_IN(void)
|
|
{
|
|
SysLoc = newlocale(LC_MESSAGES_MASK, "", (locale_t) 0);
|
|
|
|
if (SysLoc != NULL) {
|
|
const char *s18n = SysLoc->__names[5];
|
|
struct LOCALE_LOOKUP *lookUp = LocaleLookUp;
|
|
while (lookUp->i18n != NULL) {
|
|
I18N *i18n = lookUp->i18n;
|
|
while (i18n[0][0] != 0) {
|
|
if (!strncmp((char *) i18n, s18n, sizeof(I18N)))
|
|
{
|
|
SET_LOCALE(lookUp->apploc);
|
|
return;
|
|
}
|
|
i18n++;
|
|
}
|
|
lookUp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _LOCALE_OUT(void)
|
|
{
|
|
if (SysLoc != (locale_t) 0) {
|
|
freelocale(SysLoc);
|
|
}
|
|
}
|
|
|
|
void LocaleTo(int category)
|
|
{
|
|
struct LOCALE_LOOKUP *lookUp = LocaleLookUp;
|
|
while (lookUp->i18n != NULL) {
|
|
if (lookUp->apploc == GET_LOCALE()) {
|
|
char localeStr[sizeof(I18N) + 1];
|
|
memcpy(localeStr, lookUp->i18n[0], sizeof(I18N));
|
|
localeStr[sizeof(I18N)] = '\0';
|
|
setlocale(category, localeStr);
|
|
return;
|
|
}
|
|
lookUp++;
|
|
}
|
|
setlocale(category, "C");
|
|
}
|
|
|
|
__typeof__ (errno) SaveGeometries(char *cfgFQN)
|
|
{
|
|
__typeof__ (errno) rc = 0;
|
|
FILE *cfgHandle = NULL;
|
|
if ((cfgHandle = fopen(cfgFQN, "w")) == NULL)
|
|
{
|
|
char *cfgdup = strdup(cfgFQN);
|
|
if (cfgdup != NULL)
|
|
{
|
|
char *dirOnly = dirname(cfgdup);
|
|
rc = mkdir(dirOnly, S_IRWXU);
|
|
free(cfgdup);
|
|
} else {
|
|
rc = errno;
|
|
}
|
|
}
|
|
if ((cfgHandle != NULL) || (cfgHandle = fopen(cfgFQN, "w")) != NULL)
|
|
{
|
|
Stock *walker = stockList.head;
|
|
while (walker != NULL) {
|
|
if (fprintf(cfgHandle, "%llx,%hu,%hu\n",
|
|
walker->id,
|
|
walker->geometry.origin.col,
|
|
walker->geometry.origin.row) < 0)
|
|
{
|
|
rc = errno;
|
|
break;
|
|
} else {
|
|
walker = GetNext(walker);
|
|
}
|
|
}
|
|
fclose(cfgHandle);
|
|
} else {
|
|
rc = errno;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
__typeof__ (errno) LoadGeometries(char *cfgFQN)
|
|
{
|
|
__typeof__ (errno) rc = 0;
|
|
FILE *cfgHandle = NULL;
|
|
if ((cfgHandle = fopen(cfgFQN, "r")) != NULL)
|
|
{
|
|
while (!feof(cfgHandle))
|
|
{
|
|
unsigned long long id;
|
|
struct Geometry geometry;
|
|
int match = fscanf(cfgHandle, "%llx,%hu,%hu\n",
|
|
&id,
|
|
&geometry.origin.col,
|
|
&geometry.origin.row);
|
|
|
|
if ((match != EOF) && (match == 3))
|
|
{
|
|
if (AppendStock(CreateStock(id, geometry.origin)) == NULL)
|
|
{
|
|
rc = ENOMEM;
|
|
break;
|
|
}
|
|
} else {
|
|
rc = errno;
|
|
break;
|
|
}
|
|
}
|
|
fclose(cfgHandle);
|
|
} else {
|
|
rc = errno;
|
|
}
|
|
return rc;
|
|
}
|