kcpp / ICPP  -  the Internet C++ compiler and interpreter
========================================================
1.0.0+1fd1ecb   built 2026-09-23b

Copyright (c) 2026 Muhammad Anisur Rahman.  MIT License - see LICENSE.

kcpp is a C/C++ compiler toolchain. ICPP is a scripting language embedded in
it: C syntax you already know, plus one new thing - a '$var' typeless variable.
There is exactly ONE interpreter; icpp is a small launcher for it.


WHAT IS IN THIS DROP
--------------------
    windows-x64\bin\    kcpp.exe, icpp.exe, klink.exe, klib.exe, khex16.exe,
                         kice.exe, isqldll.dll
    linux-x64/bin/       kcpp, icpp, klink, klib, khex16, kice
    linux-x64/lib/       libisqldll.so.1  (+ libisqldll.so link, .tar.gz only)
    doc/                 ICPP_USER_MANUAL.md, ICPP_MANUAL.md, builtin list
    examples/            language / html / llm / fpga samples
                         (language/01_core_language.icpp and
                         10_dollar_var.icpp carry new checks)
    lib/                 ICPP libraries (stringutil.icpp)
    tools/               icpplint.py - checks a script against the $var
                         conventions in ICPP_MANUAL.md chapter 3

Both platforms are 64-bit, and both report the same version, because the
version is keyed to the source commit rather than to the build clock.

THE 32-BIT BUILD IS DISCONTINUED. The previous drop
(KCPP_ICPP_x86_2026-08-09.zip) was 32-bit and is no longer produced.

Take the .tar.gz on Linux, not the .zip: zip carries neither the executable
bit nor the symlink that libisqldll.so.1 is loaded through.

LINUX REQUIREMENTS
    glibc 2.36 or newer   (built on Debian 12; older systems will not load it)
    OpenSSL 3             libssl.so.3 and libcrypto.so.3

kcpp links OpenSSL 3. It is already present on most desktop installs, but a
minimal container image is usually missing it, and the failure is a loader
error before main() runs:

    kcpp: error while loading shared libraries: libssl.so.3: cannot open
    shared object file: No such file or directory

    Debian / Ubuntu     apt-get install -y libssl3
    Fedora / RHEL       dnf install -y openssl-libs
    Alpine              not supported - musl, not glibc

install.sh checks for it and says so before you hit that message.


INSTALL - WINDOWS
-----------------
    install.bat                     prompts for a directory (default C:\kcpp)
    install.bat D:\kcpp             install to a specific directory
    install.bat D:\kcpp /nopath     install without touching PATH
    install.bat D:\kcpp /system     register on the SYSTEM PATH (needs admin)

By default <home>\bin is added to your PER-USER PATH; no administrator rights
are needed. Open a new command prompt afterwards for it to take effect.


INSTALL - LINUX
---------------
    tar xzf KCPP_ICPP_x64_2026-09-23b.tar.gz
    cd KCPP_ICPP_x64_2026-09-23b
    ./install.sh                    installs into ~/.local/kcpp
    ./install.sh /opt/kcpp          installs somewhere else (may need sudo)

install.sh prints the two lines to add to your shell profile; it does not edit
it for you, because a script that rewrites a login file without asking is how
people lose their shells.


QUICK START
-----------
    icpp examples/language/01_core_language.icpp

    icpp yourscript.icpp            run a script
    kcpp -icpp yourscript.icpp      the same thing, spelled out
    kcpp -icpp -rtl yourscript.icpp translate to Verilog instead of running

icpp forwards every argument to kcpp, so any kcpp flag works through it.

    python tools/icpplint.py yourscript.icpp     check the $var conventions


WHAT CHANGED SINCE 2026-09-23
------------------------------
  * TLS, FROM A SCRIPT. icpp_https_get / icpp_https_post / icpp_https_status
    make one round trip in process, so a payment key lives in a $var instead
    of on a command line where ps can read it. The certificate AND the host
    name are verified. An HTTP error is not a transport failure: a 401 comes
    back with its body and its status, so a provider's own message is
    readable - "" with status 0 is the only "no answer".
  * AND THE GUARDS THAT MAKE THAT SAFE FROM A PAGE. Every call is bounded by
    ICPP_HTTPS_TIMEOUT_MS (default 30000; a value that does not parse keeps
    the default, and it never means "no timeout"), responses cap at 8 MB, and
    redirects are NOT followed, so an Authorization header is never replayed
    at whatever host a redirect named. A URL a page supplies cannot reach
    loopback, private, link-local or other reserved addresses - checked on
    the RESOLVED address, so a host name pointing at 127.0.0.1 does not walk
    through. ICPP_HTTPS_ALLOW_PRIVATE=1 opts out. Header lines carrying a CR
    or lacking a colon are dropped rather than repaired.
  * CIPHERS. icpp_hmac_sha256 (RFC 2104, so it agrees with every payment
    provider's hmac.new), icpp_pbkdf2 for storing a password, icpp_random_hex
    from the OS CSPRNG, and icpp_encrypt / icpp_decrypt (AES-256-GCM, which
    authenticates - a tampered blob is refused, never decrypted into
    rubbish). icpp_base64_encode / icpp_base64_decode are second NAMES on the
    existing base64 builtins, not second implementations.
    A Linux build made without the OpenSSL headers has no AES and returns ""
    rather than falling back to something weaker; hashing, HMAC, PBKDF2 and
    icpp_random_hex still work there.
  * A SCRIPT CAN BE CONFINED TO ONE DIRECTORY. Set ICPP_FILE_ROOT and every
    file a script opens must resolve inside it - all thirty script-reachable
    open sites go through one gate, and the path is resolved BEFORE it is
    compared, so neither .. nor a symlink walks out. Starting a process is
    refused while a root is set. Off unless you ask for it.
  * icpp_html_escape(s), and a long identifier no longer kills the process.
  * TWO EXAMPLES THAT RUN, in examples/security. Both are self-checking and
    need no network: crypto_basics.icpp (22 checks, published vectors where
    they exist) and https_request.icpp (8 checks, every one a refusal that
    happens before a packet leaves). doc/ICPP_USER_MANUAL.md gains sections
    4.31 and 4.32, and its index now lists all 248 builtins.
  * 409 conformance checks, passing on Windows and Linux, up from 346.
  * InternetSQL (isqldll.dll / libisqldll.so.1): engine 1.25, unchanged.
  * Every tool reports 1.0.0+1fd1ecb, the clean-tree stamp of the commit.

WHAT CHANGED SINCE 2026-09-21
-----------------------------
  * PYTHON, JAVA AND JSON RUN INSIDE ICPP, with nothing installed. The three
    libraries ship beside the tools (kpython, kjava, kjson) and load on first
    use. A value keeps its kind across languages, and all three share one
    symbol table with ICPP's $vars, so a number set in Python is a number in
    Java. See doc/ICPP_LANGUAGES_GUIDE.md, and examples/language/
    16_lang_sessions.icpp.
  * icpp_lang_limit(id, ms) caps how long one run may take, so a host can run
    source it did not write: "while True: pass" ends as an ordinary error
    instead of never returning.
  * EVERY OPERATOR THAT WAS BROKEN NOW WORKS. Logical not (!) in every form,
    ~x, float (it read 0 under -icpp), '+' joining strings, and every compound
    assignment (+= -= *= /= %= <<= >>= &= |= ^=), all of which crashed the
    interpreter. printf now does the standard C conversions, not only %d
    and %s. icpp_concat and isprint no longer cut their result at 4095 bytes.
  * AN ERROR DURING A RUN IS PRINTED INSTEAD OF KILLING THE PROCESS. The
    error log handle is NULL while interpreting, and every Display* function
    wrote to it unconditionally - so any diagnostic the interpreter tried to
    give died inside the call that was giving it. That is why a call to a
    function ICPP could not find looked like a crash in the statement.
  * A SOURCE LINE MAY BE 64 KB. Any line over about 4 KB used to corrupt the
    heap while being READ, with no message - a long string literal, or simply
    a long expression. A line at or past 65535 bytes is reported, not fatal.
  * A LONG IDENTIFIER no longer kills the process: names are capped at 255
    characters and a longer one is reported.
  * DEFINITION ORDER, stated plainly for the first time in the manual: ICPP
    has no forward declarations. A forward call with no arguments works; one
    WITH arguments is reported, naming the function and saying to move it.
    It used to be a silent death. See doc/ICPP_USER_MANUAL.md.
  * 346 conformance checks, passing on Windows and Linux, up from 204.
  * InternetSQL (isqldll.dll / libisqldll.so.1): engine 1.25, unchanged from
    2026-09-21.
  * Every tool reports 1.0.0+6bb5e8f, the clean-tree stamp of the commit.

WHAT CHANGED SINCE 2026-09-17
-----------------------------
  * ICPP: new builtin icpp_sql_connect_remote(host, port, user, password
    [, database]) - a client of a running isqlserverd, where icpp_sql_connect
    is embedded-only. Windows and Linux. It never hangs: the host is probed
    with a 3-second timeout first, because the engine's own connect has none.
    Credentials containing ; ' , or a control character are refused, not
    escaped. An ordinary account must pass its database. 227 builtins now;
    see doc/ICPP_USER_MANUAL.md 4.4.
  * ICPP: a negative argument to a user function - g(-5) - crashed the
    interpreter with no output. Fixed.
  * ICPP: a $var named like a keyword - $do, $for, $int, $return - did not
    compile. Every word right after a '$' is now a name.
  * ICPP: icpp_sql_status(conn) returned about a thousand bytes of
    uninitialised memory after a good query. It returns the last statement's
    message now.
  * ICPP, BEHAVIOUR CHANGE: a $var beside a typed variable of the same name
    - int aid; ... $aid - used to share one value, and both read 0. $aid is
    now its own variable. Declare the typed one FIRST: '$aid = 7; int aid;'
    is now a compile error naming both. See doc/ICPP_MANUAL.md section 4.
  * Still open, with workarounds in doc/ICPP_MANUAL.md section 4: every float
    reads as 0 under -icpp (use double); logical not (!) fails in every form
    (write '== 0'); ~x crashes (x ^ -1); $s + "y" (icpp_concat).
  * InternetSQL (isqldll.dll / libisqldll.so.1): engine 1.25 of 2026-09-20.3.
  * Every tool reports 1.0.0+d87c4aa, the clean-tree stamp of the commit.

WHAT CHANGED SINCE 2026-08-29
-----------------------------
  * ICPP: icpp_search_txt(needle, buffer) - the 0-based position of needle
    in buffer ignoring case, or -1. Note the order: the text searched FOR
    comes first. 226 builtins now; see doc/ICPP_USER_MANUAL.md 4.2.
  * ICPP: a string returned by a builtin is copied before the next builtin
    runs. Two calls in one expression - or a value kept in a $var across a
    later call - used to see the second call's buffer instead of their own.
  * ICPP: icpp_substr(s, start, 0) returns "" rather than the rest of s.
  * ICPP: a $var whose name matched a function's returned the function's
    prototype instead of the value.
  * ICPP: -icppquiet also silences the #include bookkeeping, so an embedded
    page that includes a helper prints only its own output.
  * InternetSQL (isqldll.dll / libisqldll.so.1, engine 1.25 of 2026-09-17):
      - WHERE <column> CONTAINS 'text' - case-insensitive substring match
        on char, text and storage columns, INCLUDING the text of a PDF held
        in a storage column, which the engine now extracts itself.
      - UPDATE ... SET n = n + x on a number(p,s) column keeps the declared
        scale; it used to round to a whole number.
  * Every tool in this drop reports 1.0.0+09ef8da - the clean-tree stamp of
    the commit it was built from. The previous drop's Linux tools said
    "nogit-dirty" because they were built from an exported tree.

WHAT CHANGED SINCE 2026-08-09
-----------------------------
  * ICPP: a '$var' holding a string now owns its bytes. It used to store the
    right-hand side's pointer, so a value from a query or a concat silently
    became garbage when the next call reused that buffer.
  * ICPP: '$var' works as an unbraced for / while / do / if / else body, and
    inside switch arms. Those cases used to reach the code generator from the
    interpreter and crash.
  * ICPP: the ternary ?: read the condition's address instead of its value.
  * InternetSQL: LIKE '%term%' matches. The matcher could not step over the
    character a wildcard had matched, so only ONE literal could follow a '%':
    '%a%' worked and '%ab%' could never match, while '%aa%' matched any text
    holding a single 'a'. It also could not backtrack. Both the table scan and
    the index scan used it, so NOT LIKE was wrong in the mirrored way.
  * The version stamp is trustworthy: gen_version no longer counts the file it
    writes as an uncommitted change, so a clean tree finally reports clean.
  * icpp_strcmp no longer answers "equal" to a comparison it could not make.
    It requires both operands to be strings, and an unassigned $var is the
    number zero, so the old default of 0 meant

        if (icpp_strcmp($role, "admin") == 0) { ... }

    passed whenever $role was misspelled or unset. It now returns -1, which is
    non-zero, still negative for ordering, and still inside the documented
    -1/0/1 contract. icpp_version_cmp had the same defect. If you have an
    older build and a guard shaped like the line above, check it.
  * The parser no longer corrupts its own heap on a string literal longer than
    the token buffer; it reports the literal as too long instead.
