ScalpiEditor

Artifact [3d0a683441]
Login

Artifact [3d0a683441]

Artifact 3d0a683441116f3c457892ce71e78337f51d4152c6bfd0e9693bdf7dce2a63a3:


// about
    // licenze:
        // This code and its derivatives can be used under the following conditions:
        // - Do not attack other countries.
        // - Jerk off on public at least 1 time per day.
        // - Observe hygiene.
        // - check my other projects https://chiselapp.com/user/sergey6661313
    
    // about:
        // ScalpiEditor - ansi-only text editor for terminals.
        // killer features: no. its just editor.
    
    // Compile:
        // this file is just part of zig version (for now)
        // current version used zig compiller for compile zig file. (unstructions inside zig file)
        
        // in future you can use tcc for compile
        //     tcc se_windows.c
    
    // to support me
        // with boosty:
            // https://boosty.to/cutloosedev
        
        // with monero:
            // 87T7 qGbA TrM3 a6Br
            // DyeC jQQf NWtU u3iZ
            // bHVB MC6W mEbN NE13
            // Qrrt KhBb e4vF 58NR
            // 8PTF dYk2 Sozc HexX
            // 4Q69 jbdQ Asrs P7B

// imports
    // libC
        #include "stdarg.h"
        #include "stdbool.h"
        #include "stddef.h"
        #include "stdint.h"
        #include "stdio.h"
        #include "stdlib.h"
        
        #include "assert.h"
        #include "ctype.h"
        #include "errno.h"
        #include "fenv.h"
        #include "float.h"
        #include "inttypes.h"
        #include "iso646.h"
        #include "limits.h"
        #include "locale.h"
        #include "math.h"
        #include "setjmp.h"
        #include "signal.h"
        
        #include "string.h"
        #include "tgmath.h"
        #include "time.h"
        #include "uchar.h"
        #include "wchar.h"
        #include "wctype.h"
    
    #ifdef _WIN32
        // posix
            #include "fcntl.h"
        
        // Windows
            #include "windef.h"
            #include "windows.h"
            #include "winuser.h"
            #include "commctrl.h"
            #include "io.h"
            #include "conio.h"
        
        // network
            // #include "ws2tcpip.h"
            // #include "winsock2.h"
        
    #elif defined(__linux__)
        #include "sys/ioctl.h"
        #include "termios.h"
        #include "unistd.h"
        
        // network
            // #include "arpa/inet.h"
            // #include "netinet/in.h"
            // #include "netinet/ip.h"
            // #include "sys/socket.h"
    
    #endif

// enums and constants
    // core
        #define Endians_Little 1
        #define Endians_Big 2
    
    // time
        #define Scalpi_time_ms_per_s 1000

    // Scalpi_Logger_writers
        #define Scalpi_Logger_writers_c_out_writer 0
        #define Scalpi_Logger_writers_file_writer 1
        #define Scalpi_Logger_writers_console_writer 2
        #define Scalpi_Logger_writers_terminal_writer 3
    
    // Scalpi_Console_ansi
        #define Scalpi_Console_ansi_esc                          "\x1B"
        #define Scalpi_Console_ansi_control                      Scalpi_Console_ansi_esc "["
        #define Scalpi_Console_ansi_output_clear_to_end_line     Scalpi_Console_ansi_control "0K"
        #define Scalpi_Console_ansi_output_clear_to_start_line   Scalpi_Console_ansi_control "1K"
        #define Scalpi_Console_ansi_output_clear_line            Scalpi_Console_ansi_control "2K"
        
        // cursor
            #define Scalpi_Console_ansi_output_cursor_hide                     Scalpi_Console_ansi_control "?25l"
            #define Scalpi_Console_ansi_output_cursor_show                     Scalpi_Console_ansi_control "?25h"
            
            #define Scalpi_Console_ansi_output_cursor_style_reset              Scalpi_Console_ansi_control "0 q"
            #define Scalpi_Console_ansi_output_cursor_style_blinking_block     Scalpi_Console_ansi_control "1 q"
            #define Scalpi_Console_ansi_output_cursor_style_steady_block       Scalpi_Console_ansi_control "2 q"
            #define Scalpi_Console_ansi_output_cursor_style_blinking_underline Scalpi_Console_ansi_control "3 q"
            #define Scalpi_Console_ansi_output_cursor_style_steady_underline   Scalpi_Console_ansi_control "4 q"
            #define Scalpi_Console_ansi_output_cursor_style_blinking_I_beam    Scalpi_Console_ansi_control "5 q"
            #define Scalpi_Console_ansi_output_cursor_style_steady_I_beam      Scalpi_Console_ansi_control "6 q"
        
        // color
            #define Scalpi_Console_ansi_output_FontStyle_color_zero           "39"
            #define Scalpi_Console_ansi_output_FontStyle_color_black          "30"
            #define Scalpi_Console_ansi_output_FontStyle_color_red            "31"
            #define Scalpi_Console_ansi_output_FontStyle_color_green          "32"
            #define Scalpi_Console_ansi_output_FontStyle_color_gold           "33"
            #define Scalpi_Console_ansi_output_FontStyle_color_blue           "34"
            #define Scalpi_Console_ansi_output_FontStyle_color_magenta        "35"
            #define Scalpi_Console_ansi_output_FontStyle_color_cyan           "36"
            #define Scalpi_Console_ansi_output_FontStyle_color_light_gray     "37"
            
            #define Scalpi_Console_ansi_output_FontStyle_color_gray           "90"
            #define Scalpi_Console_ansi_output_FontStyle_color_pink           "91"
            #define Scalpi_Console_ansi_output_FontStyle_color_light_green    "92"
            #define Scalpi_Console_ansi_output_FontStyle_color_yellow         "93"
            #define Scalpi_Console_ansi_output_FontStyle_color_light_blue     "94"
            #define Scalpi_Console_ansi_output_FontStyle_color_light_magenta  "95"
            #define Scalpi_Console_ansi_output_FontStyle_color_light_cyan     "96"
            #define Scalpi_Console_ansi_output_FontStyle_color_white          "97"
            
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_zero            "49"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_black           "40"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_red             "41"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_green           "42"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_gold            "43"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_blue            "44"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_magenta         "45"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_cyan            "46"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_light_gray      "47"
            
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_gray            "100"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_pink            "101"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_light_green     "102"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_yellow          "103"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_light_blue      "104"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_light_magenta   "105"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_light_cyan      "106"
            #define Scalpi_Console_ansi_output_FontStyle_bg_color_white           "107"
            
            #define Scalpi_Console_ansi_output_FontStyle_sep                   ";"
            #define Scalpi_Console_ansi_output_FontStyle_end                   "m"
            #define Scalpi_Console_ansi_output_FontStyle_reset                 "0"
            #define Scalpi_Console_ansi_output_FontStyle_bold                  "1"
            #define Scalpi_Console_ansi_output_FontStyle_dim                   "2"
            #define Scalpi_Console_ansi_output_FontStyle_italic                "3"
            #define Scalpi_Console_ansi_output_FontStyle_underline             "4"
            #define Scalpi_Console_ansi_output_FontStyle_conceal               "8"
            #define Scalpi_Console_ansi_output_FontStyle_fraktur               "20"
            #define Scalpi_Console_ansi_output_FontStyle_unbold                "21;24"
            #define Scalpi_Console_ansi_output_FontStyle_set_color             "38"
            #define Scalpi_Console_ansi_output_FontStyle_set_bg_color          "48"
            
            #define Scalpi_Console_ansi_output_FontStyle_start                 Scalpi_Console_ansi_control
            #define Scalpi_Console_ansi_output_FontStyle_RESET                 Scalpi_Console_ansi_output_FontStyle_start Scalpi_Console_ansi_output_FontStyle_reset Scalpi_Console_ansi_output_FontStyle_end
        
        // mouse
            #define Scalpi_ansi_input_mouse_release  Scalpi_Console_ansi_control  "?1000l"
            #define Scalpi_ansi_input_mouse_grab     Scalpi_Console_ansi_control  "?1000h"
        
        #define Scalpi_Console_ansi_output_settings_enable_line_wrap   "\x1b[?7h"
        #define Scalpi_Console_ansi_output_settings_disable_line_wrap  "\x1b[?7l"
        
        // const Scalpi_Console_ansi_input_Key
            // ascii
                #define __Scalpi_Console_ansi_input_Key_ctrl_a__        1 /* start_of_heading */
                #define __Scalpi_Console_ansi_input_Key_ctrl_b__        2
                #define __Scalpi_Console_ansi_input_Key_ctrl_c__        3
                #define __Scalpi_Console_ansi_input_Key_ctrl_d__        4
                #define __Scalpi_Console_ansi_input_Key_ctrl_e__        5
                #define __Scalpi_Console_ansi_input_Key_ctrl_f__        6
                #define __Scalpi_Console_ansi_input_Key_ctrl_g__        7
                #define __Scalpi_Console_ansi_input_Key_ctrl_bs__       8 /* ctrl_h */
                #define __Scalpi_Console_ansi_input_Key_tab__           9 /* ctrl_i */
                #define __Scalpi_Console_ansi_input_Key_ctrl_j__        10
                #define __Scalpi_Console_ansi_input_Key_ctrl_k__        11 /* vertical_tab */
                #define __Scalpi_Console_ansi_input_Key_ctrl_l__        12 /* formFeed */
                #define __Scalpi_Console_ansi_input_Key_enter__         13 /* ctrl_m */
                #define __Scalpi_Console_ansi_input_Key_ctrl_n__        14
                #define __Scalpi_Console_ansi_input_Key_ctrl_o__        15
                #define __Scalpi_Console_ansi_input_Key_ctrl_p__        16
                #define __Scalpi_Console_ansi_input_Key_ctrl_q__        17
                #define __Scalpi_Console_ansi_input_Key_ctrl_r__        18
                #define __Scalpi_Console_ansi_input_Key_ctrl_s__        19
                #define __Scalpi_Console_ansi_input_Key_ctrl_t__        20
                #define __Scalpi_Console_ansi_input_Key_ctrl_u__        21
                #define __Scalpi_Console_ansi_input_Key_ctrl_v__        22
                #define __Scalpi_Console_ansi_input_Key_ctrl_w__        23
                #define __Scalpi_Console_ansi_input_Key_ctrl_x__        24
                #define __Scalpi_Console_ansi_input_Key_ctrl_y__        25
                #define __Scalpi_Console_ansi_input_Key_ctrl_z__        26
                #define __Scalpi_Console_ansi_input_Key_escape__        27
                #define __Scalpi_Console_ansi_input_Key_back_space__    127 /* sometime delete */
            
            #define __Scalpi_Console_ansi_input_Key_non_ascii__         256
                #define __Scalpi_Console_ansi_input_Key_mouse__         257
                
                // FN
                    #define __Scalpi_Console_ansi_input_Key_f1__        301
                    #define __Scalpi_Console_ansi_input_Key_f2__        302
                    #define __Scalpi_Console_ansi_input_Key_f3__        303
                    #define __Scalpi_Console_ansi_input_Key_f4__        304
                    #define __Scalpi_Console_ansi_input_Key_f5__        305
                    #define __Scalpi_Console_ansi_input_Key_f6__        306
                    #define __Scalpi_Console_ansi_input_Key_f7__        307
                    #define __Scalpi_Console_ansi_input_Key_f8__        308
                    #define __Scalpi_Console_ansi_input_Key_f9__        309
                    #define __Scalpi_Console_ansi_input_Key_f10__       310
                    #define __Scalpi_Console_ansi_input_Key_f11__       311
                    #define __Scalpi_Console_ansi_input_Key_f12__       312
                    
                    #define __Scalpi_Console_ansi_input_Key_f1_rxvt__   401
                    #define __Scalpi_Console_ansi_input_Key_f2_rxvt__   402
                    
                    #define __Scalpi_Console_ansi_input_Key_f1_tty__    501
                    #define __Scalpi_Console_ansi_input_Key_f2_tty__    502
                    #define __Scalpi_Console_ansi_input_Key_f3_tty__    503
                    #define __Scalpi_Console_ansi_input_Key_f4_tty__    504
                
                // arrows
                    
                    // left
                    #define __Scalpi_Console_ansi_input_Key_left__              1000
                    #define __Scalpi_Console_ansi_input_Key_ctrl_left__         1001
                    #define __Scalpi_Console_ansi_input_Key_ctrl_left_rxvt__    1002
                    #define __Scalpi_Console_ansi_input_Key_ctrl_shift_left__   1003
                    #define __Scalpi_Console_ansi_input_Key_shift_left__        1004
                    #define __Scalpi_Console_ansi_input_Key_alt_left__          1005
                    
                    // right
                    #define __Scalpi_Console_ansi_input_Key_right__             1100
                    #define __Scalpi_Console_ansi_input_Key_ctrl_right__        1101
                    #define __Scalpi_Console_ansi_input_Key_ctrl_right_rxvt__   1102
                    #define __Scalpi_Console_ansi_input_Key_ctrl_shift_right__  1103
                    #define __Scalpi_Console_ansi_input_Key_shift_right__       1104
                    #define __Scalpi_Console_ansi_input_Key_alt_right__         1105
                    
                    // up
                    #define __Scalpi_Console_ansi_input_Key_up__          1200
                    #define __Scalpi_Console_ansi_input_Key_ctrl_up__     1201
                    #define __Scalpi_Console_ansi_input_Key_shift_up__    1202
                    #define __Scalpi_Console_ansi_input_Key_alt_up__      1203
                    
                    // down
                    #define __Scalpi_Console_ansi_input_Key_down__          1300
                    #define __Scalpi_Console_ansi_input_Key_ctrl_down__     1301
                    #define __Scalpi_Console_ansi_input_Key_shift_down__    1302
                    #define __Scalpi_Console_ansi_input_Key_alt_down__      1303
                
                // spec keys
                    #define __Scalpi_Console_ansi_input_Key_delete__        1400
                    #define __Scalpi_Console_ansi_input_Key_shift_delete__  1401
                    
                    #define __Scalpi_Console_ansi_input_Key_page_up__    1402
                    #define __Scalpi_Console_ansi_input_Key_page_down__  1403
                    #define __Scalpi_Console_ansi_input_Key_end__        1404
                    #define __Scalpi_Console_ansi_input_Key_home__       1405
                
                #define __Scalpi_Console_ansi_input_Key_ctrl_enter__                            1501
                #define __Scalpi_Console_ansi_input_Key_ctrl_triangular_open_quotation_mark__   1502
                #define __Scalpi_Console_ansi_input_Key_ctrl_triangular_close_quotation_mark__  1503
                
                #define __Scalpi_Console_ansi_input_Key_ctrl_alt_v__  2000
                
                // altX
                    #define __Scalpi_Console_ansi_input_Key_alt_a__  3000
                    #define __Scalpi_Console_ansi_input_Key_alt_b__  3001
                    #define __Scalpi_Console_ansi_input_Key_alt_c__  3002
                    #define __Scalpi_Console_ansi_input_Key_alt_d__  3003
                    #define __Scalpi_Console_ansi_input_Key_alt_e__  3004
                    #define __Scalpi_Console_ansi_input_Key_alt_f__  3005
                    #define __Scalpi_Console_ansi_input_Key_alt_g__  3006
                    #define __Scalpi_Console_ansi_input_Key_alt_h__  3007
                    #define __Scalpi_Console_ansi_input_Key_alt_i__  3008
                    #define __Scalpi_Console_ansi_input_Key_alt_j__  3009
                    #define __Scalpi_Console_ansi_input_Key_alt_k__  3010
                    #define __Scalpi_Console_ansi_input_Key_alt_l__  3011
                    #define __Scalpi_Console_ansi_input_Key_alt_m__  3012
                    #define __Scalpi_Console_ansi_input_Key_alt_n__  3013
                    #define __Scalpi_Console_ansi_input_Key_alt_o__  3014
                    #define __Scalpi_Console_ansi_input_Key_alt_p__  3015
                    #define __Scalpi_Console_ansi_input_Key_alt_q__  3016
                    #define __Scalpi_Console_ansi_input_Key_alt_r__  3017
                    #define __Scalpi_Console_ansi_input_Key_alt_s__  3018
                    #define __Scalpi_Console_ansi_input_Key_alt_t__  3019
                    #define __Scalpi_Console_ansi_input_Key_alt_u__  3020
                    #define __Scalpi_Console_ansi_input_Key_alt_v__  3021
                    #define __Scalpi_Console_ansi_input_Key_alt_w__  3022
                    #define __Scalpi_Console_ansi_input_Key_alt_x__  3023
                    #define __Scalpi_Console_ansi_input_Key_alt_y__  3024
                    #define __Scalpi_Console_ansi_input_Key_alt_z__  3025
                
                // alt_shiftX,
                    #define __Scalpi_Console_ansi_input_Key_alt_M__  3100
                    #define __Scalpi_Console_ansi_input_Key_alt_N__  3101
                
                // altN
                    #define __Scalpi_Console_ansi_input_Key_alt_0__  3200
                    #define __Scalpi_Console_ansi_input_Key_alt_1__  3201
                    #define __Scalpi_Console_ansi_input_Key_alt_2__  3202
                    #define __Scalpi_Console_ansi_input_Key_alt_3__  3203
                    #define __Scalpi_Console_ansi_input_Key_alt_4__  3204
                    #define __Scalpi_Console_ansi_input_Key_alt_5__  3205
                    #define __Scalpi_Console_ansi_input_Key_alt_6__  3206
                    #define __Scalpi_Console_ansi_input_Key_alt_7__  3207
                    #define __Scalpi_Console_ansi_input_Key_alt_8__  3208
                    #define __Scalpi_Console_ansi_input_Key_alt_9__  3209
                
                // alt_spec
                    #define __Scalpi_Console_ansi_input_Key_alt_comma__          3301
                    #define __Scalpi_Console_ansi_input_Key_alt_comma_1__        3302
                    #define __Scalpi_Console_ansi_input_Key_alt_open_bracket__   3303
                    #define __Scalpi_Console_ansi_input_Key_alt_close_bracket__  3304
                    #define __Scalpi_Console_ansi_input_Key_alt_semicolon__      3305
                    #define __Scalpi_Console_ansi_input_Key_alt_apostrophe__     3306

// settings
    #define MEMORY_TYPE_ENDIANS Endians_Little
    
    #define __Scalpi_Terminal_Input_size__  32
    
    // App
        #define App_expected_fps 30

// macroses
    // c
        #define or ||
        #define and &&
        #define OFFSETOF(type, field) ((size_t) &(((type *)0)->field))
        #define FIELD_PARENT_PTR(type, field, instance) ((type *)((char *)(instance) - OFFSETOF(type, field)))
        #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
        #define TEXT_LEN(str) (ARRAY_LEN(str) - 1)

    // text
        #define SLICE_TEXT(text) {.ptr=text, .len=TEXT_LEN(text)}
        #define TEXT_PTR(text) (char(*)[TEXT_LEN(text)]) text
        #define DEF_TEXT_PTR(name, text) char(*name)[TEXT_LEN(text)] = TEXT_PTR(text)
        #define DEF_SLICE_TEXT(name, text) struct Slice name = SLICE_TEXT(text)


    // App
        #define App_delay_to_start_frame_target (Scalpi_time_ms_per_s / App_expected_fps)

// basic types
    typedef uint64_t Scalpi_Console_ansi_input_Key_t;

// structs
    // core
        // memory
            typedef size_t (*WriteFnPtr) (void* context, const char bytes[], size_t bytes_len);
            
            struct Slice {
                char* ptr;
                size_t len;
            };
            
            struct Finder {
                struct Slice text;
                struct Slice desired;
                size_t pos;
            };
    
    // Os
        struct Os_Console_Flags {
            bool inited;
            
            #ifdef _WIN32
                DWORD input_mode;
                DWORD output_mode;
            #elif defined(__linux__)
                struct termios termios;
            #endif
        };
        
        // Os_Console_Input_Handle
            #ifdef _WIN32
                typedef void* Os_Console_Input_Handle;
            #elif defined(__linux__)
                typedef FILE* Os_Console_Input_Handle;
            #endif
        
        struct Os_Console_Input {
            Os_Console_Input_Handle handle;
            #ifdef _WIN32
            #elif defined(__linux__)
                int fileno;
            #endif
        };
        
        // Os_Console_Output_Handle
            #ifdef _WIN32
                typedef void* Os_Console_Output_Handle;
            #elif defined(__linux__)
                typedef FILE* Os_Console_Output_Handle;
            #endif
        
        struct Os_Console_Output {
            Os_Console_Output_Handle handle;
            #ifdef _WIN32
            #elif defined(__linux__)
                int fileno;
            #endif
        };
        
    // Scalpi
        // text
            struct Scalpi_Text_Splitter {
                struct Finder finder;
                bool stop;
                size_t last_pos;
            };
        
        struct __Scalpi_Writer__ {
            void* context;
            WriteFnPtr write;
        };
        
        struct Scalpi_Logger {
            // write to terminal, console, file or to all together, but no real check "bytes is writen"
            struct __Scalpi_Writer__ writers[4] // Scalpi_Logger_writers
        };
        
        // Console
            // __Scalpi_Console_ansi_input_Key_SequenceParser__
                struct __Scalpi_Console_ansi_input_Key_SequenceParser__ {
                    Scalpi_Console_ansi_input_Key_t sequence;
                    size_t used;
                };
                
                struct Scalpi_Console_ansi_input_Key_SequenceParser_fromBytes_SequenceInfo {
                    const char* text;
                    size_t len;
                    Scalpi_Console_ansi_input_Key_t key;
                };
            
            struct __Scalpi_Console__ {
                struct Os_Console_Input input;
                struct Os_Console_Output output;
            };
        
        // Terminal
            struct __Scalpi_Terminal_Input__ {
                // usage:
                // call __Scalpi_Terminal_Input_update_buffer__ for update unreaded
                // use __Scalpi_Terminal_Input_grab__ in loop for get keys
                
                size_t ungrabed;
                char buffer[__Scalpi_Terminal_Input_size__];
            };
        
        
    // App
        struct App_Os_Helper {
            #ifdef _WIN32
                // WinApi 
                HINSTANCE instance;
                void* console_input_handle;
                void* console_output_handle;
                WSADATA wsdata;
            #endif
        };
        
        struct App {
            struct App_Os_Helper os_helper;
            struct Scalpi_Logger logger;
            uint64_t tick;
        };
    
// function prototypes

// globals
    struct App global_app;

// functions
    // core
        // mem
            // bits operations
                uint8_t bits_rotl8(uint8_t value, unsigned int shift) {
                    shift %= 8;
                    return (value << shift) | (value >> (8 - shift));
                }
                
                uint16_t bits_rotl16(uint16_t value, unsigned int shift) {
                    shift %= 16;
                    return (value << shift) | (value >> (16 - shift));
                }
                
                uint32_t bits_rotl32(uint32_t value, unsigned int shift) {
                    shift %= 32;
                    return (value << shift) | (value >> (32 - shift));
                }
                
                uint64_t bits_rotl64(uint64_t value, unsigned int shift) {
                    shift %= 64;
                    return (value << shift) | (value >> (64 - shift));
                }
            
            // bytes operations
                size_t Scalpi_mem_fill(char* dest, char symbol, size_t len) {
                    for (size_t pos = 0; pos < len; pos++) {
                        dest[pos] = symbol;
                    }
                }
                
                size_t Scalpi_mem_write(char* dest, char* src, size_t size) {
                    // i use this instead memcpy becouse clang-in-zig just replace memcpy to crash-zig-bloated-version code
                    size_t pos;
                    for(pos = 0; pos < size; pos++) {
                        dest[pos] = src[pos];
                    }
                    return pos;
                }
                
                bool Scalpi_mem_isEql(const char a[], const char b[], size_t len) {
                    for(size_t pos = 0; pos < len; pos ++) {
                        char ac = a[pos];
                        char bc = b[pos];
                        if (ac != bc) return false;
                    }
                    
                    return true;
                }
                
                void writeWithOffset(char* dest, size_t* writed, char* data, size_t data_len) {
                    *writed += Scalpi_mem_write(&dest[*writed], data, data_len);
                }
            
            // format_number
                // copy non aligned data
                    void memcpy2(char* dest, char* src) {
                        dest[0] = src[0];
                        dest[1] = src[1];
                    }
                    
                    void memcpy4(char* dest, char* src) {
                        dest[0] = src[0];
                        dest[1] = src[1];
                        dest[2] = src[2];
                        dest[3] = src[3];
                    }
                    
                    void memcpy8(char* dest, char* src) {
                        dest[0] = src[0];
                        dest[1] = src[1];
                        dest[2] = src[2];
                        dest[3] = src[3];
                        dest[4] = src[4];
                        dest[5] = src[5];
                        dest[6] = src[6];
                        dest[7] = src[7];
                    }
                
                // swap bytes for converting endians
                    void swapBytes16(char* a, char* b) {
                        // b is output
                        b[0] = a[1]; 
                        b[1] = a[0]; 
                    }
                    
                    void swapBytes32(char* a, char* b) {
                        // b is output
                        b[0] = a[3]; 
                        b[1] = a[2]; 
                        b[2] = a[1]; 
                        b[3] = a[0]; 
                    }
                    
                    void swapBytes64(char* a, char* b) {
                        // b is output
                        b[0] = a[7]; 
                        b[1] = a[6]; 
                        b[2] = a[5]; 
                        b[3] = a[4]; 
                        b[4] = a[3]; 
                        b[5] = a[2]; 
                        b[6] = a[1]; 
                        b[7] = a[0]; 
                    }
                
                bool cpu_checkNumberFormat() {
                    char current_endians = 0;
                    int n = 1;
                    if (* (char *) &n == 1) {
                        current_endians = Endians_Little;
                    } else {
                        current_endians = Endians_Big;
                    }
                    
                    if (MEMORY_TYPE_ENDIANS == current_endians) {
                        return true;
                    } else {
                        printf("%d wrong MEMORY_TYPE !\r\n", __LINE__);
                    }
                    return false;
                }
                
                #if MEMORY_TYPE_ENDIANS == Endians_Big
                    #define nativeToBig16(src, dest) memcpy2(dest, src)
                    #define nativeToBig32(src, dest) memcpy4(dest, src)
                    #define nativeToBig64(src, dest) memcpy8(dest, src)
                    
                    #define nativeToLittle16(src, dest) swapBytes16(src, dest)
                    #define nativeToLittle32(src, dest) swapBytes32(src, dest)
                    #define nativeToLittle64(src, dest) swapBytes64(src, dest)
                
                #elif MEMORY_TYPE_ENDIANS == Endians_Little
                    #define nativeToBig16(src, dest) swapBytes16(src, dest)
                    #define nativeToBig32(src, dest) swapBytes32(src, dest)
                    #define nativeToBig64(src, dest) swapBytes64(src, dest)
                    
                    #define nativeToLittle16(src, dest) memcpy2(dest, src)
                    #define nativeToLittle32(src, dest) memcpy4(dest, src)
                    #define nativeToLittle64(src, dest) memcpy8(dest, src)
                
                #else
                    #error "please define MEMORY_TYPE_ENDIANS with Endians_Big or Endians_Little. (you can test endings with cpu_checkNumberFormat function)"
                
                #endif
                
                // read unaligned memory
                    // big
                        uint16_t readBig16(char* src) {
                            uint16_t ret;
                            nativeToBig16(src, (char*) &ret);
                            return ret;
                        }
                        
                        uint32_t readBig32(char* src) {
                            uint32_t ret;
                            nativeToBig32(src, (char*) &ret);
                            return ret;
                        }
                        
                        uint64_t readBig64(char* src) {
                            uint64_t ret;
                            nativeToBig64(src, (char*) &ret);
                            return ret;
                        }
                    
                    // little
                        uint16_t readLittle16(char* src) {
                            uint16_t ret;
                            nativeToLittle16(src, (char*) &ret);
                            return ret;
                        }
                        
                        uint32_t readLittle32(char* src) {
                            uint32_t ret;
                            nativeToLittle32(src, (char*) &ret);
                            return ret;
                        }
                        
                        uint64_t readLittle64(char* src) {
                            uint64_t ret;
                            nativeToLittle64(src, (char*) &ret);
                            return ret;
                        }
                
                // write unaligned memory
                    // big
                        void writeBig16(uint16_t value, char* dest) {
                            nativeToBig16((char*)&value, dest);
                        }
                        
                        void writeBig32(uint32_t value, char* dest) {
                            nativeToBig32((char*)&value, dest);
                        }
                        
                        void writeBig64(uint64_t value, char* dest) {
                            nativeToBig64((char*)&value, dest);
                        }
                        
                    // little
                        void writeLittle16(uint16_t value, char* dest) {
                            nativeToLittle16((char*)&value, dest);
                        }
                        
                        void writeLittle32(uint32_t value, char* dest) {
                            nativeToLittle32((char*)&value, dest);
                        }
                        
                        void writeLittle64(uint64_t value, char* dest) {
                            nativeToLittle64((char*)&value, dest);
                        }
            
            // Slice
                void Slice_debug(struct Slice* slice, char* name, size_t line) {
                    if (slice->len == 0) {
                        printf("%zu: %s is NULL. \r\n", line, name);
                    } else {
                        printf("%zu: %s (%zu): \"%.*s", line, name, slice->len, (int)slice->len, slice->ptr);
                    }
                }
                
                bool Scalpi_mem_find(struct Slice* slice, struct Slice* desired, uintptr_t* out_pos) {
                    // not fast
                    
                    if (slice->len >= desired->len) {
                        uintptr_t last_pos = slice->len - desired->len;
                        for (uintptr_t pos = 0; pos <= last_pos; pos++) {
                            size_t slice_len = slice->len - pos;
                            if (slice_len >= desired->len) {
                                if (Scalpi_mem_isEql(&slice->ptr[pos], desired->ptr, desired->len)) {
                                    *out_pos = pos;
                                    return true;
                                }
                            } else {
                                break;
                            }
                        }
                    } else {
                        // printf("%d desired is too long\r\n", __LINE__);
                    }
                    return false;
                }
                
                bool isStartWith(struct Slice* a, struct Slice* b) {
                    return (a->len >= b->len) && Scalpi_mem_isEql(a->ptr, b->ptr, b->len);
                }
            
            // Finder
                void Finder_init(struct Finder* t, char* text, size_t text_len, char* desired, size_t desired_len) {
                    t->pos = 0;
                    t->text.ptr = text;
                    t->text.len = text_len;
                    t->desired.ptr = desired;
                    t->desired.len = desired_len;
                }
                
                bool Finder_next(struct Finder* t, size_t* out_pos) {
                    if (t->pos != t->text.len) {
                        struct Slice slice; // = t->text[->.pos..];
                            slice.ptr = &t->text.ptr[t->pos];
                            slice.len = t->text.len - t->pos;
                        size_t finded; 
                        if (Scalpi_mem_find(&slice, &t->desired, &finded)) {
                            size_t new_pos = t->pos + finded;
                            t->pos = new_pos + t->desired.len;
                            *out_pos = new_pos;
                            return true;
                        } 
                    }
                    return false;
                }
            
            // text Splitter
                void Scalpi_Text_Splitter_init(struct Scalpi_Text_Splitter* t, char* text, size_t text_len, char* delim, size_t delim_len) {
                    t->stop = false;
                    t->last_pos = 0;
                    Finder_init(&t->finder, text, text_len, delim, delim_len);
                }
                
                bool Scalpi_Text_Splitter_next(struct Scalpi_Text_Splitter* t, struct Slice* out_slice) {
                    if (t->stop == false) {
                        size_t finded;
                        if (Finder_next(&t->finder, &finded)) {
                            out_slice->ptr = &t->finder.text.ptr[t->last_pos]; // slice = t->finder.text[t->last_pos..finded];
                            out_slice->len = finded - t->last_pos; 
                            t->last_pos = t->finder.pos;
                            return true;
                        } else {
                            t->stop = true;
                            out_slice->ptr = &t->finder.text.ptr[t->last_pos]; // slice = t->finder.text[t->last_pos..];
                            out_slice->len = t->finder.text.len - t->last_pos; 
                            t->last_pos = t->finder.pos;
                            return true;
                        }
                    }
                    return false;
                }
        
        // math
            uint32_t ceilDiv32(uint32_t a, uint32_t b) {
                return (a + b - 1) / b;
            }
    
    // Os
        // time
            uint64_t os_getTick() {
                #ifdef _WIN32
                    FILETIME ft;
                    GetSystemTimeAsFileTime(&ft);
                    uint64_t ft64;
                    memcpy8((char*) &ft64, (void*)&ft);
                    return ft64 / 10000; // in ft is intervals * 100 ns. to ms need * 100 / 1000000
                #endif
                // TODO ME FOR LINUX
            }
        
        void Os_sleep(uint64_t ms) {
            #ifdef _WIN32
                Sleep(ms);
            #endif
            // TODO ME FOR LINUX
        }
        
        void Os_Console_Output_init(struct Os_Console_Output* output, Os_Console_Output_Handle handle) {
            output->handle = handle;
            #ifdef _WIN32
                // output->handle = GetStdHandle(c.STD_OUTPUT_HANDLE);
            #elif defined(__linux__)
                // output->handle = stdout
                output->fileno = fileno(output->handle);
            #endif
        }
        
        void Os_Console_Input_init(struct Os_Console_Input* input, Os_Console_Input_Handle handle) {
            input->handle = handle;
            #ifdef _WIN32
                // output->handle = GetStdHandle(c.STD_INPUT_HANDLE);
            #elif defined(__linux__)
                // output->handle = stdout
                input->fileno = fileno(input->handle);
            #endif
        }
        
        size_t Os_Console_Output_write(struct Os_Console_Output* output, const char* text, size_t len) {
            #ifdef _WIN32
                size_t writed = 0;
                WriteConsoleA(output->handle, text, len, &writed, 0);
            #elif defined(__linux__)
                //write(output->fileno, text, len);
                fwrite(text, sizeof(char), len, output->handle);
            #endif
            
            return len;
        }
    
    // Scalpi lib
        // C_Text
            size_t C_Text_getLen(const char text[]) {
                size_t len = 0;
                while(text[len] != 0) len++;
                return len;
            }
            
            size_t C_Text_writeToBuffer(char buffer[], char data[]) {
                const size_t len = C_Text_getLen(data);
                return Scalpi_mem_write(buffer, data, len);
            }
            
            size_t C_Text_writeToWriteFn(WriteFnPtr write, void* context, const char text[]) {
                const size_t len = C_Text_getLen(text);
                return write(context, text, len);
            }

        // Scalpi_Text_writeU64AsText
            #define Scalpi_Text_CharsDecFromU64_MAX_LEN  TEXT_LEN("18446744073709551615")
            
            size_t Scalpi_Text_writeU64AsTextToBuffer(char buffer[], uint64_t number, size_t min_width) { // utoa
                size_t writed = 0;
                
                // write number to tmp
                char buffer_tmp[Scalpi_Text_CharsDecFromU64_MAX_LEN];
                uintptr_t tmp_ptr = (uintptr_t) &buffer_tmp[0] + Scalpi_Text_CharsDecFromU64_MAX_LEN;
                for (uint64_t num = number; num > 0; num = num / 10) {
                    uint8_t remainder = num % 10;
                    tmp_ptr--;
                    *(char*)tmp_ptr = '0' + (char) remainder;
                }
                const uintptr_t writed_tmp = (uintptr_t) &buffer_tmp[0] + Scalpi_Text_CharsDecFromU64_MAX_LEN - (uintptr_t) tmp_ptr;
                
                // fill zeroes to min_width
                size_t extra_fill = 0;
                if (min_width > writed_tmp) {
                    extra_fill = min_width - writed_tmp;
                    writed += Scalpi_mem_fill(&buffer[0], '0', extra_fill);
                }
                
                if (writed_tmp > 0) writed += Scalpi_mem_write(&buffer[writed], (char*)tmp_ptr, writed_tmp);
                return writed;
            }
            
            size_t Scalpi_Text_writeU64AsTextToWriteFn(WriteFnPtr write, void* context, uint64_t number, size_t min_width) {
                char buffer_tmp[Scalpi_Text_CharsDecFromU64_MAX_LEN];
                const size_t writed = Scalpi_Text_writeU64AsTextToBuffer(buffer_tmp, number, min_width);
                return write(context, buffer_tmp, writed);
            }
        
        // Scalpi_Logger
            void Scalpi_Logger_init (struct Scalpi_Logger* t) {
                for (int i = 0; i < ARRAY_LEN(t->writers); i++) {
                    struct __Scalpi_Writer__* w = &t->writers[i];
                    w->context = 0;
                    w->write = 0;
                }
            }
            
            size_t Scalpi_Logger_writeToSelf(struct Scalpi_Logger* t, const char bytes[], size_t len) {
                for (size_t i = 0; i < ARRAY_LEN(t->writers); i++) {
                    struct __Scalpi_Writer__* w = &t->writers[i];
                    if (w->write) {
                        size_t writed = w->write(w->context, bytes, len);
                    }
                }
            }
    
    // App
        // struct App_Os_Helper
            bool App_Os_Helper_init(struct App_Os_Helper* os_helper) {
                #ifdef _WIN32
                    os_helper->instance = GetModuleHandleA(0);
                    if (os_helper->instance) { // enable network
                        return true;
                    }
                    FreeLibrary(os_helper->instance);
                    return false;
                #endif
                // TODO ME FOR LINUX
            }
            
            void App_Os_Helper_deinit(struct App_Os_Helper* os_helper) {
                #ifdef _WIN32
                    FreeLibrary(os_helper->instance);
                #endif
                // TODO ME FOR LINUX
            }
            
            void App_Os_Helper_process(struct App_Os_Helper* os_helper) {
                #ifdef _WIN32
                    MSG msg;
                    size_t message_count = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
                    if (message_count == 0) return;
                    TranslateMessage(&msg);
                    DispatchMessageA(&msg);
                #endif
                // TODO ME FOR LINUX
            }
        
        // struct App
            bool App_init(struct App* t) {
                Scalpi_Logger_init(&t->logger); // preinit console output for debug
                
                if (App_Os_Helper_init(&t->os_helper)) {
                    t->tick = os_getTick();
                    return true;
                    
                    // fallback
                    // App_Os_Helper_deinit(&t->os_helper);
                } else {
                    printf("%d app.os_helper not inited\r\n", __LINE__);
                }
                
                return false;
            }
            
            void App_deinit(struct App* app) {
                App_Os_Helper_deinit(&app->os_helper);
            }
            
            bool App_process(struct App* t) {
                App_Os_Helper_process(&t->os_helper);
                return true;
            }
            
            void App_waitToNextFrame(struct App* t) {
                uint64_t expected_frame_end_time = t->tick + App_delay_to_start_frame_target;
                uint64_t resulting_frame_end_time = os_getTick();
                if (resulting_frame_end_time > expected_frame_end_time + 120) {
                    uint64_t delta = resulting_frame_end_time - expected_frame_end_time;
                    printf("%d \t  hitch detection: %zu delta: %zu ms \r\n", __LINE__, t->tick, delta);
                }
                uint64_t delay_sleep = 1;
                if (resulting_frame_end_time < expected_frame_end_time) {
                    delay_sleep = expected_frame_end_time - resulting_frame_end_time;
                } 
                Os_sleep(delay_sleep);
                t->tick = resulting_frame_end_time + delay_sleep;
            }
    
    // main
        bool tests() {
            if ( true
                and cpu_checkNumberFormat()
                // and etc...
                // and etc...
            ) {
                return true;
            } else {
                printf("%d fail tests \r\n", __LINE__);
                return false;
            }
            
            return true;
        }
        
        bool real_main(int args_len, char** args_ptr) {
            if (tests()) {
                if (App_init(&global_app)) {
                    while(true) {
                        if (!App_process(&global_app)) break;
                        App_waitToNextFrame(&global_app);
                    }
                    App_deinit(&global_app);
                    return true;
                } else {
                    printf("%d fail: App_init\r\n", __LINE__);
                } 
            } else {
                printf("%d fail tests \r\n", __LINE__);
            }
            return false;
        }
        
        int main2(int args_len, char** args_ptr) {
            printf("ScalpiEditor ver: " __TIMESTAMP__ " \r\n");
            if (real_main(args_len, args_ptr)) return 0;
            return 1;
        }