Meta: Add files to repository
This commit is contained in:
parent
80a0428b66
commit
39198164cd
1029 changed files with 78311 additions and 0 deletions
65
System/Libraries/Animation2D.HC
Normal file
65
System/Libraries/Animation2D.HC
Normal file
|
@ -0,0 +1,65 @@
|
|||
class AnimationContext2D {
|
||||
U64 signature;
|
||||
I64 duration; // in jiffies
|
||||
I64 index; // current frame
|
||||
I64 length; // length in frames
|
||||
I64 timer; // timer + cnts.jiffies = current ticks
|
||||
Context2D** frame; // Context2D*, ...
|
||||
};
|
||||
|
||||
AnimationContext2D* @animation2d_new_from_frames(Context2D** frames, I64 length,
|
||||
I64 duration = 250)
|
||||
{
|
||||
if (!frames || !length)
|
||||
return NULL;
|
||||
AnimationContext2D* actx = CAlloc(sizeof(AnimationContext2D));
|
||||
actx->signature = 'animated';
|
||||
actx->frame = frames;
|
||||
actx->length = length;
|
||||
actx->duration = duration;
|
||||
return actx;
|
||||
}
|
||||
|
||||
Context2D* @animation2d_frame(AnimationContext2D* actx)
|
||||
{
|
||||
I64 ticks = cnts.jiffies;
|
||||
if (!actx)
|
||||
return NULL;
|
||||
if (!actx->length)
|
||||
return NULL;
|
||||
if (actx->index > actx->length - 1)
|
||||
actx->index = 0;
|
||||
if (!actx->index && !actx->timer)
|
||||
actx->timer = ticks;
|
||||
while (ticks >= actx->timer + actx->duration) {
|
||||
actx->timer += actx->duration;
|
||||
actx->index++;
|
||||
if (actx->index > actx->length - 1)
|
||||
actx->index = 0;
|
||||
}
|
||||
return actx->frame[actx->index];
|
||||
}
|
||||
|
||||
Bool @animation2d_is_animation(AnimationContext2D* actx)
|
||||
{
|
||||
return T(actx->signature == 'animated', TRUE, FALSE);
|
||||
}
|
||||
|
||||
U0 @animation2d_reset(AnimationContext2D* actx) { actx->index = 0; }
|
||||
|
||||
class @animation2d
|
||||
{
|
||||
Context2D* (*Frame)(AnimationContext2D* actx);
|
||||
U0 (*Reset)(AnimationContext2D* actx);
|
||||
Bool (*IsAnimation)(AnimationContext2D* actx);
|
||||
AnimationContext2D* (*NewFromFrames)(Context2D** frames, I64 length,
|
||||
I64 duration = 250);
|
||||
};
|
||||
|
||||
@animation2d Animation2D;
|
||||
Animation2D.IsAnimation = &@animation2d_is_animation;
|
||||
Animation2D.NewFromFrames = &@animation2d_new_from_frames;
|
||||
Animation2D.Frame = &@animation2d_frame;
|
||||
Animation2D.Reset = &@animation2d_reset;
|
||||
|
||||
"animation2d ";
|
143
System/Libraries/Audio.HC
Normal file
143
System/Libraries/Audio.HC
Normal file
|
@ -0,0 +1,143 @@
|
|||
// WAV header spec information:
|
||||
// https://web.archive.org/web/20140327141505/https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
|
||||
// http://www.topherlee.com/software/pcm-tut-wavformat.html
|
||||
|
||||
class @sound_file_wav_header
|
||||
{
|
||||
// RIFF Header
|
||||
U8 riff_header[4]; // Contains "RIFF"
|
||||
I32 wav_size; // Size of the wav portion of the file, which follows the first
|
||||
// 8 bytes. File size - 8
|
||||
U8 wave_header[4]; // Contains "WAVE"
|
||||
|
||||
// Format Header
|
||||
U8 fmt_header[4]; // Contains "fmt " (includes trailing space)
|
||||
I32 fmt_chunk_size; // Should be 16 for PCM
|
||||
I16 audio_format; // Should be 1 for PCM. 3 for IEEE Float
|
||||
I16 num_channels;
|
||||
I32 sample_rate;
|
||||
I32 byte_rate; // Number of bytes per second. sample_rate * num_channels *
|
||||
// Bytes Per Sample
|
||||
I16 sample_alignment; // num_channels * Bytes Per Sample
|
||||
I16 bit_depth; // Number of bits per sample
|
||||
|
||||
// Data
|
||||
U8 data_header[4]; // Contains "data"
|
||||
I32 data_bytes; // Number of bytes in data. Number of samples * num_channels *
|
||||
// sample byte size
|
||||
U8 bytes[0]; // Remainder of wave file is bytes
|
||||
};
|
||||
|
||||
I64 @audio_get_available_output_stream()
|
||||
{
|
||||
I64 stream = 0;
|
||||
while (FifoI64Cnt(Audio.output[stream].data))
|
||||
stream++;
|
||||
if (stream > AUDIO_MAX_STREAMS - 1)
|
||||
return -1;
|
||||
return stream;
|
||||
}
|
||||
|
||||
Bool @audio_buffer_is_wav(@sound_file_wav_header* wav, I64 size)
|
||||
{
|
||||
if (!MemCmp(&wav->riff_header, "RIFF", 4) && !MemCmp(&wav->wave_header, "WAVE", 4))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 @audio_free_sound(Sound* snd)
|
||||
{
|
||||
if (!snd)
|
||||
return;
|
||||
if (snd->data)
|
||||
Free(snd->data);
|
||||
Free(snd);
|
||||
}
|
||||
|
||||
I64 @audio_play_sound(Sound* snd)
|
||||
{
|
||||
I64 i;
|
||||
I64 stream = @audio_get_available_output_stream;
|
||||
if (stream < 0)
|
||||
return stream;
|
||||
if (!snd->data || !snd->length)
|
||||
return stream;
|
||||
for (i = 0; i < snd->length; i++)
|
||||
FifoI64Ins(Audio.output[stream].data, snd->data[i]);
|
||||
return stream;
|
||||
}
|
||||
|
||||
Sound* @audio_sound_from_buffer(U32* buf, I64 length)
|
||||
{
|
||||
if (!buf || !length)
|
||||
return NULL;
|
||||
Sound* snd = CAlloc(sizeof(Sound));
|
||||
snd->rate = 44100;
|
||||
snd->channels = 2;
|
||||
snd->bits = 16;
|
||||
snd->data = buf;
|
||||
snd->length = length;
|
||||
return snd;
|
||||
}
|
||||
|
||||
U32* @audio_buffer_mono_to_stereo(U16* buf, I64 size)
|
||||
{
|
||||
U32* out = CAlloc(size * 2);
|
||||
I64 i;
|
||||
for (i = 0; i < size / 2; i++) {
|
||||
out[i].u16[0] = buf[i];
|
||||
out[i].u16[1] = buf[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
U32* @audio_buffer_copy(U32* buf, I64 size)
|
||||
{
|
||||
U32* out = MAlloc(size);
|
||||
MemCpyU32(out, buf, size / 4);
|
||||
return out;
|
||||
}
|
||||
|
||||
Sound* @audio_sound_from_file(U8* filename)
|
||||
{
|
||||
if (!FileSystem.PathExists(filename))
|
||||
return NULL;
|
||||
I64 length = 0;
|
||||
U32* buf = NULL;
|
||||
I64 size = 0;
|
||||
U8* data = FileSystem.ReadFile(filename, &size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
if (@audio_buffer_is_wav(data, size)) {
|
||||
@sound_file_wav_header* wav = data;
|
||||
if (wav->fmt_chunk_size == 16 && wav->audio_format == 1 && wav->sample_rate == 48000) {
|
||||
switch (wav->num_channels) {
|
||||
case 1:
|
||||
buf = @audio_buffer_mono_to_stereo(&wav->bytes, wav->data_bytes);
|
||||
length = wav->data_bytes / 2;
|
||||
break;
|
||||
case 2:
|
||||
buf = @audio_buffer_copy(&wav->bytes, wav->data_bytes);
|
||||
length = wav->data_bytes / 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(data);
|
||||
return @audio_sound_from_buffer(buf, length);
|
||||
}
|
||||
|
||||
U0 @audio_snd(I8 ona = 0) { Audio.wavegen.frequency = Ona2Freq(ona); }
|
||||
|
||||
Audio.SoundFromFile = &@audio_sound_from_file;
|
||||
Audio.FreeSound = &@audio_free_sound;
|
||||
Audio.PlaySound = &@audio_play_sound;
|
||||
|
||||
Sound* @snd_beep = Audio.SoundFromFile("/mnt/redsea/t/Media/Sounds/Beep.wav");
|
||||
|
||||
U0 @audio_beep() { Audio.PlaySound(@snd_beep); }
|
||||
|
||||
Audio.Beep = &@audio_beep;
|
||||
Function.Patch(&Snd, &@audio_snd);
|
||||
|
||||
"audio ";
|
90
System/Libraries/Base64.HC
Normal file
90
System/Libraries/Base64.HC
Normal file
|
@ -0,0 +1,90 @@
|
|||
|
||||
U8* @base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
U8* @base64_decode(U8* input, I64* output_length)
|
||||
{
|
||||
I64 input_length = StrLen(input);
|
||||
if (input_length % 4 != 0) {
|
||||
return NULL; // Invalid Base64 input length
|
||||
}
|
||||
|
||||
// Calculate the expected output length
|
||||
*output_length = (3 * input_length) / 4;
|
||||
if (input[input_length - 1] == '=') {
|
||||
(*output_length)--;
|
||||
}
|
||||
if (input[input_length - 2] == '=') {
|
||||
(*output_length)--;
|
||||
}
|
||||
|
||||
// Allocate memory for the decoded data
|
||||
U8* decoded_data = CAlloc(*output_length, erythros_mem_task);
|
||||
if (decoded_data == NULL) {
|
||||
return NULL; // Memory allocation failed
|
||||
}
|
||||
|
||||
// Initialize variables for decoding process
|
||||
I32 i, j = 0;
|
||||
U32 sextet_bits = 0;
|
||||
I64 sextet_count = 0;
|
||||
U32 base64_value;
|
||||
U8* char_pointer;
|
||||
U8 input_find_buf[2];
|
||||
input_find_buf[1] = NULL;
|
||||
|
||||
// Loop through the Base64 input and decode it
|
||||
for (i = 0; i < input_length; i++) {
|
||||
// Convert Base64 character to a 6-bit value
|
||||
base64_value = 0;
|
||||
if (input[i] == '=') {
|
||||
base64_value = 0;
|
||||
} else {
|
||||
input_find_buf[0] = input[i];
|
||||
char_pointer = StrFirstOcc(@base64_chars, input_find_buf);
|
||||
if (char_pointer == NULL) {
|
||||
Free(decoded_data);
|
||||
return NULL; // Invalid Base64 character
|
||||
}
|
||||
base64_value = char_pointer - @base64_chars;
|
||||
}
|
||||
|
||||
// Combine 6-bit values into a 24-bit sextet
|
||||
sextet_bits = (sextet_bits << 6) | base64_value;
|
||||
sextet_count++;
|
||||
|
||||
// When a sextet is complete, decode it into three bytes
|
||||
if (sextet_count == 4) {
|
||||
decoded_data[j++] = (sextet_bits >> 16) & 0xFF;
|
||||
decoded_data[j++] = (sextet_bits >> 8) & 0xFF;
|
||||
decoded_data[j++] = sextet_bits & 0xFF;
|
||||
sextet_bits = 0;
|
||||
sextet_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return decoded_data;
|
||||
}
|
||||
|
||||
U8* @base64_encode(U8* input, I64 input_length)
|
||||
{
|
||||
I64 i;
|
||||
U8 buf[3];
|
||||
I64 c = 0;
|
||||
U8* output = CAlloc(input_length * 2, erythros_mem_task);
|
||||
|
||||
for (i = 0; i < input_length; i += 3) {
|
||||
buf[0] = input[i];
|
||||
buf[1] = @t((i + 1 < input_length), input[i + 1], 0);
|
||||
buf[2] = @t((i + 2 < input_length), input[i + 2], 0);
|
||||
|
||||
output[c++] = @base64_chars[(buf[0] & 0xfc) >> 2];
|
||||
output[c++] = @base64_chars[((buf[0] & 0x03) << 4) + ((buf[1] & 0xf0) >> 4)];
|
||||
output[c++] = @t((i + 1 < input_length), @base64_chars[((buf[1] & 0x0f) << 2) + ((buf[2] & 0xc0) >> 6)], '=');
|
||||
output[c++] = @t((i + 2 < input_length), @base64_chars[buf[2] & 0x3f], '=');
|
||||
}
|
||||
|
||||
output[c] = '\0';
|
||||
return output;
|
||||
}
|
||||
|
||||
"base64 ";
|
146
System/Libraries/BitmapFont.HC
Normal file
146
System/Libraries/BitmapFont.HC
Normal file
|
@ -0,0 +1,146 @@
|
|||
extern class Context2D;
|
||||
extern U32 Color(I64 r, I64 g, I64 b, I64 a = 255);
|
||||
extern U32 Peek2D(Context2D* ctx, I64 x, I64 y);
|
||||
|
||||
class BitmapFont {
|
||||
U8* name;
|
||||
U8* char_map;
|
||||
I64 line_height;
|
||||
U16 bitmap[4096];
|
||||
};
|
||||
|
||||
class @bitmap_font_list
|
||||
{
|
||||
@bitmap_font_list* prev;
|
||||
@bitmap_font_list* next;
|
||||
BitmapFont* font;
|
||||
};
|
||||
|
||||
class @bitmapfont
|
||||
{
|
||||
@bitmap_font_list* fonts;
|
||||
U0 (*Add)(BitmapFont* font);
|
||||
BitmapFont* (*GetByName)(U8* name);
|
||||
U0 (*Init)();
|
||||
};
|
||||
|
||||
// BitmapFont* @bitmapfont_new_from_bdf_data(Context2D* ctx, U8* bdf_data)
|
||||
//{
|
||||
// BitmapFont* font = CAlloc(sizeof(BitmapFont));
|
||||
//
|
||||
// I64 bdf_lines_max = 0;
|
||||
// U8** bdf_lines = String.Split(bdf_data, , &bdf_lines_max);
|
||||
//
|
||||
// I64 char_pos = 0;
|
||||
// I64 char_x_pos = 0;
|
||||
// I64 i, w;
|
||||
// I64 xx, yy;
|
||||
// /*
|
||||
// while (*char_map++) {
|
||||
// // Clear character bitmap
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// font->bitmap[(char_pos * 16) + i] = 0;
|
||||
// }
|
||||
// // Get character width
|
||||
// w = 0;
|
||||
// for (xx = 0; xx < 16; xx++) {
|
||||
// if (Peek2D(ctx, char_x_pos + xx, 0) == Color(255, 0, 0)) {
|
||||
// w = xx;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// // Extract bitmap
|
||||
// for (yy = 0; yy < 16; yy++) {
|
||||
// for (xx = 0; xx < w + 1; xx++) {
|
||||
// if (Peek2D(ctx, char_x_pos + xx, yy) == Color(0, 0, 0)) {
|
||||
// font->bitmap[(char_pos * 16) + yy] |= 0x8000 >> xx;
|
||||
// }
|
||||
// }
|
||||
// //"%016b\n", font->bitmap[(char_pos * 16) + yy];
|
||||
// }
|
||||
// char_pos++;
|
||||
// char_x_pos += w + 1;
|
||||
// }
|
||||
// */
|
||||
// return font;
|
||||
// }
|
||||
|
||||
BitmapFont* @bitmapfont_new_from_context2d(Context2D* ctx, U8* name,
|
||||
U8* char_map, I64 fixed_width = 0)
|
||||
{
|
||||
BitmapFont* font = CAlloc(sizeof(BitmapFont));
|
||||
font->name = StrNew(name);
|
||||
font->char_map = StrNew(char_map);
|
||||
|
||||
I64 char_pos = 0;
|
||||
I64 char_x_pos = 0;
|
||||
I64 i, w;
|
||||
I64 xx, yy;
|
||||
while (*char_map++) {
|
||||
// Clear character bitmap
|
||||
for (i = 0; i < 16; i++) {
|
||||
font->bitmap[(char_pos * 16) + i] = 0;
|
||||
}
|
||||
w = fixed_width;
|
||||
if (!w) {
|
||||
// Get character width
|
||||
for (xx = 0; xx < 16; xx++) {
|
||||
if (Peek2D(ctx, char_x_pos + xx, 0) == Color(255, 0, 0)) {
|
||||
w = xx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Extract bitmap
|
||||
for (yy = 0; yy < 16; yy++) {
|
||||
for (xx = 0; xx < w + 1; xx++) {
|
||||
if (Peek2D(ctx, char_x_pos + xx, yy) == Color(0, 0, 0)) {
|
||||
font->bitmap[(char_pos * 16) + yy] |= 0x8000 >> xx;
|
||||
}
|
||||
}
|
||||
//"%016b\n", font->bitmap[(char_pos * 16) + yy];
|
||||
}
|
||||
char_pos++;
|
||||
char_x_pos += w + 1;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
@bitmapfont BitmapFonts;
|
||||
|
||||
U0 @bitmap_fonts_add(BitmapFont* font)
|
||||
{
|
||||
@bitmap_font_list* fonts = BitmapFonts.fonts;
|
||||
while (fonts->next) {
|
||||
fonts = fonts->next;
|
||||
}
|
||||
@bitmap_font_list* font_list_item = CAlloc(sizeof(@bitmap_font_list));
|
||||
font_list_item->prev = fonts;
|
||||
font_list_item->font = font;
|
||||
fonts->next = font_list_item;
|
||||
}
|
||||
|
||||
BitmapFont* @bitmap_fonts_get_by_name(U8* name)
|
||||
{
|
||||
@bitmap_font_list* fonts = BitmapFonts.fonts;
|
||||
while (fonts) {
|
||||
if (fonts->font) {
|
||||
if (!StrCmp(fonts->font->name, name))
|
||||
return fonts->font;
|
||||
}
|
||||
fonts = fonts->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 @bitmap_fonts_init()
|
||||
{
|
||||
BitmapFonts.fonts = CAlloc(sizeof(@bitmap_font_list));
|
||||
}
|
||||
|
||||
BitmapFonts.Add = &@bitmap_fonts_add;
|
||||
BitmapFonts.GetByName = &@bitmap_fonts_get_by_name;
|
||||
BitmapFonts.Init = &@bitmap_fonts_init;
|
||||
BitmapFonts.Init();
|
||||
|
||||
"bitmapfont ";
|
125
System/Libraries/Clipboard.HC
Normal file
125
System/Libraries/Clipboard.HC
Normal file
|
@ -0,0 +1,125 @@
|
|||
#define CLIP_MSG_NULL 0
|
||||
#define CLIP_MSG_INSERT 1
|
||||
#define CLIP_MSG_REMOVE 2
|
||||
|
||||
#define CLIP_TYPE_NULL 0
|
||||
#define CLIP_TYPE_TEXT 1
|
||||
#define CLIP_TYPE_DATA 2
|
||||
|
||||
class @clipboard_item
|
||||
{
|
||||
I64 length;
|
||||
I64 type;
|
||||
};
|
||||
|
||||
class ClipboardTextItem : @clipboard_item {
|
||||
U8* text;
|
||||
}
|
||||
|
||||
class ClipboardDataItem : @clipboard_item {
|
||||
U8* data;
|
||||
}
|
||||
|
||||
class @clipboard_list_item
|
||||
{
|
||||
@clipboard_list_item* prev;
|
||||
@clipboard_list_item* next;
|
||||
@clipboard_item* item;
|
||||
};
|
||||
|
||||
class @clipboard
|
||||
{
|
||||
CTask* task;
|
||||
I64 length;
|
||||
@clipboard_list_item* items;
|
||||
U0 (*Init)();
|
||||
U0 (*Insert)(I64 type, U8* data);
|
||||
I64 (*Length)();
|
||||
U0(*Task)
|
||||
();
|
||||
};
|
||||
|
||||
@clipboard Clipboard;
|
||||
|
||||
U0 @clipboard_add(@clipboard_item* item)
|
||||
{
|
||||
@clipboard_list_item* items = Clipboard.items;
|
||||
while (items->next) {
|
||||
items = items->next;
|
||||
}
|
||||
@clipboard_list_item* new_item = CAlloc(sizeof(@clipboard_list_item));
|
||||
new_item->prev = items;
|
||||
new_item->item = item;
|
||||
items->next = new_item;
|
||||
Clipboard.length++;
|
||||
Clipboard.items->prev = new_item;
|
||||
}
|
||||
|
||||
U0 @clipboard_init() { Clipboard.items = CAlloc(sizeof(@clipboard_list_item)); }
|
||||
|
||||
I64 @clipboard_length() { return Clipboard.length; }
|
||||
|
||||
U0 @clipboard_ipc_queue_process()
|
||||
{
|
||||
IpcMessage* msg;
|
||||
msg = Ipc.MsgRecv();
|
||||
if (msg) {
|
||||
switch (msg->type) {
|
||||
case CLIP_MSG_INSERT:
|
||||
@clipboard_add(msg->payload);
|
||||
break;
|
||||
case CLIP_MSG_REMOVE:
|
||||
// FIXME: Handle this
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
U0 @clipboard_insert_text(U8* text)
|
||||
{
|
||||
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
|
||||
ClipboardTextItem* item = CAlloc(sizeof(ClipboardTextItem));
|
||||
item->length = StrLen(text);
|
||||
item->type = CLIP_TYPE_TEXT;
|
||||
item->text = text;
|
||||
msg->client = NULL; // FIXME: Do we care about client here? :/
|
||||
msg->type = CLIP_MSG_INSERT;
|
||||
msg->payload = item;
|
||||
System.Log(Fs, "Sent message → ClipInsert -> \"%s\"", text);
|
||||
Ipc.MsgSend(Clipboard.task, msg);
|
||||
}
|
||||
|
||||
U0 @clipboard_insert(I64 type, U8* data)
|
||||
{
|
||||
switch (type) {
|
||||
case CLIP_TYPE_TEXT:
|
||||
@clipboard_insert_text(data);
|
||||
break;
|
||||
case CLIP_TYPE_DATA:
|
||||
// Reserved
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 @clipboard_task()
|
||||
{
|
||||
Ipc.InitQueue(Fs);
|
||||
Clipboard.task = Fs;
|
||||
System.Log(Fs, "Task running at 0x%08x", Fs);
|
||||
while (1) {
|
||||
@clipboard_ipc_queue_process();
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
Clipboard.Init = &@clipboard_init;
|
||||
Clipboard.Insert = &@clipboard_insert;
|
||||
Clipboard.Length = &@clipboard_length;
|
||||
Clipboard.Task = &@clipboard_task;
|
||||
|
||||
"clipboard ";
|
49
System/Libraries/Display.HC
Normal file
49
System/Libraries/Display.HC
Normal file
|
@ -0,0 +1,49 @@
|
|||
Silent(ON);
|
||||
|
||||
#define FB_NONE 0x00
|
||||
#define FB_VMSVGA 0x01
|
||||
|
||||
I64 @display_init(I64 width, I64 height, I64 bpp, I64 driver)
|
||||
{
|
||||
I64 err;
|
||||
Display.width = width;
|
||||
Display.height = height;
|
||||
Display.bpp = bpp;
|
||||
Display.driver = driver;
|
||||
Display.fb = NULL;
|
||||
switch (Display.driver) {
|
||||
case FB_VMSVGA:
|
||||
err = VMSVGA.Init(Display.width, Display.height, Display.bpp);
|
||||
if (err)
|
||||
return err;
|
||||
Display.fb = VMSVGA.FrameBuffer();
|
||||
Display.Update = &@vmsvga_display_update;
|
||||
break;
|
||||
default:
|
||||
//"Unsupported display driver\n";
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
text.cols = Display.width / 8;
|
||||
text.rows = Display.height / 16;
|
||||
text.raw_col = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
I64 @display_get_width() { return Display.width; }
|
||||
|
||||
I64 @display_get_height() { return Display.height; }
|
||||
|
||||
I64 @display_get_bpp() { return Display.bpp; }
|
||||
|
||||
I64 @display_get_driver() { return Display.driver; }
|
||||
|
||||
Display.Init = &@display_init;
|
||||
Display.Width = &@display_get_width;
|
||||
Display.Height = &@display_get_height;
|
||||
Display.Bpp = &@display_get_bpp;
|
||||
Display.Driver = &@display_get_driver;
|
||||
|
||||
Silent(OFF);
|
||||
|
||||
"display ";
|
234
System/Libraries/FileSystem.HC
Normal file
234
System/Libraries/FileSystem.HC
Normal file
|
@ -0,0 +1,234 @@
|
|||
#define FS_TYPE_UNSUPPORTED -1
|
||||
#define FS_TYPE_SYSTEM 0
|
||||
#define FS_TYPE_REDSEA 1
|
||||
#define FS_TYPE_9P 2
|
||||
|
||||
#define DE_TYPE_FILE 0
|
||||
#define DE_TYPE_DIR 1
|
||||
|
||||
class @dir_entry
|
||||
{
|
||||
U8 mode;
|
||||
U8 type;
|
||||
U32 atime;
|
||||
U32 mtime;
|
||||
U64 size;
|
||||
U8 name[255];
|
||||
U8 uid[255];
|
||||
U8 gid[255];
|
||||
@dir_entry* next;
|
||||
};
|
||||
|
||||
extern Bool @plan9fs_file_find(U8* path);
|
||||
extern @dir_entry* @plan9fs_get_files(U8* path);
|
||||
extern U8* @plan9fs_read_file(U8* path, I64* size);
|
||||
extern I64 @plan9fs_write_file(U8* path, U64 buffer, I64 size);
|
||||
|
||||
class @filesystem
|
||||
{
|
||||
I64 root_fs_type;
|
||||
@dir_entry (*GetFiles)(U8* path);
|
||||
U8* (*GetFileExtension)(U8* path);
|
||||
U0 (*Init)();
|
||||
Bool (*PathExists)(U8* path);
|
||||
U8* (*ReadFile)(U8* path, I64* size);
|
||||
I64* (*WriteFile)(U8* path, U64 buffer, I64 size);
|
||||
};
|
||||
|
||||
@filesystem FileSystem;
|
||||
|
||||
U8* @filesystem_resolve_path(U8* path)
|
||||
{
|
||||
U8* abs_path = CAlloc(StrLen(path));
|
||||
I64 argc;
|
||||
I64 i;
|
||||
I64 pos = 0;
|
||||
U8** argv;
|
||||
U8** outv;
|
||||
U8* path_cpy = StrNew(path);
|
||||
argv = String.Split(path_cpy, '/', &argc);
|
||||
outv = CAlloc(sizeof(U64) * argc);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!(!StrCmp(argv[i], ".") || !StrCmp(argv[i], "") || !StrCmp(argv[i], ".."))) {
|
||||
outv[pos] = argv[i];
|
||||
pos++;
|
||||
}
|
||||
if (!StrCmp(argv[i], "..")) {
|
||||
pos = Max(0, pos - 1);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < pos; i++)
|
||||
String.Append(abs_path, "/%s", outv[i]);
|
||||
Free(path_cpy);
|
||||
Free(outv);
|
||||
if (abs_path[StrLen(abs_path) - 1] == '/')
|
||||
abs_path[StrLen(abs_path) - 1] = NULL;
|
||||
if (!StrLen(abs_path))
|
||||
StrCpy(abs_path, "/");
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
I64 @filesystem_get_type(U8* path)
|
||||
{
|
||||
if (!MemCmp(path, "/mnt/redsea/", 12) && StrLen(path) > 12)
|
||||
return FS_TYPE_REDSEA;
|
||||
if (!MemCmp(path, "/sys/", 5))
|
||||
return FS_TYPE_SYSTEM;
|
||||
return FileSystem.root_fs_type;
|
||||
}
|
||||
|
||||
@dir_entry* @filesystem_get_files_9p(U8* path)
|
||||
{
|
||||
return @plan9fs_get_files(path);
|
||||
}
|
||||
|
||||
@dir_entry* @filesystem_get_files_redsea(U8* path)
|
||||
{
|
||||
CDirEntry* de = FilesFind(path);
|
||||
CDirEntry* tmpde = NULL;
|
||||
@dir_entry* entries = NULL;
|
||||
@dir_entry* entry = NULL;
|
||||
@dir_entry* new = NULL;
|
||||
if (de) {
|
||||
entries = CAlloc(sizeof(@dir_entry));
|
||||
entry = entries;
|
||||
tmpde = de;
|
||||
while (tmpde) {
|
||||
new = CAlloc(sizeof(@dir_entry));
|
||||
entry->next = new;
|
||||
|
||||
StrCpy(&new->name, &tmpde->name);
|
||||
StrCpy(&new->uid,
|
||||
"templeos"); // No file ownership in TempleOS
|
||||
StrCpy(&new->gid,
|
||||
"templeos"); // No file ownership in TempleOS
|
||||
new->size = tmpde->size;
|
||||
new->type = T(IsDir(tmpde->full_name), 1, 0);
|
||||
|
||||
entry = new;
|
||||
tmpde = tmpde->next;
|
||||
}
|
||||
DirTreeDel(de);
|
||||
return entries;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@dir_entry* @filesystem_get_files(U8* path)
|
||||
{
|
||||
if (!path)
|
||||
return NULL;
|
||||
U8 buf[512];
|
||||
I64 type = @filesystem_get_type(path);
|
||||
switch (type) {
|
||||
case FS_TYPE_SYSTEM:
|
||||
SysHlt;
|
||||
break;
|
||||
case FS_TYPE_REDSEA:
|
||||
StrPrint(&buf, "%c:%s", ToUpper(path[12]), path + 13);
|
||||
if (buf[StrLen(&buf) - 1] == ':')
|
||||
buf[StrLen(&buf)] = '/';
|
||||
if (buf[StrLen(&buf) - 1] == '/')
|
||||
buf[StrLen(&buf)] = '.';
|
||||
return @filesystem_get_files_redsea(&buf);
|
||||
break;
|
||||
case FS_TYPE_9P:
|
||||
return @filesystem_get_files_9p(path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8* @filesystem_get_file_extension(U8* path)
|
||||
{
|
||||
return (StrLastOcc(path, ".") + 1);
|
||||
}
|
||||
|
||||
Bool @filesystem_path_exists(U8* opath)
|
||||
{
|
||||
if (!opath)
|
||||
return FALSE;
|
||||
U8 buf[512];
|
||||
U8* path = @filesystem_resolve_path(opath);
|
||||
I64 type = @filesystem_get_type(path);
|
||||
switch (type) {
|
||||
case FS_TYPE_SYSTEM:
|
||||
return NULL;
|
||||
SysHlt;
|
||||
break;
|
||||
case FS_TYPE_REDSEA:
|
||||
StrPrint(&buf, "%c:%s", ToUpper(path[12]), path + 13);
|
||||
if (buf[StrLen(&buf) - 1] == ':')
|
||||
buf[StrLen(&buf)] = '/';
|
||||
if (buf[StrLen(&buf) - 1] == '/')
|
||||
buf[StrLen(&buf)] = '.';
|
||||
Free(path);
|
||||
return FileFind(&buf);
|
||||
break;
|
||||
case FS_TYPE_9P:
|
||||
return NULL;
|
||||
Free(path);
|
||||
return @plan9fs_file_find(path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8* @filesystem_read_file(U8* path, I64* size)
|
||||
{
|
||||
if (!path)
|
||||
return FALSE;
|
||||
U8 buf[512];
|
||||
I64 type = @filesystem_get_type(path);
|
||||
switch (type) {
|
||||
case FS_TYPE_SYSTEM:
|
||||
SysHlt;
|
||||
break;
|
||||
case FS_TYPE_REDSEA:
|
||||
StrPrint(&buf, "%c:%s", ToUpper(path[12]), path + 13);
|
||||
return FileRead(&buf, size);
|
||||
break;
|
||||
case FS_TYPE_9P:
|
||||
return @plan9fs_read_file(path, size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 @filesystem_write_file(U8* path, U8* buffer, I64 size)
|
||||
{
|
||||
if (!path || !buffer || !size)
|
||||
return FALSE;
|
||||
U8 buf[512];
|
||||
I64 type = @filesystem_get_type(path);
|
||||
switch (type) {
|
||||
case FS_TYPE_SYSTEM:
|
||||
SysHlt;
|
||||
break;
|
||||
case FS_TYPE_REDSEA:
|
||||
StrPrint(&buf, "%c:%s", ToUpper(path[12]), path + 13);
|
||||
return FileWrite(&buf, buffer, size);
|
||||
break;
|
||||
case FS_TYPE_9P:
|
||||
return @plan9fs_write_file(path, buffer, size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FileSystem.GetFiles = &@filesystem_get_files;
|
||||
FileSystem.GetFileExtension = &@filesystem_get_file_extension;
|
||||
FileSystem.PathExists = &@filesystem_path_exists;
|
||||
FileSystem.ReadFile = &@filesystem_read_file;
|
||||
FileSystem.WriteFile = &@filesystem_write_file;
|
||||
|
||||
"filesystem ";
|
28
System/Libraries/Function.HC
Normal file
28
System/Libraries/Function.HC
Normal file
|
@ -0,0 +1,28 @@
|
|||
U0 @function_insert_call(U32 from, U32 to)
|
||||
{
|
||||
*(from(U8*)) = 0xE8;
|
||||
*((from + 1)(I32*)) = to - from - 5;
|
||||
}
|
||||
|
||||
U0 @function_patch(U32 from, U32 to)
|
||||
{
|
||||
*(from(U8*)) = 0xE9;
|
||||
*((from + 1)(I32*)) = to - from - 5;
|
||||
}
|
||||
|
||||
class @function
|
||||
{
|
||||
U0(*InsertCall)
|
||||
(U32 from, U32 to);
|
||||
U0(*Patch)
|
||||
(U32 from, U32 to);
|
||||
};
|
||||
|
||||
@function Function;
|
||||
Function.InsertCall = &@function_insert_call;
|
||||
Function.Patch = &@function_patch;
|
||||
|
||||
// usage: Function.InsertCall(addr, &func);
|
||||
// usage: Function.Patch(&old_func, &new_func);
|
||||
|
||||
"function ";
|
1428
System/Libraries/Graphics2D.HC
Normal file
1428
System/Libraries/Graphics2D.HC
Normal file
File diff suppressed because it is too large
Load diff
398
System/Libraries/Gui.HC
Normal file
398
System/Libraries/Gui.HC
Normal file
|
@ -0,0 +1,398 @@
|
|||
extern class Widget;
|
||||
extern class Window;
|
||||
|
||||
#define WIN_FLAGS_NULL 0x0
|
||||
#define WIN_FLAGS_NO_REINDEX 0x1 // Wallpaper, taskbar, etc.
|
||||
#define WIN_FLAGS_RESIZABLE 0x2
|
||||
#define WIN_FLAGS_MOVABLE 0x4
|
||||
#define WIN_FLAGS_ICON 0x8
|
||||
#define WIN_FLAGS_TITLE_BAR 0x10
|
||||
#define WIN_FLAGS_MIN_BUTTON 0x20
|
||||
#define WIN_FLAGS_MAX_BUTTON 0x40
|
||||
#define WIN_FLAGS_CLOSE_BUTTON 0x80
|
||||
|
||||
#define WIN_FLAGS_MINIMIZED 0x100
|
||||
#define WIN_FLAGS_MAXIMIZED 0x200
|
||||
#define WIN_FLAGS_HIDDEN 0x400
|
||||
#define WIN_FLAGS_NOHILIGHT 0x800
|
||||
|
||||
#define WIN_FLAGS_SKIP 0x1000
|
||||
#define WIN_FLAGS_NOFILL 0x2000
|
||||
#define WIN_FLAGS_MENU 0x4000
|
||||
|
||||
#define WIN_FLAGS_MAX 0x10000
|
||||
|
||||
#define WIN_SIGNATURE 0x1596e3c1c62c34b929d75cded8c0
|
||||
|
||||
#define WIN_FLAGS_DEFAULT \
|
||||
(WIN_FLAGS_RESIZABLE | WIN_FLAGS_MOVABLE | WIN_FLAGS_ICON | WIN_FLAGS_TITLE_BAR | WIN_FLAGS_MIN_BUTTON | WIN_FLAGS_MAX_BUTTON | WIN_FLAGS_CLOSE_BUTTON)
|
||||
|
||||
class @widget_callbacks
|
||||
{
|
||||
U0 (*change)(Widget* widget);
|
||||
U0 (*clicked)(Widget* widget);
|
||||
U0 (*repaint)(Widget* widget);
|
||||
};
|
||||
|
||||
class @widget_origin
|
||||
{
|
||||
I64 x;
|
||||
I64 y;
|
||||
I64 width;
|
||||
I64 height;
|
||||
I64 mouse_x;
|
||||
I64 mouse_y;
|
||||
};
|
||||
|
||||
class Widget {
|
||||
Bool change;
|
||||
I64 id;
|
||||
I64 type;
|
||||
I64 x;
|
||||
I64 y;
|
||||
I64 width;
|
||||
I64 height;
|
||||
I64 opacity;
|
||||
U64 flags;
|
||||
U8* tag;
|
||||
Widget* echo;
|
||||
Window* parent_win;
|
||||
Context2D* backing_store;
|
||||
Context2D* pointer;
|
||||
@widget_callbacks callback;
|
||||
@widget_origin origin;
|
||||
};
|
||||
|
||||
class @window_widgets_list
|
||||
{
|
||||
@window_widgets_list* prev;
|
||||
@window_widgets_list* next;
|
||||
Widget* widget;
|
||||
};
|
||||
|
||||
class @window_origin
|
||||
{
|
||||
I64 x;
|
||||
I64 y;
|
||||
I64 width;
|
||||
I64 height;
|
||||
I64 mouse_x;
|
||||
I64 mouse_y;
|
||||
};
|
||||
|
||||
class @window_position
|
||||
{
|
||||
I64 x;
|
||||
I64 y;
|
||||
}
|
||||
|
||||
class @window_buttons
|
||||
{
|
||||
Bool minimize;
|
||||
Bool maximize;
|
||||
Bool close;
|
||||
};
|
||||
|
||||
class @window_callbacks
|
||||
{
|
||||
U0 (*minimize)(Window* win);
|
||||
U0 (*maximize)(Window* win);
|
||||
U0 (*mouseat)(Window* win);
|
||||
U0 (*keypress)(Window* win, I64 key);
|
||||
U0 (*repaint)(Window* win);
|
||||
U0 (*close)(Window* win);
|
||||
};
|
||||
|
||||
class @window_mouse
|
||||
{
|
||||
I64 x;
|
||||
I64 y;
|
||||
Bool left;
|
||||
Bool right;
|
||||
};
|
||||
|
||||
class @window_event
|
||||
{ // FIXME: Better name?
|
||||
I64 x;
|
||||
I64 y;
|
||||
Bool left;
|
||||
Bool right;
|
||||
};
|
||||
|
||||
class Window {
|
||||
U64 signature;
|
||||
Bool alpha;
|
||||
Bool refresh;
|
||||
Bool repainting;
|
||||
CTask* client;
|
||||
I64 x;
|
||||
I64 y;
|
||||
I64 width;
|
||||
I64 height;
|
||||
I64 opacity;
|
||||
U64 flags;
|
||||
U8 title[512];
|
||||
I64 title_bar_x;
|
||||
I64 title_bar_width;
|
||||
I64 min_width;
|
||||
I64 min_height;
|
||||
Context2D* icon;
|
||||
Context2D* backing_store;
|
||||
Context2D* pointer;
|
||||
Context2D* render_ctx;
|
||||
Context2D* resize_ctx;
|
||||
Widget* mouse_down_widget;
|
||||
Widget* focused_widget;
|
||||
Widget* hovered_widget;
|
||||
@window_buttons button;
|
||||
@window_callbacks callback;
|
||||
@window_origin origin;
|
||||
@window_mouse mouse;
|
||||
@window_event left_btn_down; // FIXME: put these in a Window.event.xxx class?
|
||||
@window_event left_btn_up;
|
||||
@window_event right_btn_down;
|
||||
@window_event right_btn_up;
|
||||
@window_widgets_list* widget;
|
||||
};
|
||||
|
||||
class @gui_widget
|
||||
{
|
||||
Bool (*IsHovered)(Window* win, Widget* widget);
|
||||
U0 (*SetCallback)(Widget* widget, U8* name, U64 callback);
|
||||
U0 (*SetEcho)(Widget* widget, Widget* echo);
|
||||
U0 (*SetFont)(Widget* widget, U8* font_name);
|
||||
U0 (*SetMousePointer)(Widget* widget, Context2D* pointer);
|
||||
U0 (*ClearMousePointer)(Widget* widget);
|
||||
U0 (*SetOpacity)(Widget* widget, I64 opacity);
|
||||
U0 (*SetText)(Widget* widget, U8* text);
|
||||
};
|
||||
|
||||
class @gui_window
|
||||
{
|
||||
U0 (*Center)(Window* win, Bool horz = TRUE, Bool vert = TRUE);
|
||||
U0 (*DisableAlphaChannel)(Window* win);
|
||||
U0 (*EnableAlphaChannel)(Window* win);
|
||||
U0 (*Hide)(Window* win);
|
||||
Bool (*IsHovered)(Window* win);
|
||||
Bool (*IsVisible)(Window* win);
|
||||
U0 (*SetCallback)(Window* win, U8* name, U64 callback);
|
||||
U0 (*SetFocus)(Window* win);
|
||||
U0 (*SetIcon)(Window* win, Context2D* icon);
|
||||
U0 (*SetMousePointer)(Window* win, Context2D* pointer);
|
||||
U0 (*ClearMousePointer)(Window* win);
|
||||
U0 (*SetOpacity)(Window* win, I64 opacity);
|
||||
U0 (*SetTitle)(Window* win, U8* text);
|
||||
U0 (*SetPosition)(Window* win, I64 x, I64 y);
|
||||
U0 (*SetZIndex)(Window* win, I64 index);
|
||||
U0 (*Show)(Window* win);
|
||||
U0 (*Refresh)(Window* win);
|
||||
};
|
||||
|
||||
class @gui
|
||||
{
|
||||
@gui_widget Widget;
|
||||
@gui_window Window;
|
||||
U0 (*App)();
|
||||
Widget* (*InitWidget)(Widget* widget, Window* win, I64 type, I64 x, I64 y,
|
||||
I64 width, I64 height);
|
||||
Widget* (*CreateWidget)(Window* win, I64 type, I64 x, I64 y, I64 width,
|
||||
I64 height);
|
||||
};
|
||||
|
||||
@gui Gui;
|
||||
|
||||
I64 @gui_app_header_size;
|
||||
U8* @gui_app_header_data = FileRead("M:/Include/Gui.HC", &@gui_app_header_size);
|
||||
|
||||
U0 @gui_app()
|
||||
{
|
||||
CDoc* @gui_app_header_doc = DocNew;
|
||||
DocLoad(@gui_app_header_doc, @gui_app_header_data, @gui_app_header_size);
|
||||
ExeDoc(@gui_app_header_doc);
|
||||
}
|
||||
|
||||
Bool @gui_window_flag_is_set(Window* win, U64 flag)
|
||||
{
|
||||
if (!win)
|
||||
return FALSE;
|
||||
if (win->flags & flag == flag)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool @gui_window_is_hovered(Window* win)
|
||||
{
|
||||
if (Mouse.x > win->x && Mouse.x < win->x + win->width && Mouse.y > win->y && Mouse.y < win->y + win->height)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool @gui_window_is_visible(Window* win)
|
||||
{
|
||||
if (!win)
|
||||
return NULL;
|
||||
return !@gui_window_flag_is_set(win, WIN_FLAGS_HIDDEN);
|
||||
}
|
||||
|
||||
U0 @gui_widget_destroy(Widget* widget)
|
||||
{
|
||||
Window* win = widget->parent_win;
|
||||
@window_widgets_list* widgets = win->widget;
|
||||
@window_widgets_list* prev;
|
||||
@window_widgets_list* next;
|
||||
while (widgets) {
|
||||
if (widgets->widget == widget) {
|
||||
prev = widgets->prev;
|
||||
next = widgets->next;
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
// FIXME: Free widget and child data
|
||||
widget->type = NULL;
|
||||
}
|
||||
widgets = widgets->next;
|
||||
}
|
||||
}
|
||||
|
||||
U0 @gui_widget_repaint(Window* win, Widget* widget, I64 type) { }
|
||||
|
||||
U0 @gui_window_repaint(Window* win, I64 type)
|
||||
{
|
||||
@system_log(Fs, "Repainting window 0x%08x [%s]", win, win->title);
|
||||
}
|
||||
|
||||
U0 @gui_window_center(Window* win, Bool horz = TRUE, Bool vert = TRUE)
|
||||
{
|
||||
if (!win)
|
||||
return;
|
||||
I64 x = win->x;
|
||||
I64 y = win->y;
|
||||
if (horz)
|
||||
x = (Display.Width() / 2) - (win->width / 2);
|
||||
if (vert)
|
||||
y = (Display.Height() / 2) - (win->height / 2);
|
||||
win->x = x;
|
||||
win->y = y;
|
||||
}
|
||||
|
||||
U0 @gui_window_set_position(Window* win, I64 x, I64 y)
|
||||
{
|
||||
if (!win)
|
||||
return;
|
||||
win->x = x;
|
||||
win->y = y;
|
||||
}
|
||||
|
||||
U0 @gui_window_set_icon(Window* win, Context2D* icon)
|
||||
{
|
||||
if (!win || !icon)
|
||||
return;
|
||||
Bool refresh = FALSE;
|
||||
if (win->icon != icon)
|
||||
refresh = TRUE;
|
||||
win->icon = icon;
|
||||
if (refresh)
|
||||
Gui.Window.Refresh(win);
|
||||
}
|
||||
|
||||
U0 @gui_window_set_mouse_pointer(Window* win, Context2D* pointer)
|
||||
{
|
||||
if (!win)
|
||||
return;
|
||||
win->pointer = pointer;
|
||||
}
|
||||
|
||||
U0 @gui_window_clear_mouse_pointer(Window* win)
|
||||
{
|
||||
if (!win)
|
||||
return;
|
||||
win->pointer = NULL;
|
||||
}
|
||||
|
||||
U0 @gui_window_set_opacity(Window* win, I64 opacity)
|
||||
{
|
||||
if (!win)
|
||||
return;
|
||||
Bool refresh = FALSE;
|
||||
if (win->opacity != opacity)
|
||||
refresh = TRUE;
|
||||
win->opacity = ClampI64(opacity, 0, 255);
|
||||
if (refresh)
|
||||
Gui.Window.Refresh(win);
|
||||
}
|
||||
|
||||
U0 @gui_window_set_title(Window* win, U8* text)
|
||||
{
|
||||
if (!win || !text)
|
||||
return;
|
||||
if (!StrLen(text))
|
||||
return;
|
||||
if (StrLen(text) > 511) {
|
||||
MemCpy(&win->title, text, 512);
|
||||
win->title[511] = NULL;
|
||||
return;
|
||||
}
|
||||
StrCpy(&win->title, text);
|
||||
Gui.Window.Refresh(win);
|
||||
}
|
||||
|
||||
U0 @gui_window_callback_close(Window* win) { }
|
||||
|
||||
U0 @gui_window_callback_maximize(Window* win)
|
||||
{
|
||||
win->flags |= WIN_FLAGS_MAXIMIZED;
|
||||
}
|
||||
|
||||
U0 @gui_window_callback_minimize(Window* win)
|
||||
{
|
||||
win->flags |= WIN_FLAGS_MINIMIZED;
|
||||
}
|
||||
|
||||
U0 @gui_window_disable_alpha_channel(Window* win) { win->alpha = FALSE; }
|
||||
|
||||
U0 @gui_window_enable_alpha_channel(Window* win) { win->alpha = TRUE; }
|
||||
|
||||
U0 @gui_window_hide(Window* win) { win->flags |= WIN_FLAGS_HIDDEN; }
|
||||
|
||||
U0 @gui_window_show(Window* win)
|
||||
{
|
||||
win->flags &= ~WIN_FLAGS_HIDDEN;
|
||||
win->flags &= ~WIN_FLAGS_MINIMIZED;
|
||||
}
|
||||
|
||||
U0 @gui_window_set_callback(Window* win, U8* name, U64 callback)
|
||||
{
|
||||
if (!win || !name || !callback)
|
||||
return;
|
||||
if (!StrCmp(name, "minimize"))
|
||||
win->callback.minimize = callback;
|
||||
if (!StrCmp(name, "maximize"))
|
||||
win->callback.maximize = callback;
|
||||
if (!StrCmp(name, "mouseat"))
|
||||
win->callback.mouseat = callback;
|
||||
if (!StrCmp(name, "keypress"))
|
||||
win->callback.keypress = callback;
|
||||
if (!StrCmp(name, "repaint"))
|
||||
win->callback.repaint = callback;
|
||||
if (!StrCmp(name, "close"))
|
||||
win->callback.close = callback;
|
||||
}
|
||||
|
||||
Gui.App = &@gui_app;
|
||||
Gui.Window.Center = &@gui_window_center;
|
||||
Gui.Window.DisableAlphaChannel = &@gui_window_disable_alpha_channel;
|
||||
Gui.Window.EnableAlphaChannel = &@gui_window_enable_alpha_channel;
|
||||
Gui.Window.Hide = &@gui_window_hide;
|
||||
Gui.Window.IsHovered = &@gui_window_is_hovered;
|
||||
Gui.Window.IsVisible = &@gui_window_is_visible;
|
||||
Gui.Window.SetCallback = &@gui_window_set_callback;
|
||||
Gui.Window.SetIcon = &@gui_window_set_icon;
|
||||
Gui.Window.SetMousePointer = &@gui_window_set_mouse_pointer;
|
||||
Gui.Window.ClearMousePointer = &@gui_window_clear_mouse_pointer;
|
||||
Gui.Window.SetOpacity = &@gui_window_set_opacity;
|
||||
Gui.Window.SetTitle = &@gui_window_set_title;
|
||||
Gui.Window.SetPosition = &@gui_window_set_position;
|
||||
Gui.Window.Show = &@gui_window_show;
|
||||
|
||||
"gui ";
|
628
System/Libraries/Http.HC
Normal file
628
System/Libraries/Http.HC
Normal file
|
@ -0,0 +1,628 @@
|
|||
#define HTTP_TMP_DIRECTORY "B:/Tmp"
|
||||
#define HTTP_CACHE_DIRECTORY "B:/Tmp/Cache"
|
||||
#define HTTP_FETCH_BUFFER_SIZE 1024 << 15
|
||||
|
||||
#define SEDECIM_USER_AGENT_STRING "Mozilla/5.0 (compatible; Sedecim/1.0; TempleOS) (KHTML, like Gecko)"
|
||||
|
||||
class @http_buffer
|
||||
{
|
||||
I64 length;
|
||||
U8* data;
|
||||
};
|
||||
|
||||
class @http_status
|
||||
{
|
||||
U8* protocol;
|
||||
I64 code;
|
||||
U8* text;
|
||||
};
|
||||
|
||||
class @http_response
|
||||
{
|
||||
I64 state;
|
||||
TlsSocket* s;
|
||||
@http_status status;
|
||||
JsonObject* headers;
|
||||
@http_buffer body;
|
||||
Bool headers_parsed;
|
||||
};
|
||||
|
||||
class @http_url
|
||||
{
|
||||
U8* scheme;
|
||||
U8* host;
|
||||
I64 port;
|
||||
U8* path;
|
||||
U8* query;
|
||||
U8* fragment;
|
||||
};
|
||||
|
||||
class @http_request
|
||||
{
|
||||
@http_url* url;
|
||||
U8* buf;
|
||||
U8* data;
|
||||
I64 type;
|
||||
JsonObject* headers;
|
||||
@http_response* response;
|
||||
};
|
||||
|
||||
#define HttpResponse @http_response
|
||||
#define HttpUrl @http_url
|
||||
|
||||
#define HTTP_FETCH_BUFFER_SIZE 16777216
|
||||
|
||||
#define HTTP_PARSE_SCHEME 0
|
||||
#define HTTP_PARSE_SCHEME_FS 1
|
||||
#define HTTP_PARSE_HOST 2
|
||||
#define HTTP_PARSE_PORT 3
|
||||
#define HTTP_PARSE_PATH 4
|
||||
#define HTTP_PARSE_QUERY 5
|
||||
#define HTTP_PARSE_FRAGMENT 6
|
||||
|
||||
#define HTTP_MIN_REQUEST_BUFFER_SIZE 16384
|
||||
#define HTTP_PARSE_URL_FIFO_SIZE 1024
|
||||
|
||||
#define HTTP_REQ_GET 0
|
||||
#define HTTP_REQ_HEAD 1
|
||||
#define HTTP_REQ_POST 2
|
||||
#define HTTP_REQ_PUT 3
|
||||
|
||||
#define HTTP_STATE_UNSENT 0
|
||||
#define HTTP_STATE_OPENED 1
|
||||
#define HTTP_STATE_HEADERS_RECEIVED 2
|
||||
#define HTTP_STATE_LOADING 3
|
||||
#define HTTP_STATE_DONE 4
|
||||
|
||||
U8* @http_string_from_fifo(CFifoU8* f)
|
||||
{
|
||||
U8 ch;
|
||||
I64 i = 0;
|
||||
U8* str = CAlloc(FifoU8Cnt(f) + 1, erythros_mem_task);
|
||||
while (FifoU8Cnt(f)) {
|
||||
FifoU8Rem(f, &ch);
|
||||
str[i] = ch;
|
||||
i++;
|
||||
}
|
||||
FifoU8Flush(f);
|
||||
return str;
|
||||
}
|
||||
|
||||
U0 @http_free_url(@http_url* url)
|
||||
{
|
||||
if (!url)
|
||||
return;
|
||||
if (url->scheme)
|
||||
Free(url->scheme);
|
||||
if (url->host)
|
||||
Free(url->host);
|
||||
if (url->path)
|
||||
Free(url->path);
|
||||
if (url->query)
|
||||
Free(url->query);
|
||||
if (url->fragment)
|
||||
Free(url->fragment);
|
||||
Free(url);
|
||||
}
|
||||
|
||||
U0 @http_free_response(@http_response* resp)
|
||||
{
|
||||
if (!resp)
|
||||
return;
|
||||
// FIXME: Free response headers JSON object
|
||||
Free(resp);
|
||||
}
|
||||
|
||||
@http_url* @http_parse_url(U8* str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
U8* buf = NULL;
|
||||
U8 hex[3];
|
||||
I64 i = 0;
|
||||
I64 state = HTTP_PARSE_SCHEME;
|
||||
CFifoU8* consume_fifo = FifoU8New(HTTP_PARSE_URL_FIFO_SIZE, erythros_mem_task);
|
||||
@http_url* url = CAlloc(sizeof(@http_url), erythros_mem_task);
|
||||
while (1) {
|
||||
switch (str[i]) {
|
||||
case 0:
|
||||
switch (state) {
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
url->path = StrNew("/", erythros_mem_task);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_PORT:
|
||||
buf = @http_string_from_fifo(consume_fifo);
|
||||
url->port = Str2I64(buf);
|
||||
Free(buf);
|
||||
url->path = StrNew("/", erythros_mem_task);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_QUERY:
|
||||
url->query = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_FRAGMENT:
|
||||
url->fragment = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
default:
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_FRAGMENT;
|
||||
break;
|
||||
case HTTP_PARSE_QUERY:
|
||||
url->query = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_FRAGMENT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_QUERY;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_SCHEME:
|
||||
state = HTTP_PARSE_SCHEME_FS;
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
case HTTP_PARSE_SCHEME_FS:
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
url->scheme = @http_string_from_fifo(consume_fifo);
|
||||
if (!StrCmp(url->scheme, "http://"))
|
||||
url->port = 80;
|
||||
if (!StrCmp(url->scheme, "https://"))
|
||||
url->port = 443;
|
||||
state = HTTP_PARSE_HOST;
|
||||
break;
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_PATH;
|
||||
break;
|
||||
case HTTP_PARSE_PORT:
|
||||
buf = @http_string_from_fifo(consume_fifo);
|
||||
url->port = Str2I64(buf);
|
||||
Free(buf);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_PATH;
|
||||
break;
|
||||
case HTTP_PARSE_PATH:
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_SCHEME:
|
||||
case HTTP_PARSE_PATH:
|
||||
case HTTP_PARSE_QUERY:
|
||||
case HTTP_PARSE_FRAGMENT:
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
state = HTTP_PARSE_PORT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
keep_consuming_url_chars:
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
case HTTP_PARSE_QUERY:
|
||||
switch (str[i]) {
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
case '?':
|
||||
case '&':
|
||||
case '/':
|
||||
case '=':
|
||||
// !'()*-._~
|
||||
case '!':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '-':
|
||||
case '.':
|
||||
case '_':
|
||||
case '~':
|
||||
case '%':
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
break;
|
||||
default:
|
||||
FifoU8Ins(consume_fifo, '%');
|
||||
StrPrint(hex, "%02X", str[i]);
|
||||
FifoU8Ins(consume_fifo, hex[0]);
|
||||
FifoU8Ins(consume_fifo, hex[1]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
done_parsing_url:
|
||||
FifoU8Flush(consume_fifo);
|
||||
FifoU8Del(consume_fifo);
|
||||
return url;
|
||||
}
|
||||
|
||||
U0 @http_parse_response_headers(@http_response* resp, U8* buffer, I64 length)
|
||||
{
|
||||
if (!resp || !buffer || !length)
|
||||
return;
|
||||
U64 response_data_ptr = StrFind("\r\n\r\n", buffer);
|
||||
if (!response_data_ptr)
|
||||
return;
|
||||
resp->body.data = response_data_ptr + 4;
|
||||
resp->body.data[-4] = NULL;
|
||||
JsonObject* headers = Json.CreateObject(erythros_mem_task);
|
||||
U8** lines = NULL;
|
||||
I64 lines_count = 0;
|
||||
I64 i;
|
||||
I64 j;
|
||||
U8* key_ptr = NULL;
|
||||
U8* value_ptr = NULL;
|
||||
lines = String.Split(buffer, '\n', &lines_count);
|
||||
|
||||
U8* resp_protocol = lines[0];
|
||||
U8* resp_status_code = StrFind(" ", resp_protocol) + 1;
|
||||
U8* resp_text = StrFind(" ", resp_status_code + 1);
|
||||
(*StrFind(" ", resp_protocol)) = NULL;
|
||||
(*StrFind(" ", resp_status_code)) = NULL;
|
||||
|
||||
resp->status.protocol = StrNew(resp_protocol, erythros_mem_task);
|
||||
resp->status.code = Str2I64(resp_status_code);
|
||||
resp->status.text = StrNew(resp_text, erythros_mem_task);
|
||||
|
||||
for (i = 1; i < lines_count; i++) {
|
||||
for (j = 0; j < StrLen(lines[i]); j++) {
|
||||
if (lines[i][j] == ':' && lines[i][j + 1] == ' ') {
|
||||
lines[i][j] = NULL;
|
||||
key_ptr = lines[i];
|
||||
value_ptr = lines[i] + j + 2;
|
||||
(*StrFind("\r", value_ptr)) = NULL;
|
||||
headers->set(key_ptr, value_ptr, JSON_STRING);
|
||||
goto @http_next_header_line;
|
||||
}
|
||||
}
|
||||
@http_next_header_line:
|
||||
}
|
||||
resp->headers = headers;
|
||||
resp->headers_parsed = TRUE;
|
||||
}
|
||||
|
||||
Bool @http_detect_response_headers(U8* buf, I64 len)
|
||||
{
|
||||
if (len < 4)
|
||||
return FALSE;
|
||||
I64 i;
|
||||
for (i = 0; i < len - 4; i++) {
|
||||
if (!MemCmp(buf + i, "\r\n\r\n", 4))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 @http_req(@http_request* req)
|
||||
{
|
||||
if (!req)
|
||||
return NULL;
|
||||
if (!req->url || !req->buf || !req->response)
|
||||
return NULL;
|
||||
if (!req->url->scheme || !req->url->host || !req->url->path)
|
||||
return NULL;
|
||||
if (req->type == HTTP_REQ_POST && !req->data)
|
||||
return NULL;
|
||||
if (req->type == HTTP_REQ_PUT && !req->data)
|
||||
return NULL;
|
||||
|
||||
@http_response* resp = req->response;
|
||||
|
||||
U8* buf = NULL;
|
||||
U8* headers_buf = "";
|
||||
I64 cnt = 1;
|
||||
I64 len = NULL;
|
||||
|
||||
buf = CAlloc(HTTP_MIN_REQUEST_BUFFER_SIZE, erythros_mem_task);
|
||||
if (req->headers) {
|
||||
headers_buf = CAlloc(HTTP_MIN_REQUEST_BUFFER_SIZE, erythros_mem_task);
|
||||
JsonKey* key = req->headers->keys;
|
||||
while (key) {
|
||||
StrPrint(headers_buf + StrLen(headers_buf), "%s: %s\r\n", key->name, key->value);
|
||||
key = key->next;
|
||||
}
|
||||
}
|
||||
|
||||
switch (req->type) {
|
||||
case HTTP_REQ_GET:
|
||||
StrPrint(buf,
|
||||
"GET %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf);
|
||||
break;
|
||||
case HTTP_REQ_HEAD:
|
||||
StrPrint(buf,
|
||||
"HEAD %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf);
|
||||
break;
|
||||
case HTTP_REQ_POST:
|
||||
StrPrint(buf,
|
||||
"POST %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf,
|
||||
StrLen(req->data));
|
||||
StrPrint(buf + StrLen(buf), req->data);
|
||||
break;
|
||||
case HTTP_REQ_PUT:
|
||||
StrPrint(buf,
|
||||
"PUT %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf,
|
||||
StrLen(req->data));
|
||||
StrPrint(buf + StrLen(buf), req->data);
|
||||
break;
|
||||
}
|
||||
|
||||
TlsSocket* s = NULL;
|
||||
resp->s = NULL;
|
||||
|
||||
if (!StrCmp(req->url->scheme, "http://")) {
|
||||
s = @tcp_socket_create(req->url->host, req->url->port);
|
||||
resp->s = s;
|
||||
while (s->state != TCP_SOCKET_STATE_ESTABLISHED)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (!StrCmp(req->url->scheme, "https://")) {
|
||||
s = @tls_socket_create(req->url->host, req->url->port);
|
||||
resp->s = s;
|
||||
while (!@tls_established(s->ctx))
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
resp->state = HTTP_STATE_OPENED;
|
||||
s->send(buf, StrLen(buf));
|
||||
while (cnt || s->state != TCP_SOCKET_STATE_CLOSED) {
|
||||
cnt = s->receive(req->buf + len, 1024);
|
||||
len += cnt;
|
||||
switch (resp->state) {
|
||||
case HTTP_STATE_LOADING:
|
||||
resp->body.length += cnt;
|
||||
break;
|
||||
case HTTP_STATE_HEADERS_RECEIVED:
|
||||
resp->body.length = (req->buf + len) - resp->body.data;
|
||||
resp->state = HTTP_STATE_LOADING;
|
||||
break;
|
||||
case HTTP_STATE_OPENED:
|
||||
if (@http_detect_response_headers(req->buf, len)) {
|
||||
@http_parse_response_headers(resp, req->buf, len);
|
||||
resp->state = HTTP_STATE_HEADERS_RECEIVED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
if (!resp->headers_parsed)
|
||||
@http_parse_response_headers(resp, req->buf, len);
|
||||
resp->state = HTTP_STATE_DONE;
|
||||
req->buf[len] = NULL;
|
||||
Free(buf);
|
||||
if (StrLen(headers_buf) > 0) {
|
||||
Free(headers_buf);
|
||||
}
|
||||
s->close();
|
||||
resp->s = NULL;
|
||||
Free(req);
|
||||
return len;
|
||||
}
|
||||
|
||||
Bool @http_scheme_is_https(@http_url* url)
|
||||
{
|
||||
if (!url || !url->scheme)
|
||||
return FALSE;
|
||||
return !MemCmp(url->scheme, "https", 5);
|
||||
}
|
||||
|
||||
@http_response* @http_get(@http_url* url, U8* buf, U64 return_req = NULL, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), erythros_mem_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), erythros_mem_task);
|
||||
if (return_req)
|
||||
MemCpy(return_req, &req, sizeof(U64));
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_GET;
|
||||
req->headers = headers;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPGetRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_head(@http_url* url, U8* buf, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), erythros_mem_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), erythros_mem_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_HEAD;
|
||||
req->headers = headers;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPHeadRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_post(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), erythros_mem_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), erythros_mem_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_POST;
|
||||
req->headers = headers;
|
||||
req->data = data;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPPostRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_put(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), erythros_mem_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), erythros_mem_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_PUT;
|
||||
req->headers = headers;
|
||||
req->data = data;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPPutRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
class @http
|
||||
{
|
||||
@http_response* (*Get)(@http_url* url, U8* buf, U64* req = NULL, JsonObject* headers = NULL);
|
||||
@http_response* (*Head)(@http_url* url, U8* buf, JsonObject* headers = NULL);
|
||||
@http_response* (*Post)(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL);
|
||||
@http_response* (*Put)(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL);
|
||||
};
|
||||
|
||||
@http Http;
|
||||
|
||||
Http.Get = &@http_get;
|
||||
Http.Head = &@http_head;
|
||||
Http.Post = &@http_post;
|
||||
Http.Put = &@http_put;
|
||||
|
||||
Bool @http_is_resource_cached(U8* src, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8 buf[512];
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
return FileFind(buf);
|
||||
}
|
||||
|
||||
U0 @http_cache_resource(U8* src, U8* data, I64 size, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8 buf[512];
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
FileWrite(buf, data, size);
|
||||
}
|
||||
|
||||
U8* @http_get_cached_resource_filename(U8* src, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8* buf = CAlloc(512, erythros_mem_task);
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
return buf;
|
||||
}
|
||||
|
||||
U0 @http_init_tmp_and_cache_directories()
|
||||
{
|
||||
if (!FileFind(HTTP_TMP_DIRECTORY))
|
||||
DirMk(HTTP_TMP_DIRECTORY);
|
||||
if (!FileFind(HTTP_CACHE_DIRECTORY))
|
||||
DirMk(HTTP_CACHE_DIRECTORY);
|
||||
}
|
||||
|
||||
@http_response* fetch(U8* url_string, U8* fetch_buffer)
|
||||
{
|
||||
if (!url_string || !fetch_buffer)
|
||||
return NULL;
|
||||
HttpUrl* url = @http_parse_url(url_string);
|
||||
if (!url)
|
||||
return NULL;
|
||||
@http_response* resp = Http.Get(url, fetch_buffer);
|
||||
while (resp->state != HTTP_STATE_DONE)
|
||||
Sleep(1);
|
||||
return resp;
|
||||
}
|
||||
|
||||
I64 curl(U8* url_string)
|
||||
{
|
||||
if (!url_string)
|
||||
return 0;
|
||||
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, erythros_mem_task);
|
||||
@http_response* resp = fetch(url_string, fetch_buffer);
|
||||
if (!resp)
|
||||
return 0;
|
||||
if (resp->body.length) {
|
||||
U8* buf = resp->body.data;
|
||||
while (*buf) {
|
||||
if (*buf == '\d')
|
||||
"\d\d";
|
||||
else
|
||||
"%c", *buf;
|
||||
++buf;
|
||||
}
|
||||
"\n";
|
||||
}
|
||||
Free(fetch_buffer);
|
||||
return resp->body.length;
|
||||
}
|
||||
|
||||
I64 download(U8* path, U8* url_string)
|
||||
{
|
||||
if (!path || !url_string)
|
||||
return 0;
|
||||
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, erythros_mem_task);
|
||||
@http_response* resp = fetch(url_string, fetch_buffer);
|
||||
if (!resp)
|
||||
return 0;
|
||||
if (resp->body.length) {
|
||||
FileWrite(path, resp->body.data, resp->body.length);
|
||||
}
|
||||
Free(fetch_buffer);
|
||||
return resp->body.length;
|
||||
}
|
||||
|
||||
"http ";
|
55
System/Libraries/Image.HC
Normal file
55
System/Libraries/Image.HC
Normal file
|
@ -0,0 +1,55 @@
|
|||
class @image
|
||||
{
|
||||
Context2D* (*FileToContext2D)(U8* filepath);
|
||||
Context2D* (*BufferToContext2D)(U8* buffer, I64 size);
|
||||
};
|
||||
|
||||
@image Image;
|
||||
|
||||
Context2D* @image_buffer_to_context2d(U8* buffer, I64 size)
|
||||
{
|
||||
if (!buffer || !size) {
|
||||
return NULL;
|
||||
}
|
||||
I32 x;
|
||||
I32 y;
|
||||
I32 comp;
|
||||
I32 code = @stbi_info_from_memory(buffer, size, &x, &y, &comp);
|
||||
if (code != 1) {
|
||||
return NULL;
|
||||
}
|
||||
U8* pixels = @stbi_load_from_memory(buffer, size, &x, &y, &comp, 4);
|
||||
if (!pixels) {
|
||||
return NULL;
|
||||
}
|
||||
Context2D* ctx = CAlloc(sizeof(Context2D));
|
||||
ctx->width = x;
|
||||
ctx->height = y;
|
||||
ctx->bpp = 32;
|
||||
ctx->fb = pixels;
|
||||
I64 i;
|
||||
for (i = 0; i < x * y; i++) {
|
||||
ctx->fb(U32*)[i] = @image_pixel_flip_rgb_bgr(ctx->fb(U32*)[i]);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
Context2D* @image_file_to_context2d(U8* filepath)
|
||||
{
|
||||
if (!FileFind(filepath)) {
|
||||
return NULL;
|
||||
}
|
||||
I64 size = NULL;
|
||||
U8* buffer = FileRead(filepath, &size);
|
||||
if (!buffer || !size) {
|
||||
return NULL;
|
||||
}
|
||||
Context2D* ctx = @image_buffer_to_context2d(buffer, size);
|
||||
Free(buffer);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
Image.FileToContext2D = &@image_file_to_context2d;
|
||||
Image.BufferToContext2D = &@image_buffer_to_context2d;
|
||||
|
||||
"image ";
|
54
System/Libraries/Ipc.HC
Normal file
54
System/Libraries/Ipc.HC
Normal file
|
@ -0,0 +1,54 @@
|
|||
#define ipc user_data.u32[0]
|
||||
#define IPC_QUEUE_SIZE 1024
|
||||
#define IPC_ENQUEUE_LIMIT 16
|
||||
|
||||
class IpcMessage {
|
||||
CTask* client;
|
||||
I64 type;
|
||||
U64 payload;
|
||||
I64 i64;
|
||||
};
|
||||
|
||||
class @ipc
|
||||
{
|
||||
U0 (*InitQueue)(CTask* task);
|
||||
IpcMessage* (*MsgRecv)();
|
||||
U0 (*MsgSend)(CTask* task, IpcMessage* msg);
|
||||
};
|
||||
|
||||
U0 @ipc_queue_init(CTask* task)
|
||||
{ // Initialize a task's IpcMessage Queue
|
||||
MemSetU32(task->pad, 0, 1);
|
||||
if (!task->ipc) {
|
||||
task->ipc = FifoI64New(IPC_QUEUE_SIZE, task->code_heap);
|
||||
}
|
||||
}
|
||||
|
||||
IpcMessage* @ipc_msg_recv()
|
||||
{ // Receive a IpcMessage from current task's
|
||||
// message queue.
|
||||
U64 msg_ptr;
|
||||
if (!FifoI64Cnt(Fs->ipc))
|
||||
return FALSE;
|
||||
FifoI64Rem(Fs->ipc, &msg_ptr);
|
||||
return msg_ptr;
|
||||
}
|
||||
|
||||
U0 @ipc_msg_send(
|
||||
CTask* task,
|
||||
IpcMessage* msg)
|
||||
{ // Send a IpcMessage to a task (client or server)
|
||||
if (FifoI64Cnt(task->ipc) > IPC_ENQUEUE_LIMIT) {
|
||||
Free(msg);
|
||||
return;
|
||||
}
|
||||
FifoI64Ins(task->ipc, msg);
|
||||
}
|
||||
|
||||
@ipc Ipc;
|
||||
|
||||
Ipc.InitQueue = &@ipc_queue_init;
|
||||
Ipc.MsgRecv = &@ipc_msg_recv;
|
||||
Ipc.MsgSend = &@ipc_msg_send;
|
||||
|
||||
"ipc ";
|
1550
System/Libraries/Json.HC
Normal file
1550
System/Libraries/Json.HC
Normal file
File diff suppressed because it is too large
Load diff
104
System/Libraries/RawText.HC
Normal file
104
System/Libraries/RawText.HC
Normal file
|
@ -0,0 +1,104 @@
|
|||
I64 @rawtext_output_port = NULL;
|
||||
|
||||
U0 @rawtext_detect_qemu()
|
||||
{
|
||||
CRAXRBCRCXRDX res;
|
||||
CPUId(0x40000000, &res);
|
||||
if (res.rbx == 'KVMK')
|
||||
@rawtext_output_port = 0xe9;
|
||||
}
|
||||
|
||||
U0 @rawtext_detect_vbox()
|
||||
{
|
||||
I64 res = PCIClassFind(0x088000, 0);
|
||||
if (res >= 0)
|
||||
@rawtext_output_port = 0x504;
|
||||
}
|
||||
|
||||
U0 @dbg_put_char(I64 ch)
|
||||
{
|
||||
OutU8(@rawtext_output_port, ch);
|
||||
if (!System.text_mode)
|
||||
return;
|
||||
Context2D* fb = Graphics2D.FrameBufferContext2D();
|
||||
text.raw_flags &= ~RWF_SHOW_DOLLAR;
|
||||
if (ch > '~' && ch != 219)
|
||||
ch = ' ';
|
||||
I64 row, col;
|
||||
if (!(text.raw_flags & RWF_SHOW_DOLLAR)) {
|
||||
if (ch == '$$') {
|
||||
if (text.raw_flags & RWF_IN_DOLLAR) {
|
||||
text.raw_flags &= ~RWF_IN_DOLLAR;
|
||||
if (!(text.raw_flags & RWF_LAST_DOLLAR)) {
|
||||
text.raw_flags &= ~RWF_LAST_DOLLAR;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
text.raw_flags |= RWF_IN_DOLLAR | RWF_LAST_DOLLAR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
text.raw_flags &= ~RWF_LAST_DOLLAR;
|
||||
if (text.raw_flags & RWF_IN_DOLLAR)
|
||||
return;
|
||||
}
|
||||
if (ch == '\t') {
|
||||
@dbg_put_char(CH_SPACE);
|
||||
while (text.raw_col & 7)
|
||||
@dbg_put_char(CH_SPACE);
|
||||
} else if (ch == CH_BACKSPACE) {
|
||||
text.raw_col--;
|
||||
@dbg_put_char(CH_SPACE);
|
||||
text.raw_col--;
|
||||
} else if (ch == '\n') {
|
||||
@dbg_put_char(CH_SPACE);
|
||||
while (text.raw_col % text.cols)
|
||||
@dbg_put_char(CH_SPACE);
|
||||
} else if (Bt(char_bmp_displayable, ch)) {
|
||||
row = text.raw_col / text.cols % text.rows;
|
||||
col = text.raw_col % text.cols;
|
||||
if (text.raw_flags & RWF_SCROLL && text.raw_col && !row && !col) {
|
||||
CopyRect2D(fb, 0, -16, fb);
|
||||
Rect2D(fb, 0, Display.Height() - 16, Display.Width(), 16, 0x0);
|
||||
text.raw_col -= text.cols;
|
||||
row = text.rows - 1;
|
||||
}
|
||||
ConsolePrint2D(fb, col * 8, row * 16, , , "%c", ch);
|
||||
text.raw_col++;
|
||||
}
|
||||
}
|
||||
|
||||
Bool @kd_raw_putkey(I64 ch, I64)
|
||||
{
|
||||
if (IsRaw) {
|
||||
@dbg_put_char(ch);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool @kd_raw_puts(U8* st)
|
||||
{
|
||||
I64 ch;
|
||||
if (IsRaw) {
|
||||
while (ch = *st++)
|
||||
@dbg_put_char(ch);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 @rawdr_dummy(CTask*) { }
|
||||
|
||||
CKeyDevEntry* tmp_kde = keydev.put_key_head;
|
||||
while (tmp_kde->put_s != &KDRawPutS)
|
||||
tmp_kde = tmp_kde->next;
|
||||
tmp_kde->put_key = &@kd_raw_putkey;
|
||||
tmp_kde->put_s = &@kd_raw_puts;
|
||||
|
||||
Function.Patch(&RawDr, &@rawdr_dummy);
|
||||
|
||||
@rawtext_detect_qemu;
|
||||
@rawtext_detect_vbox;
|
||||
|
||||
"rawtext ";
|
46
System/Libraries/Rsa.HC
Normal file
46
System/Libraries/Rsa.HC
Normal file
|
@ -0,0 +1,46 @@
|
|||
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
|
||||
|
||||
I64 @rsa_import(U8* der_bytes, I64 der_len, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = der_bytes;
|
||||
U64 reg RSI rsi = der_len;
|
||||
U64 reg RDX rdx = key;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, RSA_IMPORT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I64 @rsa_create_signature(U8* sig, I64* siglen, U8* hash, I64 hashlen, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = sig;
|
||||
U64 reg RSI rsi = siglen;
|
||||
U64 reg RDX rdx = hash;
|
||||
U64 reg RCX rcx = hashlen;
|
||||
U64 reg R8 r8 = key;
|
||||
no_warn rdi, rsi, rdx, rcx, r8;
|
||||
asm {
|
||||
MOV RAX, RSA_CREATE_SIGNATURE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I64 @rsa_verify_signature(U8* sig, I64 siglen, U8* hash, I64 hashlen, I32* stat, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = sig;
|
||||
U64 reg RSI rsi = siglen;
|
||||
U64 reg RDX rdx = hash;
|
||||
U64 reg RCX rcx = hashlen;
|
||||
U64 reg R8 r8 = stat;
|
||||
U64 reg R9 r9 = key;
|
||||
no_warn rdi, rsi, rdx, rcx, r8, r9;
|
||||
asm {
|
||||
MOV RAX, RSA_VERIFY_SIGNATURE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
Silent(0);
|
||||
|
||||
"rsa ";
|
8
System/Libraries/Session.HC
Normal file
8
System/Libraries/Session.HC
Normal file
|
@ -0,0 +1,8 @@
|
|||
class @session
|
||||
{
|
||||
U8 home[4096];
|
||||
U8 hostname[256];
|
||||
@user user;
|
||||
};
|
||||
|
||||
"session ";
|
235
System/Libraries/Sha256.HC
Normal file
235
System/Libraries/Sha256.HC
Normal file
|
@ -0,0 +1,235 @@
|
|||
#define CHUNK_SIZE 64
|
||||
#define TOTAL_LEN_LEN 8
|
||||
|
||||
/*
|
||||
* ABOUT bool: this file does not use bool in order to be as pre-C99 compatible
|
||||
* as possible.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are
|
||||
* reproduced here. When useful for clarification, portions of the pseudo-code
|
||||
* are reproduced here too.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize array of round constants:
|
||||
* (first 32 bits of the fractional parts of the cube roots of the first 64
|
||||
* primes 2..311):
|
||||
*/
|
||||
U32 k[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
U32 _h[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
|
||||
|
||||
class buffer_state {
|
||||
U8* p;
|
||||
I32 len;
|
||||
I32 total_len;
|
||||
I32 single_one_delivered; /* bool */
|
||||
I32 total_len_delivered; /* bool */
|
||||
};
|
||||
|
||||
U32 right_rot(U32 value, U32 count)
|
||||
{
|
||||
/*
|
||||
* Defined behaviour in standard C for all count where 0 < count < 32,
|
||||
* which is what we need here.
|
||||
*/
|
||||
return value >> count | value << (32 - count);
|
||||
}
|
||||
|
||||
U0 init_buf_state(buffer_state* state, U8* input, I32 len)
|
||||
{
|
||||
state->p = input;
|
||||
state->len = len;
|
||||
state->total_len = len;
|
||||
state->single_one_delivered = 0;
|
||||
state->total_len_delivered = 0;
|
||||
}
|
||||
|
||||
/* Return value: bool */
|
||||
I32 calc_chunk(U8* chunk, buffer_state* state)
|
||||
{
|
||||
I32 space_in_chunk;
|
||||
|
||||
if (state->total_len_delivered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->len >= CHUNK_SIZE) {
|
||||
MemCpy(chunk, state->p, CHUNK_SIZE);
|
||||
state->p += CHUNK_SIZE;
|
||||
state->len -= CHUNK_SIZE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MemCpy(chunk, state->p, state->len);
|
||||
chunk += state->len;
|
||||
space_in_chunk = CHUNK_SIZE - state->len;
|
||||
state->p += state->len;
|
||||
state->len = 0;
|
||||
|
||||
/* If we are here, space_in_chunk is one at minimum. */
|
||||
if (!state->single_one_delivered) {
|
||||
*chunk++ = 0x80;
|
||||
space_in_chunk -= 1;
|
||||
state->single_one_delivered = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now:
|
||||
* - either there is enough space left for the total length, and we can
|
||||
* conclude,
|
||||
* - or there is too little space left, and we have to pad the rest of this
|
||||
* chunk with zeroes. In the latter case, we will conclude at the next
|
||||
* invokation of this function.
|
||||
*/
|
||||
if (space_in_chunk >= TOTAL_LEN_LEN) {
|
||||
I32 left = space_in_chunk - TOTAL_LEN_LEN;
|
||||
I32 len = state->total_len;
|
||||
I32 i;
|
||||
MemSet(chunk, 0x00, left);
|
||||
chunk += left;
|
||||
|
||||
/* Storing of len * 8 as a big endian 64-bit without overflow. */
|
||||
chunk[7] = (len << 3);
|
||||
len >>= 5;
|
||||
for (i = 6; i >= 0; i--) {
|
||||
chunk[i] = len;
|
||||
len >>= 8;
|
||||
}
|
||||
state->total_len_delivered = 1;
|
||||
} else {
|
||||
MemSet(chunk, 0x00, space_in_chunk);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Limitations:
|
||||
* - Since input is a pointer in RAM, the data to hash should be in RAM, which
|
||||
* could be a problem for large data sizes.
|
||||
* - SHA algorithms theoretically operate on bit strings. However, this
|
||||
* implementation has no support for bit string lengths that are not multiples
|
||||
* of eight, and it really operates on arrays of bytes. In particular, the len
|
||||
* parameter is a number of bytes.
|
||||
*/
|
||||
U0 calc_sha_256(U8* hash, U8* input, I32 len)
|
||||
{
|
||||
/*
|
||||
* Note 1: All integers (expect indexes) are 32-bit U32 integers and addition
|
||||
* is calculated modulo 2^32. Note 2: For each round, there is one round
|
||||
* constant k[i] and one entry in the message schedule array w[i], 0 = i = 63
|
||||
* Note 3: The compression function uses 8 working variables, a through h
|
||||
* Note 4: Big-endian convention is used when expressing the constants in this
|
||||
* pseudocode, and when parsing message block data from bytes to words, for
|
||||
* example, the first word of the input message "abc" after padding is
|
||||
* 0x61626380
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize hash values:
|
||||
* (first 32 bits of the fractional parts of the square roots of the first 8
|
||||
* primes 2..19):
|
||||
*/
|
||||
|
||||
U32 h[8];
|
||||
U32 i, j;
|
||||
MemCpy(h, _h, sizeof(U32) * 8);
|
||||
|
||||
/* 512-bit chunks is what we will operate on. */
|
||||
U8 chunk[64];
|
||||
|
||||
buffer_state state;
|
||||
|
||||
init_buf_state(&state, input, len);
|
||||
|
||||
while (calc_chunk(chunk, &state)) {
|
||||
U32 ah[8];
|
||||
|
||||
U8* p = chunk;
|
||||
|
||||
/* Initialize working variables to current hash value: */
|
||||
for (i = 0; i < 8; i++)
|
||||
ah[i] = h[i];
|
||||
|
||||
/* Compression function main loop: */
|
||||
for (i = 0; i < 4; i++) {
|
||||
/*
|
||||
* The w-array is really w[64], but since we only need
|
||||
* 16 of them at a time, we save stack by calculating
|
||||
* 16 at a time.
|
||||
*
|
||||
* This optimization was not there initially and the
|
||||
* rest of the comments about w[64] are kept in their
|
||||
* initial state.
|
||||
*/
|
||||
|
||||
/*
|
||||
* create a 64-entry message schedule array w[0..63] of 32-bit words
|
||||
* (The initial values in w[0..63] don't matter, so many implementations
|
||||
* zero them here) copy chunk into first 16 words w[0..15] of the message
|
||||
* schedule array
|
||||
*/
|
||||
U32 w[16];
|
||||
|
||||
U32 s0, s1;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i == 0) {
|
||||
w[j] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
|
||||
p += 4;
|
||||
} else {
|
||||
/* Extend the first 16 words into the remaining 48 words w[16..63] of
|
||||
* the message schedule array: */
|
||||
s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3);
|
||||
s1 = right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);
|
||||
w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1;
|
||||
}
|
||||
s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);
|
||||
U32 ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]);
|
||||
U32 temp1 = ah[7] + s1 + ch + k[i << 4 | j] + w[j];
|
||||
s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22);
|
||||
U32 maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]);
|
||||
U32 temp2 = s0 + maj;
|
||||
|
||||
ah[7] = ah[6];
|
||||
ah[6] = ah[5];
|
||||
ah[5] = ah[4];
|
||||
ah[4] = ah[3] + temp1;
|
||||
ah[3] = ah[2];
|
||||
ah[2] = ah[1];
|
||||
ah[1] = ah[0];
|
||||
ah[0] = temp1 + temp2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the compressed chunk to the current hash value: */
|
||||
for (i = 0; i < 8; i++)
|
||||
h[i] += ah[i];
|
||||
}
|
||||
|
||||
/* Produce the final hash value (big-endian): */
|
||||
for (i = 0, j = 0; i < 8; i++) {
|
||||
hash[j++] = (h[i] >> 24);
|
||||
hash[j++] = (h[i] >> 16);
|
||||
hash[j++] = (h[i] >> 8);
|
||||
hash[j++] = h[i];
|
||||
}
|
||||
}
|
||||
|
||||
"sha256 ";
|
52
System/Libraries/Shell.HC
Normal file
52
System/Libraries/Shell.HC
Normal file
|
@ -0,0 +1,52 @@
|
|||
#define SHELL_HISTORY_LIMIT 1025
|
||||
#define SHELL_INPUT_FIFO_SIZE 65536
|
||||
|
||||
class @shell_env_var
|
||||
{
|
||||
@shell_env_var* prev;
|
||||
@shell_env_var* next;
|
||||
U8 key[256];
|
||||
U8 value[1024];
|
||||
};
|
||||
|
||||
class @shell_autocomplete
|
||||
{
|
||||
I64 depth;
|
||||
I64 length[8];
|
||||
U8*** entries;
|
||||
};
|
||||
|
||||
class @shell_history
|
||||
{
|
||||
I64 index;
|
||||
I64 limit;
|
||||
I64 pos;
|
||||
U8** entries;
|
||||
};
|
||||
|
||||
class @shell_readline
|
||||
{
|
||||
@shell_autocomplete autocomplete;
|
||||
@shell_history history;
|
||||
};
|
||||
|
||||
class @shell
|
||||
{
|
||||
CFifoU8* input;
|
||||
CFifoU8* output;
|
||||
CTask* task;
|
||||
Bool break;
|
||||
Bool exit;
|
||||
I64 answer;
|
||||
@shell_env_var* env;
|
||||
@shell_history history;
|
||||
@shell_readline readline;
|
||||
@session* session;
|
||||
U8 cwd[4096];
|
||||
U8 PS1[512];
|
||||
U8 PS2[512];
|
||||
U8 PS3[512];
|
||||
U8 PS4[512];
|
||||
};
|
||||
|
||||
"shell ";
|
155
System/Libraries/Stdio.HC
Normal file
155
System/Libraries/Stdio.HC
Normal file
|
@ -0,0 +1,155 @@
|
|||
class @stdio
|
||||
{
|
||||
U0 (*ReadLine)(@shell* sh, U8* str);
|
||||
U0 (*WriteLine)(@shell* sh, U8* fmt, ...);
|
||||
};
|
||||
|
||||
U0 @stdio_write_line(@shell* sh, U8* fmt, ...)
|
||||
{
|
||||
if (!sh)
|
||||
return;
|
||||
if (!fmt || !sh->output)
|
||||
return;
|
||||
U8* buf;
|
||||
if (argc) {
|
||||
buf = StrPrintJoin(NULL, fmt, argc, argv);
|
||||
} else {
|
||||
buf = StrNew(fmt, erythros_mem_task);
|
||||
}
|
||||
I64 i;
|
||||
for (i = 0; i < StrLen(buf); i++)
|
||||
FifoU8Ins(sh->output, buf[i]);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
I64 @stdio_handle_control_chars(@shell* sh)
|
||||
{
|
||||
if (!FifoU8Cnt(sh->input))
|
||||
return 0;
|
||||
U8 char;
|
||||
FifoU8Rem(sh->input, &char);
|
||||
switch (char) {
|
||||
case '[':
|
||||
if (!FifoU8Cnt(sh->input))
|
||||
return 0;
|
||||
FifoU8Rem(sh->input, &char);
|
||||
switch (char) {
|
||||
case 'A':
|
||||
return SC_CURSOR_UP;
|
||||
break;
|
||||
case 'B':
|
||||
return SC_CURSOR_DOWN;
|
||||
break;
|
||||
case 'D':
|
||||
return SC_CURSOR_LEFT;
|
||||
break;
|
||||
case 'C':
|
||||
return SC_CURSOR_RIGHT;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 @stdio_read_line_history_back(@shell* sh, I64 pos)
|
||||
{
|
||||
if (sh->history.index < 0)
|
||||
sh->history.index = 0;
|
||||
while (pos > 0) {
|
||||
FifoU8Ins(sh->input, '\x8');
|
||||
pos--;
|
||||
}
|
||||
U8* char = sh->history.entries[sh->history.index];
|
||||
while (*char)
|
||||
FifoU8Ins(sh->input, *char ++);
|
||||
if (sh->history.index > -1) {
|
||||
sh->history.index--;
|
||||
}
|
||||
}
|
||||
|
||||
U0 @stdio_read_line_history_fwd(@shell* sh, I64 pos)
|
||||
{
|
||||
if (sh->history.index < sh->history.pos) {
|
||||
sh->history.index++;
|
||||
}
|
||||
if (sh->history.index > sh->history.pos)
|
||||
sh->history.index = sh->history.pos;
|
||||
while (pos > 0) {
|
||||
FifoU8Ins(sh->input, '\x8');
|
||||
pos--;
|
||||
}
|
||||
U8* char = sh->history.entries[sh->history.index];
|
||||
while (*char)
|
||||
FifoU8Ins(sh->input, *char ++);
|
||||
}
|
||||
|
||||
U0 @stdio_read_line(@shell* sh, U8* str)
|
||||
{
|
||||
U8 char = NULL;
|
||||
U8 line[4096];
|
||||
I64 pos = 0;
|
||||
if (!str || !sh)
|
||||
return;
|
||||
sh->history.index = sh->history.pos - 1;
|
||||
while (char != '\x3' && char != '\n') {
|
||||
while (FifoU8Cnt(sh->input)) {
|
||||
FifoU8Rem(sh->input, &char);
|
||||
switch (char) {
|
||||
case 3:
|
||||
@stdio_write_line(sh, "^C");
|
||||
break;
|
||||
case 8:
|
||||
if (pos > 0) {
|
||||
line[StrLen(line) - 1] = NULL;
|
||||
FifoU8Ins(sh->output, '\x8');
|
||||
pos--;
|
||||
} else
|
||||
FifoU8Ins(sh->output, '\x7');
|
||||
break;
|
||||
case 13:
|
||||
break;
|
||||
case 27:
|
||||
switch (@stdio_handle_control_chars(sh)) {
|
||||
case SC_CURSOR_UP:
|
||||
@stdio_read_line_history_back(sh, pos);
|
||||
break;
|
||||
case SC_CURSOR_DOWN:
|
||||
@stdio_read_line_history_fwd(sh, pos);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 32...127:
|
||||
line[pos] = char;
|
||||
FifoU8Ins(sh->output, char);
|
||||
pos++;
|
||||
break;
|
||||
};
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
line[pos] = NULL;
|
||||
switch (char) {
|
||||
case '\x3':
|
||||
StrCpy(str, "");
|
||||
break;
|
||||
case '\n':
|
||||
StrCpy(str, &line);
|
||||
break;
|
||||
};
|
||||
FifoU8Ins(sh->output, '\n');
|
||||
}
|
||||
|
||||
@stdio Stdio;
|
||||
|
||||
Stdio.ReadLine = &@stdio_read_line;
|
||||
Stdio.WriteLine = &@stdio_write_line;
|
||||
|
||||
"stdio ";
|
171
System/Libraries/String.HC
Normal file
171
System/Libraries/String.HC
Normal file
|
@ -0,0 +1,171 @@
|
|||
#define TRIM_BOTH 0
|
||||
#define TRIM_LEFT 1
|
||||
#define TRIM_RIGHT 2
|
||||
|
||||
U0 @string_append(U8* dst, U8* fmt, ...)
|
||||
{
|
||||
U8* buf;
|
||||
if (argc) {
|
||||
buf = StrPrintJoin(NULL, fmt, argc, argv);
|
||||
} else {
|
||||
buf = StrNew(fmt, erythros_mem_task);
|
||||
}
|
||||
U8* src = buf;
|
||||
StrCpy(dst + StrLen(dst), src);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
Bool @string_is_number(U8* s)
|
||||
{
|
||||
while (*s) {
|
||||
switch (*s) {
|
||||
case '-':
|
||||
case '.':
|
||||
case '0' ... '9':
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool @string_begins_with(U8* fragment, U8* str)
|
||||
{
|
||||
if (!fragment || !str)
|
||||
return FALSE;
|
||||
if (StrLen(fragment) > StrLen(str))
|
||||
return FALSE;
|
||||
return !MemCmp(fragment, str, StrLen(fragment));
|
||||
}
|
||||
|
||||
Bool @string_ends_with(U8* fragment, U8* str)
|
||||
{
|
||||
if (!fragment || !str)
|
||||
return FALSE;
|
||||
if (StrLen(fragment) > StrLen(str))
|
||||
return FALSE;
|
||||
return !MemCmp(fragment, str + StrLen(str) - StrLen(fragment), StrLen(fragment));
|
||||
}
|
||||
|
||||
U8* @string_replace(U8* s, U8* oldW, U8* newW)
|
||||
{
|
||||
if (!StrFind(oldW, s)) {
|
||||
return StrNew(s, erythros_mem_task);
|
||||
}
|
||||
U8* result;
|
||||
I64 i, cnt = 0;
|
||||
I64 newWlen = StrLen(newW);
|
||||
I64 oldWlen = StrLen(oldW);
|
||||
for (i = 0; s[i] != NULL; i++) {
|
||||
if (StrFind(oldW, &s[i]) == &s[i]) {
|
||||
cnt++;
|
||||
|
||||
i += oldWlen - 1;
|
||||
}
|
||||
}
|
||||
result = MAlloc(i + cnt * (newWlen - oldWlen) + 1, erythros_mem_task);
|
||||
i = 0;
|
||||
while (*s) {
|
||||
if (StrFind(oldW, s) == s) {
|
||||
StrCpy(&result[i], newW);
|
||||
i += newWlen;
|
||||
s += oldWlen;
|
||||
} else
|
||||
result[i++] = *s++;
|
||||
}
|
||||
result[i] = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
U8** @string_split(U8* s, U8 ch = '\n', I64* cnt)
|
||||
{
|
||||
U8 check_buf[4];
|
||||
StrPrint(check_buf, "%c", ch);
|
||||
if (!StrFind(check_buf, s)) {
|
||||
U8** same_arr = CAlloc(sizeof(U8*) * 1, erythros_mem_task);
|
||||
same_arr[0] = s;
|
||||
*cnt = 1;
|
||||
return same_arr;
|
||||
}
|
||||
U8* p = s;
|
||||
cnt[0] = 0;
|
||||
while (*p) {
|
||||
if (*p == ch)
|
||||
cnt[0]++;
|
||||
p++;
|
||||
}
|
||||
if (!(cnt[0]))
|
||||
return NULL;
|
||||
cnt[0]++;
|
||||
I64 i = -1;
|
||||
U8** arr = CAlloc(sizeof(U8*) * cnt[0], erythros_mem_task);
|
||||
p = s;
|
||||
while (*p) {
|
||||
if (*p == ch || i < 0) {
|
||||
i++;
|
||||
arr[i] = p;
|
||||
if (*p == ch) {
|
||||
arr[i]++;
|
||||
*p = NULL;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
Bool @string_trim_ch(U8 s_ch, U8 trim_ch)
|
||||
{
|
||||
if (!s_ch) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!trim_ch) {
|
||||
return (s_ch == ' ' || s_ch == '\r' || s_ch == '\n' || s_ch == '\t');
|
||||
} else {
|
||||
return (s_ch == trim_ch);
|
||||
}
|
||||
}
|
||||
|
||||
U0 @string_trim(U8* s, U8 ch = NULL, I64 mode = TRIM_BOTH)
|
||||
{
|
||||
Bool trim_ch = @string_trim_ch(*s, ch);
|
||||
if (mode == TRIM_BOTH || mode == TRIM_LEFT) {
|
||||
while (trim_ch) {
|
||||
StrCpy(s, s + 1);
|
||||
trim_ch = @string_trim_ch(*s, ch);
|
||||
}
|
||||
}
|
||||
trim_ch = @string_trim_ch(s[StrLen(s) - 1], ch);
|
||||
if (mode == TRIM_BOTH || mode == TRIM_RIGHT) {
|
||||
while (trim_ch) {
|
||||
s[StrLen(s) - 1] = NULL;
|
||||
trim_ch = @string_trim_ch(s[StrLen(s) - 1], ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class @string
|
||||
{
|
||||
U0(*Append)
|
||||
(U8 * dst, U8 * fmt, ...);
|
||||
Bool (*BeginsWith)(U8* fragment, U8* str);
|
||||
Bool (*EndsWith)(U8* fragment, U8* str);
|
||||
Bool (*IsNumber)(U8* s);
|
||||
U8* (*Replace)(U8* s, U8* oldW, U8* newW);
|
||||
U8** (*Split)(U8* s, U8 ch = '\n', I64 * cnt);
|
||||
U0 (*Trim)(U8* s, U8 ch = NULL, I64 mode = TRIM_BOTH);
|
||||
};
|
||||
|
||||
@string String;
|
||||
String.Append = &@string_append;
|
||||
String.BeginsWith = &@string_begins_with;
|
||||
String.EndsWith = &@string_ends_with;
|
||||
String.IsNumber = &@string_is_number;
|
||||
String.Replace = &@string_replace;
|
||||
String.Split = &@string_split;
|
||||
String.Trim = &@string_trim;
|
||||
|
||||
"string ";
|
104
System/Libraries/System.HC
Normal file
104
System/Libraries/System.HC
Normal file
|
@ -0,0 +1,104 @@
|
|||
class @system
|
||||
{
|
||||
Bool text_mode;
|
||||
CFifoI64* log_fifo;
|
||||
U8* build_info;
|
||||
U8* (*BuildInfo)();
|
||||
U0 (*Init)();
|
||||
U0 (*Log)(CTask* task, U8* fmt, ...);
|
||||
U0 (*PowerOff)();
|
||||
};
|
||||
|
||||
@system System;
|
||||
|
||||
U0 @system_lex_warn(CCmpCtrl* cc,
|
||||
U8* str = NULL)
|
||||
{ // Print warn msg, then, LexPutPos().
|
||||
if (!MemCmp(str, "Assign U0 ", 10))
|
||||
return; // suppress "Assign U0 " warnings
|
||||
if (str)
|
||||
PrintWarn(str);
|
||||
if (cc->htc.fun) {
|
||||
"in fun '%s'.\n", cc->htc.fun->str;
|
||||
if (IsRaw)
|
||||
"%s\n", cc->htc.fun->src_link;
|
||||
else {
|
||||
"$LK,\"%s\"$\n", cc->htc.fun->src_link;
|
||||
AdamErr("%s\n", cc->htc.fun->src_link);
|
||||
}
|
||||
} else
|
||||
LexPutPos(cc);
|
||||
cc->warning_cnt++;
|
||||
}
|
||||
|
||||
U0 @system_print_warn(U8* fmt, ...)
|
||||
{ // Print "Warn:" and msg in blinking red.
|
||||
if (!MemCmp(fmt, "Unused var", 10))
|
||||
return; // suppress "Unused var" warnings
|
||||
if (!MemCmp(fmt, "Using 64-bit reg var.", 21))
|
||||
return; // suppress "Using 64-bit reg var." warnings
|
||||
U8* buf = StrPrintJoin(NULL, fmt, argc, argv);
|
||||
GetOutOfDollar;
|
||||
"%,p %,p %,p %,p " ST_WARN_ST "%s", Caller, Caller(2), Caller(3), Caller(4),
|
||||
buf;
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
@patch_jmp_rel32(&LexWarn, &@system_lex_warn);
|
||||
@patch_jmp_rel32(&PrintWarn, &@system_print_warn);
|
||||
|
||||
U8* @system_build_info() { return System.build_info; }
|
||||
|
||||
U0 @system_log(CTask* task, U8* fmt, ...)
|
||||
{
|
||||
U8* buf = StrPrintJoin(NULL, fmt, argc, argv);
|
||||
U8* str = buf;
|
||||
U32 color;
|
||||
MemCpyU32(&color, &task->task_name, 1);
|
||||
if (!color) {
|
||||
color = RandU32 * 1048576;
|
||||
MemCpyU32(&task->pad, &color, 1);
|
||||
}
|
||||
U8* log_msg = MAlloc(1024);
|
||||
StrPrint(log_msg, "[\x1b[38;2;%d;%d;%dm%16s\x1b[0m] %s\n",
|
||||
color.u8[3] << 5 & 0xFF, color.u8[2] << 4 & 0xFF,
|
||||
color.u8[1] << 3 & 0xFF, Fs->task_name, buf);
|
||||
FifoI64Ins(System.log_fifo, log_msg);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 @system_log_task()
|
||||
{
|
||||
I64 log_msg;
|
||||
while (1) {
|
||||
while (FifoI64Cnt(System.log_fifo)) {
|
||||
FifoI64Rem(System.log_fifo, &log_msg);
|
||||
"%s", log_msg;
|
||||
Free(log_msg);
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
U0 @system_power_off()
|
||||
{
|
||||
OutU16(0x4004, 0x3400);
|
||||
OutU16(0x0604, 0x2000);
|
||||
OutU16(0xB004, 0x2000);
|
||||
}
|
||||
|
||||
U0 @system_init()
|
||||
{
|
||||
System.build_info = FileRead("build_info.TXT");
|
||||
System.log_fifo = FifoI64New(1024);
|
||||
Spawn(&@system_log_task, , , T(mp_cnt, 1, 0));
|
||||
}
|
||||
|
||||
System.BuildInfo = &@system_build_info;
|
||||
System.Init = &@system_init;
|
||||
System.Log = &@system_log;
|
||||
System.PowerOff = &@system_power_off;
|
||||
|
||||
System.Init();
|
||||
|
||||
"system ";
|
49
System/Libraries/Theme.HC
Normal file
49
System/Libraries/Theme.HC
Normal file
|
@ -0,0 +1,49 @@
|
|||
class @theme_colors
|
||||
{
|
||||
U32 active_border;
|
||||
U32 hilight;
|
||||
};
|
||||
|
||||
class @theme_window
|
||||
{
|
||||
I64 min_width;
|
||||
I64 min_height;
|
||||
};
|
||||
|
||||
class @theme_bitmap_fonts
|
||||
{
|
||||
BitmapFont* menu;
|
||||
BitmapFont* monospace;
|
||||
BitmapFont* sans;
|
||||
}
|
||||
|
||||
class @theme_pointers
|
||||
{
|
||||
Context2D* pointer;
|
||||
Context2D* pen;
|
||||
Context2D* move;
|
||||
Context2D* link;
|
||||
AnimationContext2D* wait;
|
||||
Context2D* horz;
|
||||
Context2D* vert;
|
||||
Context2D* text;
|
||||
Context2D* cross;
|
||||
Context2D* dgn1;
|
||||
Context2D* dgn2;
|
||||
Context2D* help;
|
||||
Context2D* alternate;
|
||||
Context2D* unavailable;
|
||||
};
|
||||
|
||||
class @theme
|
||||
{
|
||||
U8* path;
|
||||
@theme_colors color;
|
||||
@theme_bitmap_fonts font;
|
||||
@theme_pointers pointer;
|
||||
@theme_window window;
|
||||
Context2D* wallpaper;
|
||||
U0 (*window_repaint)(Window* win, I64 type);
|
||||
};
|
||||
|
||||
"theme ";
|
115
System/Libraries/Tlse.HC
Normal file
115
System/Libraries/Tlse.HC
Normal file
|
@ -0,0 +1,115 @@
|
|||
#define TLS_V12 0x0303
|
||||
|
||||
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
|
||||
|
||||
U64 @tls_create_context(U8 is_server, U16 version)
|
||||
{
|
||||
U64 reg RDI rdi = is_server;
|
||||
U64 reg RSI rsi = version;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_CREATE_CONTEXT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_sni_set(U64 context, U8* sni)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = sni;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_SNI_SET
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_client_connect(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_CLIENT_CONNECT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U8* @tls_get_write_buffer(U64 context, U32* outlen)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = outlen;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_GET_WRITE_BUFFER
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_buffer_clear(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_BUFFER_CLEAR
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_connection_status(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_CONNECTION_STATUS
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_consume_stream(U64 context, U8* buf, I32 buf_len, U64 certificate_verify)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = buf;
|
||||
U64 reg RDX rdx = buf_len;
|
||||
U64 reg RCX rcx = certificate_verify;
|
||||
no_warn rdi, rsi, rdx, rcx;
|
||||
asm {
|
||||
MOV RAX, TLS_CONSUME_STREAM
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_read(U64 context, U8* buf, U32 size)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = buf;
|
||||
U64 reg RDX rdx = size;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, TLS_READ
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_write(U64 context, U8* data, U32 len)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = data;
|
||||
U64 reg RDX rdx = len;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, TLS_WRITE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_established(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_ESTABLISHED
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
Silent(0);
|
10
System/Libraries/User.HC
Normal file
10
System/Libraries/User.HC
Normal file
|
@ -0,0 +1,10 @@
|
|||
class @user
|
||||
{
|
||||
I64 uid;
|
||||
U8 name[256];
|
||||
U8 fullname[256];
|
||||
U8 passwd[256];
|
||||
U8 groups[256];
|
||||
}
|
||||
|
||||
"user ";
|
834
System/Libraries/Widget.HC
Normal file
834
System/Libraries/Widget.HC
Normal file
|
@ -0,0 +1,834 @@
|
|||
#define TextInputWidget BitmapFontTextInputWidget
|
||||
#define TextLabelWidget BitmapFontTextLabelWidget
|
||||
|
||||
#define WIDGET_TYPE_NULL 0
|
||||
#define WIDGET_TYPE_BUTTON 1
|
||||
#define WIDGET_TYPE_CHECKBOX 2
|
||||
#define WIDGET_TYPE_RADIO 3
|
||||
#define WIDGET_TYPE_INPUT 4
|
||||
#define WIDGET_TYPE_LABEL 5
|
||||
#define WIDGET_TYPE_CONTEXT2D 6
|
||||
#define WIDGET_TYPE_TTF_INPUT 7
|
||||
#define WIDGET_TYPE_TTF_LABEL 8
|
||||
#define WIDGET_TYPE_HORZ_SLIDER 9
|
||||
#define WIDGET_TYPE_VERT_SLIDER 10
|
||||
#define WIDGET_TYPE_TERMINAL 11
|
||||
#define WIDGET_TYPE_HORZ_SCROLLBAR 12
|
||||
#define WIDGET_TYPE_VERT_SCROLLBAR 13
|
||||
#define WIDGET_TYPE_MENU_ITEM 14
|
||||
#define WIDGET_TYPE_LISTVIEW 15
|
||||
|
||||
#define TERMINAL_MAX_COLS 1920 / 8
|
||||
|
||||
#define TERMINAL_STATE_OUTPUT 0
|
||||
#define TERMINAL_STATE_CONSUME_BEGIN 1
|
||||
#define TERMINAL_STATE_CONSUME_CTRL_SEQ 2
|
||||
#define TERMINAL_STATE_CONSUME_OS_CMD 3
|
||||
#define TERMINAL_STATE_CONSUME_END 99
|
||||
|
||||
asm {
|
||||
TERMINAL_COLOR_TABLE::
|
||||
DU32 0xff000000, 0xff800000, 0xff008000, 0xff808000, 0xff000080, 0xff800080, 0xff008080, 0xffc0c0c0, 0xff808080, 0xffff0000, 0xff00ff00, 0xffffff00, 0xff0000ff, 0xffff00ff, 0xff00ffff, 0xffffffff, 0xff000000, 0xff00005f, 0xff000087, 0xff0000af, 0xff0000d7, 0xff0000ff, 0xff005f00, 0xff005f5f, 0xff005f87, 0xff005faf, 0xff005fd7, 0xff005fff, 0xff008700, 0xff00875f, 0xff008787, 0xff0087af, 0xff0087d7, 0xff0087ff, 0xff00af00, 0xff00af5f, 0xff00af87, 0xff00afaf, 0xff00afd7, 0xff00afff, 0xff00d700, 0xff00d75f, 0xff00d787, 0xff00d7af, 0xff00d7d7, 0xff00d7ff, 0xff00ff00, 0xff00ff5f, 0xff00ff87, 0xff00ffaf, 0xff00ffd7, 0xff00ffff, 0xff5f0000, 0xff5f005f, 0xff5f0087, 0xff5f00af, 0xff5f00d7, 0xff5f00ff, 0xff5f5f00, 0xff5f5f5f, 0xff5f5f87, 0xff5f5faf, 0xff5f5fd7, 0xff5f5fff, 0xff5f8700, 0xff5f875f, 0xff5f8787, 0xff5f87af, 0xff5f87d7, 0xff5f87ff, 0xff5faf00, 0xff5faf5f, 0xff5faf87, 0xff5fafaf, 0xff5fafd7, 0xff5fafff, 0xff5fd700, 0xff5fd75f, 0xff5fd787, 0xff5fd7af, 0xff5fd7d7, 0xff5fd7ff, 0xff5fff00, 0xff5fff5f, 0xff5fff87, 0xff5fffaf, 0xff5fffd7, 0xff5fffff, 0xff870000, 0xff87005f, 0xff870087, 0xff8700af, 0xff8700d7, 0xff8700ff, 0xff875f00, 0xff875f5f, 0xff875f87, 0xff875faf, 0xff875fd7, 0xff875fff, 0xff878700, 0xff87875f, 0xff878787, 0xff8787af, 0xff8787d7, 0xff8787ff, 0xff87af00, 0xff87af5f, 0xff87af87, 0xff87afaf, 0xff87afd7, 0xff87afff, 0xff87d700, 0xff87d75f, 0xff87d787, 0xff87d7af, 0xff87d7d7, 0xff87d7ff, 0xff87ff00, 0xff87ff5f, 0xff87ff87, 0xff87ffaf, 0xff87ffd7, 0xff87ffff, 0xffaf0000, 0xffaf005f, 0xffaf0087, 0xffaf00af, 0xffaf00d7, 0xffaf00ff, 0xffaf5f00, 0xffaf5f5f, 0xffaf5f87, 0xffaf5faf, 0xffaf5fd7, 0xffaf5fff, 0xffaf8700, 0xffaf875f, 0xffaf8787, 0xffaf87af, 0xffaf87d7, 0xffaf87ff, 0xffafaf00, 0xffafaf5f, 0xffafaf87, 0xffafafaf, 0xffafafd7, 0xffafafff, 0xffafd700, 0xffafd75f, 0xffafd787, 0xffafd7af, 0xffafd7d7, 0xffafd7ff, 0xffafff00, 0xffafff5f, 0xffafff87, 0xffafffaf, 0xffafffd7, 0xffafffff, 0xffd70000, 0xffd7005f, 0xffd70087, 0xffd700af, 0xffd700d7, 0xffd700ff, 0xffd75f00, 0xffd75f5f, 0xffd75f87, 0xffd75faf, 0xffd75fd7, 0xffd75fff, 0xffd78700, 0xffd7875f, 0xffd78787, 0xffd787af, 0xffd787d7, 0xffd787ff, 0xffd7af00, 0xffd7af5f, 0xffd7af87, 0xffd7afaf, 0xffd7afd7, 0xffd7afff, 0xffd7d700, 0xffd7d75f, 0xffd7d787, 0xffd7d7af, 0xffd7d7d7, 0xffd7d7ff, 0xffd7ff00, 0xffd7ff5f, 0xffd7ff87, 0xffd7ffaf, 0xffd7ffd7, 0xffd7ffff, 0xffff0000, 0xffff005f, 0xffff0087, 0xffff00af, 0xffff00d7, 0xffff00ff, 0xffff5f00, 0xffff5f5f, 0xffff5f87, 0xffff5faf, 0xffff5fd7, 0xffff5fff, 0xffff8700, 0xffff875f, 0xffff8787, 0xffff87af, 0xffff87d7, 0xffff87ff, 0xffffaf00, 0xffffaf5f, 0xffffaf87, 0xffffafaf, 0xffffafd7, 0xffffafff, 0xffffd700, 0xffffd75f, 0xffffd787, 0xffffd7af, 0xffffd7d7, 0xffffd7ff, 0xffffff00, 0xffffff5f, 0xffffff87, 0xffffffaf, 0xffffffd7, 0xffffffff, 0xff080808, 0xff121212, 0xff1c1c1c, 0xff262626, 0xff303030, 0xff3a3a3a, 0xff444444, 0xff4e4e4e, 0xff585858, 0xff626262, 0xff6c6c6c, 0xff767676, 0xff808080, 0xff8a8a8a, 0xff949494, 0xff9e9e9e, 0xffa8a8a8, 0xffb2b2b2, 0xffbcbcbc, 0xffc6c6c6, 0xffd0d0d0, 0xffdadada, 0xffe4e4e4, 0xffeeeeee;
|
||||
}
|
||||
|
||||
U8 widget_self_set1[0x1F] = { 0x55, 0x48, 0x8B, 0xEC, 0x56, 0x48, 0x8B, 0x75,
|
||||
0x10, 0x56, 0x48, 0xBB, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x53, 0xE8, 0x0, 0x0,
|
||||
0x0, 0x0, 0x5E, 0x5D, 0xC2, 0x08, 0x0 };
|
||||
|
||||
class ButtonWidget : Widget {
|
||||
BitmapFont* font;
|
||||
U8 text[1024];
|
||||
Context2D* image;
|
||||
U32 color;
|
||||
};
|
||||
|
||||
class MenuItemWidget : Widget {
|
||||
BitmapFont* font;
|
||||
U8 text[128];
|
||||
Context2D* icon;
|
||||
U32 color;
|
||||
U8* path;
|
||||
Window* submenu;
|
||||
};
|
||||
|
||||
class Context2DWidget : Widget {
|
||||
Bool fast_copy;
|
||||
Context2D* ctx;
|
||||
};
|
||||
|
||||
class CheckBoxWidget : Widget {
|
||||
Bool checked;
|
||||
};
|
||||
|
||||
class RadioButtonWidget : Widget {
|
||||
I64 group;
|
||||
Bool selected;
|
||||
};
|
||||
|
||||
class @terminal_widget_attr
|
||||
{
|
||||
Bool bold;
|
||||
Bool underline;
|
||||
Bool blink;
|
||||
Bool negative;
|
||||
Bool invisible;
|
||||
}
|
||||
|
||||
class @terminal_widget_col
|
||||
{
|
||||
U32 background;
|
||||
U32 foreground;
|
||||
U8 char;
|
||||
};
|
||||
|
||||
class @terminal_widget_color
|
||||
{
|
||||
U32 background;
|
||||
U32 foreground;
|
||||
U32 cursor;
|
||||
};
|
||||
|
||||
class @terminal_widget_cursor
|
||||
{
|
||||
I64 x;
|
||||
I64 y;
|
||||
Bool hidden;
|
||||
};
|
||||
|
||||
class @terminal_widget_row
|
||||
{
|
||||
@terminal_widget_col col[TERMINAL_MAX_COLS];
|
||||
};
|
||||
|
||||
class @terminal_widget_scroll
|
||||
{
|
||||
I64 x;
|
||||
I64 y;
|
||||
};
|
||||
|
||||
class @terminal_widget_size
|
||||
{
|
||||
I64 rows;
|
||||
I64 cols;
|
||||
};
|
||||
|
||||
class @terminal_widget_stored
|
||||
{
|
||||
@terminal_widget_attr attr;
|
||||
@terminal_widget_color color;
|
||||
@terminal_widget_cursor cursor;
|
||||
};
|
||||
|
||||
class TerminalWidget : Widget {
|
||||
CFifoU8* input;
|
||||
CFifoU8* output;
|
||||
Bool refresh;
|
||||
U8 consumed_chars[256];
|
||||
I64 state;
|
||||
I64 last_fg_color_set;
|
||||
@terminal_widget_attr attr;
|
||||
@terminal_widget_color color;
|
||||
@terminal_widget_cursor cursor;
|
||||
@terminal_widget_row* row;
|
||||
@terminal_widget_scroll scroll;
|
||||
@terminal_widget_scroll max;
|
||||
@terminal_widget_size size;
|
||||
@terminal_widget_stored stored;
|
||||
};
|
||||
|
||||
class BitmapFontTextInputWidget : Widget {
|
||||
BitmapFont* font;
|
||||
Bool blink;
|
||||
Bool in_drag;
|
||||
Bool is_password;
|
||||
I64 cursor_index;
|
||||
I64 mouse_drag_origin_x;
|
||||
I64 mouse_drag_index;
|
||||
I64 selected_region_start;
|
||||
I64 selected_region_end;
|
||||
I64 x_offset;
|
||||
U32 color;
|
||||
U8 text[1024];
|
||||
U8 password[1024];
|
||||
U0 (*SetFont)(U8* font);
|
||||
U0 (*SetText)(U8* text);
|
||||
}
|
||||
|
||||
class BitmapFontTextLabelWidget : Widget {
|
||||
BitmapFont* font;
|
||||
U32 color;
|
||||
U8 text[1024];
|
||||
U0 (*SetFont)(U8* font);
|
||||
U0 (*SetText)(U8* text);
|
||||
};
|
||||
|
||||
class TrueTypeTextInputWidget : Widget {
|
||||
U8* font;
|
||||
U32 color;
|
||||
U32 bgcolor;
|
||||
I64 size;
|
||||
U8* text;
|
||||
U8* prev_text;
|
||||
};
|
||||
|
||||
class TrueTypeTextLabelWidget : Widget {
|
||||
U8* font;
|
||||
U32 color;
|
||||
U32 bgcolor;
|
||||
I64 size;
|
||||
U8* text;
|
||||
U8* prev_text;
|
||||
};
|
||||
|
||||
class HorizontalSliderWidget : Widget {
|
||||
Bool in_drag;
|
||||
I64 scroll;
|
||||
I64 max;
|
||||
I64 value;
|
||||
};
|
||||
|
||||
class VerticalSliderWidget : Widget {
|
||||
Bool in_drag;
|
||||
I64 scroll;
|
||||
I64 max;
|
||||
I64 value;
|
||||
};
|
||||
|
||||
class HorizontalScrollBarWidget : Widget {
|
||||
Bool in_drag;
|
||||
I64 scroll;
|
||||
I64 max;
|
||||
I64 value;
|
||||
};
|
||||
|
||||
class VerticalScrollBarWidget : Widget {
|
||||
Bool in_drag;
|
||||
I64 scroll;
|
||||
I64 length;
|
||||
I64 max;
|
||||
I64 value;
|
||||
};
|
||||
|
||||
class @list_view_item
|
||||
{
|
||||
@list_view_item* prev;
|
||||
@list_view_item* next;
|
||||
Context2D* icon;
|
||||
U8 text[1024];
|
||||
};
|
||||
|
||||
class ListViewWidget : Widget {
|
||||
BitmapFont* font;
|
||||
U32 color;
|
||||
@list_view_item* items;
|
||||
};
|
||||
|
||||
U0 @gui_widget_set_echo(Widget* widget, U8* echo)
|
||||
{
|
||||
if (!widget || !echo)
|
||||
return;
|
||||
widget->echo = echo;
|
||||
}
|
||||
|
||||
U0 @gui_widget_set_font(Widget* widget, U8* font_name)
|
||||
{
|
||||
if (!widget || !font_name)
|
||||
return;
|
||||
if (!StrLen(font_name))
|
||||
return;
|
||||
switch (widget->type) {
|
||||
case WIDGET_TYPE_BUTTON:
|
||||
widget(ButtonWidget*)->font = BitmapFonts.GetByName(font_name);
|
||||
break;
|
||||
case WIDGET_TYPE_INPUT:
|
||||
widget(BitmapFontTextInputWidget*)->font = BitmapFonts.GetByName(font_name);
|
||||
break;
|
||||
case WIDGET_TYPE_LABEL:
|
||||
widget(BitmapFontTextLabelWidget*)->font = BitmapFonts.GetByName(font_name);
|
||||
break;
|
||||
case WIDGET_TYPE_LISTVIEW:
|
||||
widget(ListViewWidget*)->font = BitmapFonts.GetByName(font_name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 @gui_widget_set_mouse_pointer(Widget* widget, Context2D* pointer)
|
||||
{
|
||||
if (!widget)
|
||||
return;
|
||||
widget->pointer = pointer;
|
||||
}
|
||||
|
||||
U0 @gui_widget_clear_mouse_pointer(Widget* widget)
|
||||
{
|
||||
if (!widget)
|
||||
return;
|
||||
widget->pointer = NULL;
|
||||
}
|
||||
|
||||
U0 @gui_widget_set_opacity(Widget* widget, I64 opacity)
|
||||
{
|
||||
if (!widget)
|
||||
return;
|
||||
widget->opacity = ClampI64(opacity, 0, 255);
|
||||
}
|
||||
|
||||
U0 @gui_widget_set_callback(Widget* widget, U8* name, U64 callback)
|
||||
{
|
||||
if (!widget || !name || !callback)
|
||||
return;
|
||||
if (!StrCmp(name, "change"))
|
||||
widget->callback.change = callback;
|
||||
if (!StrCmp(name, "clicked"))
|
||||
widget->callback.clicked = callback;
|
||||
if (!StrCmp(name, "repaint"))
|
||||
widget->callback.repaint = callback;
|
||||
}
|
||||
|
||||
U0 @gui_widget_set_text(Widget* widget, U8* text)
|
||||
{
|
||||
if (!widget)
|
||||
return;
|
||||
switch (widget->type) {
|
||||
case WIDGET_TYPE_BUTTON:
|
||||
StrCpy(&widget(ButtonWidget*)->text, text);
|
||||
break;
|
||||
case WIDGET_TYPE_INPUT:
|
||||
StrCpy(&widget(TextInputWidget*)->text, text);
|
||||
break;
|
||||
case WIDGET_TYPE_LABEL:
|
||||
StrCpy(&widget(TextLabelWidget*)->text, text);
|
||||
break;
|
||||
case WIDGET_TYPE_MENU_ITEM:
|
||||
StrCpy(&widget(MenuItemWidget*)->text, text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Bool @widget_is_hovered(I64 x, I64 y, Widget* widget)
|
||||
{
|
||||
if (Mouse.x > x && Mouse.x < x + widget->width && Mouse.y > y && Mouse.y < y + widget->height)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool @gui_widget_is_hovered(Window* win, Widget* widget)
|
||||
{
|
||||
return @widget_is_hovered(win->x + widget->x, win->y + widget->y, widget);
|
||||
}
|
||||
|
||||
U0 @widget_add_widget_to_list(Window* win, Widget* widget)
|
||||
{
|
||||
if (!win || !widget)
|
||||
return;
|
||||
@window_widgets_list* widgets_list = win->widget;
|
||||
while (widgets_list->next) {
|
||||
widgets_list = widgets_list->next;
|
||||
}
|
||||
@window_widgets_list* widget_list_item = CAlloc(sizeof(@window_widgets_list));
|
||||
widget_list_item->widget = widget;
|
||||
widget_list_item->prev = widgets_list;
|
||||
widgets_list->next = widget_list_item;
|
||||
}
|
||||
|
||||
U0 @widget_input_backspace(BitmapFontTextInputWidget* widget)
|
||||
{
|
||||
I64 i;
|
||||
I64 len = StrLen(&widget->text);
|
||||
for (i = widget->cursor_index - 1; i < len; i++) {
|
||||
widget->text[i] = widget->text[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
U0 @widget_input_clear_selected_region(BitmapFontTextInputWidget* widget)
|
||||
{
|
||||
widget->selected_region_start = -1;
|
||||
widget->selected_region_end = -1;
|
||||
}
|
||||
Bool @widget_input_delete_selected_region(BitmapFontTextInputWidget* widget)
|
||||
{
|
||||
I64 i;
|
||||
I64 j;
|
||||
if (widget->selected_region_start != -1 && widget->selected_region_end != -1) {
|
||||
j = widget->selected_region_start;
|
||||
for (i = widget->selected_region_end + 1; i < StrLen(&widget->text) + 1;
|
||||
i++) {
|
||||
widget->text[j++] = widget->text[i];
|
||||
}
|
||||
widget->text[j] = NULL;
|
||||
widget->cursor_index = widget->selected_region_start;
|
||||
@widget_input_clear_selected_region(widget);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 @widget_input_delete_at_cursor(BitmapFontTextInputWidget* widget)
|
||||
{
|
||||
I64 i;
|
||||
I64 len = StrLen(&widget->text);
|
||||
for (i = widget->cursor_index; i < len; i++)
|
||||
widget->text[i] = widget->text[i + 1];
|
||||
@widget_input_clear_selected_region(widget);
|
||||
}
|
||||
|
||||
U0 @widget_input_insert_char(BitmapFontTextInputWidget* widget, I64 char)
|
||||
{
|
||||
U8 buf[1024];
|
||||
U8* pos;
|
||||
I64 i, j, k;
|
||||
j = 0;
|
||||
for (i = widget->cursor_index; i < StrLen(&widget->text); i++) {
|
||||
buf[j++] = widget->text[i];
|
||||
}
|
||||
buf[j] = NULL;
|
||||
for (i = widget->cursor_index; i < 1024; i++) {
|
||||
widget->text[i] = NULL;
|
||||
}
|
||||
widget->text[StrLen(&widget->text)] = char;
|
||||
pos = &buf;
|
||||
while (*pos) {
|
||||
widget->text[StrLen(&widget->text)] = *pos;
|
||||
pos++;
|
||||
}
|
||||
@widget_input_clear_selected_region(widget);
|
||||
widget->cursor_index++;
|
||||
}
|
||||
|
||||
U0 @widget_input_insert_scancode(BitmapFontTextInputWidget* widget, I64 key)
|
||||
{
|
||||
U8 buf[1024];
|
||||
U8* pos;
|
||||
I64 i, j, k;
|
||||
j = 0;
|
||||
for (i = widget->cursor_index; i < StrLen(&widget->text); i++) {
|
||||
buf[j++] = widget->text[i];
|
||||
}
|
||||
buf[j] = NULL;
|
||||
for (i = widget->cursor_index; i < 1024; i++) {
|
||||
widget->text[i] = NULL;
|
||||
}
|
||||
if (!Bt(kbd.down_bitmap, SC_SHIFT))
|
||||
widget->text[StrLen(&widget->text)] = NORMAL_KEY_SCAN_DECODE_TABLE(U8*)[key];
|
||||
else
|
||||
widget->text[StrLen(&widget->text)] = SHIFT_KEY_SCAN_DECODE_TABLE(U8*)[key];
|
||||
pos = &buf;
|
||||
while (*pos) {
|
||||
widget->text[StrLen(&widget->text)] = *pos;
|
||||
pos++;
|
||||
}
|
||||
@widget_input_clear_selected_region(widget);
|
||||
widget->cursor_index++;
|
||||
}
|
||||
|
||||
U0 @widget_input_insert_text(BitmapFontTextInputWidget* widget, U8* text)
|
||||
{
|
||||
while (*text) {
|
||||
@widget_input_insert_char(widget, *text);
|
||||
text++;
|
||||
}
|
||||
}
|
||||
|
||||
Bool @widget_input_handle_key(BitmapFontTextInputWidget* widget)
|
||||
{
|
||||
I64 key = Keyboard.active_key;
|
||||
I64 tS = Keyboard.active_key_tS;
|
||||
if (widget->cursor_index > StrLen(&widget->text) || widget->cursor_index < 0)
|
||||
widget->cursor_index = 0;
|
||||
if (widget->selected_region_start > widget->selected_region_end) {
|
||||
@widget_input_clear_selected_region(widget);
|
||||
}
|
||||
if (key && tS != Keyboard.last_key_tS) {
|
||||
switch (key) {
|
||||
case SC_DELETE:
|
||||
if (widget->selected_region_start != -1 && widget->selected_region_end != -1) {
|
||||
@widget_input_delete_selected_region(widget);
|
||||
} else {
|
||||
@widget_input_delete_at_cursor(widget);
|
||||
}
|
||||
break;
|
||||
case SC_HOME:
|
||||
if (Bt(kbd.down_bitmap, SC_SHIFT) && widget->selected_region_start) {
|
||||
widget->selected_region_start = 0;
|
||||
if (widget->selected_region_end == -1)
|
||||
widget->selected_region_end = widget->cursor_index - 1;
|
||||
} else {
|
||||
@widget_input_clear_selected_region(widget);
|
||||
widget->cursor_index = 0;
|
||||
}
|
||||
break;
|
||||
case SC_CURSOR_LEFT:
|
||||
/*
|
||||
"widget->selected_region_start : %d \n", widget->selected_region_start;
|
||||
"widget->selected_region_end : %d \n", widget->selected_region_end;
|
||||
"widget->cursor_index : %d \n", widget->cursor_index;
|
||||
*/
|
||||
if (widget->cursor_index)
|
||||
widget->cursor_index--;
|
||||
if (!Bt(kbd.down_bitmap, SC_SHIFT)) {
|
||||
if (widget->selected_region_start != -1)
|
||||
widget->cursor_index = widget->selected_region_start;
|
||||
@widget_input_clear_selected_region(widget);
|
||||
} else {
|
||||
if (Bt(kbd.down_bitmap, SC_CTRL) && widget->selected_region_start) {
|
||||
widget->selected_region_start = 0;
|
||||
if (widget->selected_region_end == -1)
|
||||
widget->selected_region_end = widget->cursor_index;
|
||||
break;
|
||||
}
|
||||
switch (widget->selected_region_start) {
|
||||
case -1:
|
||||
widget->selected_region_start = widget->cursor_index;
|
||||
widget->selected_region_end = widget->cursor_index;
|
||||
break;
|
||||
// case 0:
|
||||
// break;
|
||||
default:
|
||||
if (widget->cursor_index > widget->selected_region_start) {
|
||||
widget->selected_region_end = widget->cursor_index - 1;
|
||||
} else {
|
||||
widget->selected_region_start = widget->cursor_index;
|
||||
if (widget->selected_region_start == widget->selected_region_end) {
|
||||
@widget_input_clear_selected_region(widget);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SC_END:
|
||||
if (Bt(kbd.down_bitmap, SC_SHIFT)) {
|
||||
widget->selected_region_start = widget->cursor_index;
|
||||
widget->selected_region_end = StrLen(&widget->text) - 1;
|
||||
} else {
|
||||
@widget_input_clear_selected_region(widget);
|
||||
widget->cursor_index = StrLen(&widget->text);
|
||||
}
|
||||
break;
|
||||
case SC_CURSOR_RIGHT:
|
||||
/*
|
||||
"widget->selected_region_start : %d \n", widget->selected_region_start;
|
||||
"widget->selected_region_end : %d \n", widget->selected_region_end;
|
||||
"widget->cursor_index : %d \n", widget->cursor_index;
|
||||
*/
|
||||
if (!Bt(kbd.down_bitmap, SC_SHIFT)) {
|
||||
if (widget->selected_region_end != -1)
|
||||
widget->cursor_index = widget->selected_region_end;
|
||||
@widget_input_clear_selected_region(widget);
|
||||
} else {
|
||||
if (Bt(kbd.down_bitmap, SC_CTRL)) {
|
||||
widget->selected_region_start = widget->cursor_index;
|
||||
widget->selected_region_end = StrLen(&widget->text) - 1;
|
||||
break;
|
||||
}
|
||||
switch (widget->selected_region_start) {
|
||||
case -1:
|
||||
widget->selected_region_start = widget->cursor_index;
|
||||
widget->selected_region_end = widget->cursor_index;
|
||||
break;
|
||||
default:
|
||||
if (widget->cursor_index == widget->selected_region_start) {
|
||||
widget->selected_region_start = widget->cursor_index + 1;
|
||||
} else
|
||||
widget->selected_region_end = widget->cursor_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (widget->cursor_index < StrLen(&widget->text))
|
||||
widget->cursor_index++;
|
||||
break;
|
||||
|
||||
case SC_BACKSPACE:
|
||||
if (@widget_input_delete_selected_region(widget))
|
||||
return TRUE;
|
||||
if (widget->cursor_index < 1)
|
||||
break;
|
||||
@widget_input_backspace(widget);
|
||||
@widget_input_clear_selected_region(widget);
|
||||
widget->cursor_index--;
|
||||
break;
|
||||
|
||||
case 0x02 ... 0x0D:
|
||||
case 0x10 ... 0x1B:
|
||||
case 0x1E ... 0x29:
|
||||
case 0x2B ... 0x35:
|
||||
case 0x39:
|
||||
if (Bt(kbd.down_bitmap, SC_CTRL)) {
|
||||
switch (ScanCode2Char(key)) {
|
||||
case 'a':
|
||||
if (StrLen(&widget->text)) {
|
||||
widget->selected_region_start = 0;
|
||||
widget->selected_region_end = StrLen(&widget->text) - 1;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
case 'x':
|
||||
if (widget->selected_region_start != -1 && widget->selected_region_end != -1) {
|
||||
U64 pos = &widget->text;
|
||||
pos += widget->selected_region_start;
|
||||
U8* text = StrNew(pos);
|
||||
text[widget->selected_region_end - widget->selected_region_start + 1] = NULL;
|
||||
Clipboard.Insert(CLIP_TYPE_TEXT, text);
|
||||
if (ScanCode2Char(key) == 'x')
|
||||
@widget_input_delete_selected_region(widget);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
// FIXME: Clipboard.Paste?
|
||||
if (Clipboard.length) {
|
||||
@widget_input_delete_selected_region(widget);
|
||||
if (Clipboard.items->prev) {
|
||||
if (Clipboard.items->prev->item->type == CLIP_TYPE_TEXT) {
|
||||
@widget_input_insert_text(
|
||||
widget,
|
||||
Clipboard.items->prev->item(ClipboardTextItem*)->text);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@widget_input_delete_selected_region(widget);
|
||||
@widget_input_insert_scancode(widget, key);
|
||||
break;
|
||||
default:
|
||||
//@widget_input_delete_selected_region(widget);
|
||||
break;
|
||||
};
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Widget* @widget_create_widget(Window* win, I64 type, I64 x, I64 y, I64 width,
|
||||
I64 height)
|
||||
{
|
||||
if (!win || !type)
|
||||
return NULL;
|
||||
|
||||
I64 size_of_widget;
|
||||
Widget* widget;
|
||||
|
||||
switch (type) {
|
||||
case WIDGET_TYPE_NULL:
|
||||
return NULL;
|
||||
case WIDGET_TYPE_BUTTON:
|
||||
size_of_widget = sizeof(ButtonWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_CHECKBOX:
|
||||
size_of_widget = sizeof(CheckBoxWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_TERMINAL:
|
||||
size_of_widget = sizeof(TerminalWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_RADIO:
|
||||
size_of_widget = sizeof(RadioButtonWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_INPUT:
|
||||
size_of_widget = sizeof(TextInputWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_LABEL:
|
||||
size_of_widget = sizeof(TextLabelWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_LISTVIEW:
|
||||
size_of_widget = sizeof(ListViewWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_MENU_ITEM:
|
||||
size_of_widget = sizeof(MenuItemWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_TTF_LABEL:
|
||||
size_of_widget = sizeof(TrueTypeTextLabelWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_CONTEXT2D:
|
||||
size_of_widget = sizeof(Context2DWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_HORZ_SLIDER:
|
||||
size_of_widget = sizeof(HorizontalSliderWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_VERT_SLIDER:
|
||||
size_of_widget = sizeof(VerticalSliderWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_HORZ_SCROLLBAR:
|
||||
size_of_widget = sizeof(HorizontalScrollBarWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
case WIDGET_TYPE_VERT_SCROLLBAR:
|
||||
size_of_widget = sizeof(VerticalScrollBarWidget) * 2;
|
||||
goto @widget_create_set_values;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@widget_create_set_values : widget = CAlloc(size_of_widget);
|
||||
widget->type = type;
|
||||
widget->x = x;
|
||||
widget->y = y;
|
||||
widget->width = width;
|
||||
widget->height = height;
|
||||
widget->parent_win = win;
|
||||
|
||||
switch (type) {
|
||||
case WIDGET_TYPE_TERMINAL:
|
||||
widget(TerminalWidget*)->backing_store = NewContext2D(Display.Width(), Display.Height());
|
||||
widget(TerminalWidget*)->input = FifoU8New(65536);
|
||||
widget(TerminalWidget*)->color.background = Color(0, 0, 0);
|
||||
widget(TerminalWidget*)->color.foreground = Color(217, 217, 217);
|
||||
widget(TerminalWidget*)->color.cursor = Color(217, 217, 0);
|
||||
widget(TerminalWidget*)->row = CAlloc(sizeof(@terminal_widget_row) * 2000);
|
||||
break;
|
||||
case WIDGET_TYPE_INPUT:
|
||||
widget(TextInputWidget*)->color = Color(0, 0, 0);
|
||||
widget(TextInputWidget*)->cursor_index = -1;
|
||||
widget(TextInputWidget*)->mouse_drag_index = -1;
|
||||
widget(TextInputWidget*)->selected_region_start = -1;
|
||||
widget(TextInputWidget*)->selected_region_end = -1;
|
||||
break;
|
||||
case WIDGET_TYPE_LABEL:
|
||||
widget(TextLabelWidget*)->color = Color(0, 0, 0);
|
||||
widget(TextLabelWidget*)->SetText = CAlloc(0x1F, Fs->code_heap);
|
||||
I32 addr = widget(TextLabelWidget*)->SetText;
|
||||
MemCpy(addr, widget_self_set1, 0x1F);
|
||||
MemCpy(addr + 12, &widget, 8);
|
||||
Function.InsertCall(addr + 21, Gui.Widget.SetText);
|
||||
break;
|
||||
case WIDGET_TYPE_LISTVIEW:
|
||||
widget(ListViewWidget*)->color = Color(0, 0, 0);
|
||||
widget(ListViewWidget*)->items = CAlloc(sizeof(@list_view_item));
|
||||
break;
|
||||
}
|
||||
|
||||
@widget_add_widget_to_list(win, widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
U0 @widget_init_widget(Widget* widget, Window* win, I64 type, I64 x, I64 y,
|
||||
I64 width, I64 height)
|
||||
{
|
||||
if (!win || !widget || !type)
|
||||
return;
|
||||
|
||||
I64 size_of_widget = 0;
|
||||
I32 addr = NULL;
|
||||
|
||||
switch (type) {
|
||||
case WIDGET_TYPE_NULL:
|
||||
return;
|
||||
case WIDGET_TYPE_BUTTON:
|
||||
size_of_widget = sizeof(ButtonWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_CHECKBOX:
|
||||
size_of_widget = sizeof(CheckBoxWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_TERMINAL:
|
||||
size_of_widget = sizeof(TerminalWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_RADIO:
|
||||
size_of_widget = sizeof(RadioButtonWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_INPUT:
|
||||
size_of_widget = sizeof(TextInputWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_LABEL:
|
||||
size_of_widget = sizeof(TextLabelWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_LISTVIEW:
|
||||
size_of_widget = sizeof(ListViewWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_MENU_ITEM:
|
||||
size_of_widget = sizeof(MenuItemWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_TTF_LABEL:
|
||||
size_of_widget = sizeof(TrueTypeTextLabelWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_CONTEXT2D:
|
||||
size_of_widget = sizeof(Context2DWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_HORZ_SLIDER:
|
||||
size_of_widget = sizeof(HorizontalSliderWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_VERT_SLIDER:
|
||||
size_of_widget = sizeof(VerticalSliderWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_HORZ_SCROLLBAR:
|
||||
size_of_widget = sizeof(HorizontalScrollBarWidget);
|
||||
break;
|
||||
case WIDGET_TYPE_VERT_SCROLLBAR:
|
||||
size_of_widget = sizeof(VerticalScrollBarWidget);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MemSet(widget, NULL, size_of_widget);
|
||||
|
||||
widget->type = type;
|
||||
widget->x = x;
|
||||
widget->y = y;
|
||||
widget->width = width;
|
||||
widget->height = height;
|
||||
widget->parent_win = win;
|
||||
|
||||
switch (type) {
|
||||
case WIDGET_TYPE_TERMINAL:
|
||||
widget(TerminalWidget*)->backing_store = NewContext2D(Display.Width(), Display.Height());
|
||||
widget(TerminalWidget*)->input = FifoU8New(65536);
|
||||
widget(TerminalWidget*)->color.background = Color(0, 0, 0);
|
||||
widget(TerminalWidget*)->color.foreground = Color(217, 217, 217);
|
||||
widget(TerminalWidget*)->color.cursor = Color(217, 217, 0);
|
||||
widget(TerminalWidget*)->row = CAlloc(sizeof(@terminal_widget_row) * 2000);
|
||||
break;
|
||||
case WIDGET_TYPE_INPUT:
|
||||
widget(TextInputWidget*)->color = Color(0, 0, 0);
|
||||
widget(TextInputWidget*)->cursor_index = -1;
|
||||
widget(TextInputWidget*)->mouse_drag_index = -1;
|
||||
widget(TextInputWidget*)->selected_region_start = -1;
|
||||
widget(TextInputWidget*)->selected_region_end = -1;
|
||||
widget(TextInputWidget*)->color = Color(0, 0, 0);
|
||||
widget(TextInputWidget*)->SetText = CAlloc(0x1F, Fs->code_heap);
|
||||
addr = widget(TextInputWidget*)->SetFont;
|
||||
MemCpy(addr, widget_self_set1, 0x1F);
|
||||
MemCpy(addr + 12, &widget, 8);
|
||||
Function.InsertCall(addr + 21, Gui.Widget.SetFont);
|
||||
addr = widget(TextInputWidget*)->SetText;
|
||||
MemCpy(addr, widget_self_set1, 0x1F);
|
||||
MemCpy(addr + 12, &widget, 8);
|
||||
Function.InsertCall(addr + 21, Gui.Widget.SetText);
|
||||
break;
|
||||
case WIDGET_TYPE_LABEL:
|
||||
widget(TextLabelWidget*)->color = Color(0, 0, 0);
|
||||
widget(TextLabelWidget*)->SetText = CAlloc(0x1F, Fs->code_heap);
|
||||
addr = widget(TextLabelWidget*)->SetFont;
|
||||
MemCpy(addr, widget_self_set1, 0x1F);
|
||||
MemCpy(addr + 12, &widget, 8);
|
||||
Function.InsertCall(addr + 21, Gui.Widget.SetFont);
|
||||
addr = widget(TextLabelWidget*)->SetText;
|
||||
MemCpy(addr, widget_self_set1, 0x1F);
|
||||
MemCpy(addr + 12, &widget, 8);
|
||||
Function.InsertCall(addr + 21, Gui.Widget.SetText);
|
||||
break;
|
||||
case WIDGET_TYPE_LISTVIEW:
|
||||
widget(ListViewWidget*)->color = Color(0, 0, 0);
|
||||
widget(ListViewWidget*)->items = CAlloc(sizeof(@list_view_item));
|
||||
break;
|
||||
}
|
||||
|
||||
@widget_add_widget_to_list(win, widget);
|
||||
}
|
||||
|
||||
Gui.CreateWidget = &@widget_create_widget;
|
||||
Gui.InitWidget = &@widget_init_widget;
|
||||
|
||||
Gui.Widget.IsHovered = &@gui_widget_is_hovered;
|
||||
Gui.Widget.SetCallback = &@gui_widget_set_callback;
|
||||
Gui.Widget.SetEcho = &@gui_widget_set_echo;
|
||||
Gui.Widget.SetFont = &@gui_widget_set_font;
|
||||
Gui.Widget.SetMousePointer = &@gui_widget_set_mouse_pointer;
|
||||
Gui.Widget.ClearMousePointer = &@gui_widget_clear_mouse_pointer;
|
||||
Gui.Widget.SetOpacity = &@gui_widget_set_opacity;
|
||||
Gui.Widget.SetText = &@gui_widget_set_text;
|
||||
|
||||
"widget ";
|
Loading…
Add table
Add a link
Reference in a new issue