diff --git a/CMakeLists.txt b/CMakeLists.txt index b7432e3..f294a1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(fun VERSION 0.16.1 LANGUAGES C) +project(fun VERSION 0.16.2 LANGUAGES C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/examples/crc32_demo.fun b/examples/crc32_demo.fun deleted file mode 100755 index 4b89d9a..0000000 --- a/examples/crc32_demo.fun +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env fun - -/* - * This file is part of the Fun programming language. - * https://hanez.org/project/fun/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-09-29 - */ - -// Include the pure Fun CRC32 library -include "lib/crypt/crc32.fun" - -// Create a Class-typed instance to prevent accidental shadowing -Class c32 = CRC32() -print(typeof(c32)) // should be "Class" - -print("=== CRC32 demo (hex input) ===") - -// "" (empty) -> 00000000 -print(c32.crc32_hex("")) - - // "abc" -> 352441c2 -print(c32.crc32_hex("616263")) - -// "123456789" -> cbf43926 -print(c32.crc32_hex("313233343536373839")) - -print("=== Done ===") diff --git a/examples/md5_demo.fun b/examples/md5_demo.fun index 7ef6aa7..6f63169 100755 --- a/examples/md5_demo.fun +++ b/examples/md5_demo.fun @@ -12,7 +12,7 @@ */ // Include the pure Fun MD5 library -include "lib/crypt/md5.fun" +include // create a hasher instance md5 = MD5() @@ -31,4 +31,7 @@ print(md5.md5_hex("6d65737361676520646967657374")) // -> f96b697d7cb7938d525a2f // "abcdefghijklmnopqrstuvwxyz" print(md5.md5_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> c3fcd3d76192e4007dfb496cca67e13b +// "Have Fun!" +print(md5.md5_str("Have Fun!")) // -> + print("=== Done ===") diff --git a/examples/sha1_demo.fun b/examples/sha1_demo.fun old mode 100644 new mode 100755 diff --git a/examples/sha256_demo.fun b/examples/sha256_demo.fun index 1365aa1..60f7cc5 100755 --- a/examples/sha256_demo.fun +++ b/examples/sha256_demo.fun @@ -12,7 +12,7 @@ */ // Include the pure Fun SHA-256 library -include "lib/crypt/sha256.fun" +include sha = SHA256() diff --git a/examples/sha256_str_demo.fun b/examples/sha256_str_demo.fun index c18c653..48f75d2 100755 --- a/examples/sha256_str_demo.fun +++ b/examples/sha256_str_demo.fun @@ -12,7 +12,7 @@ */ // Demo: SHA-256 of raw strings (no hex decoding) -include "lib/crypt/sha256.fun" +include sha = SHA256() diff --git a/examples/sha512_demo.fun b/examples/sha512_demo.fun index 63437eb..c630bc6 100755 --- a/examples/sha512_demo.fun +++ b/examples/sha512_demo.fun @@ -11,7 +11,7 @@ * Added: 2025-09-29 */ -include "lib/crypt/sha512.fun" +include sha = SHA512() diff --git a/examples/sha512_str_demo.fun b/examples/sha512_str_demo.fun index b2e058f..4eac385 100755 --- a/examples/sha512_str_demo.fun +++ b/examples/sha512_str_demo.fun @@ -12,7 +12,7 @@ */ // Demo: SHA-512 of raw strings (no hex decoding) -include "lib/crypt/sha512.fun" +include sha = SHA512() diff --git a/lib/crypt/md5.fun b/lib/crypt/md5.fun index 82cb3e7..c4d66bc 100644 --- a/lib/crypt/md5.fun +++ b/lib/crypt/md5.fun @@ -277,6 +277,9 @@ fun md5_hex(hexStr) // Class wrapper to avoid global name collisions and show class usage */ + +#include + class MD5() // MD5 constants (as fields) K = [ @@ -517,3 +520,8 @@ class MD5() bytes = this.from_hex(hexStr) digest = this.md5_bytes(bytes) return this.bytes_to_hex(digest) + + fun md5_str(this, str) + bytes = string_to_bytes_ascii(str) + digest = this.md5_bytes(bytes) + return this.bytes_to_hex(digest) diff --git a/lib/crypt/sha1.fun b/lib/crypt/sha1.fun index 1e41d0b..907ed4b 100644 --- a/lib/crypt/sha1.fun +++ b/lib/crypt/sha1.fun @@ -17,6 +17,8 @@ // sha.sha1_hex(hexStr) -> digest hex string (lowercase) // sha.sha1_str("abc") -> digest hex string of ASCII bytes +#include + class SHA1() // 32-bit helpers fun u32(this, x) @@ -207,59 +209,7 @@ class SHA1() digest = this.sha1_bytes(bytes) return this.bytes_to_hex(digest) - // ASCII string to bytes (printable ASCII 0x20..0x7E) - fun string_to_bytes_ascii(this, s) - str = to_string(s) - out = [] - number i = 0 - // ASCII printable ranges - P1 = " !\"#$%&'()*+,-./" // 32..47 - P2 = "0123456789" // 48..57 - P3 = ":;<=>?@" // 58..64 - P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90 - P5 = "[\\]^_`" // 91..96 - P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122 - P7 = "{|}~" // 123..126 - while true - ch = substr(str, i, 1) - if (typeof(ch) != "String" || ch == "") - break - number code = -1 - idx = find(P1, ch) - if (idx >= 0) - code = 32 + idx - else - idx = find(P2, ch) - if (idx >= 0) - code = 48 + idx - else - idx = find(P3, ch) - if (idx >= 0) - code = 58 + idx - else - idx = find(P4, ch) - if (idx >= 0) - code = 65 + idx - else - idx = find(P5, ch) - if (idx >= 0) - code = 91 + idx - else - idx = find(P6, ch) - if (idx >= 0) - code = 97 + idx - else - idx = find(P7, ch) - if (idx >= 0) - code = 123 + idx - else - // non-printable -> 0 - code = 0 - push(out, code) - i = i + 1 - return out - fun sha1_str(this, str) - bytes = this.string_to_bytes_ascii(str) + bytes = string_to_bytes_ascii(str) digest = this.sha1_bytes(bytes) return this.bytes_to_hex(digest) diff --git a/lib/crypt/sha256.fun b/lib/crypt/sha256.fun index 17d657c..b53c25b 100644 --- a/lib/crypt/sha256.fun +++ b/lib/crypt/sha256.fun @@ -19,6 +19,8 @@ // Example: // print(SHA256().sha256_hex("616263")) // "abc" => ba7816bf... +#include + class SHA256() // 32-bit helpers fun u32(this, x) @@ -260,60 +262,8 @@ class SHA256() digest = this.sha256_bytes(bytes) return this.bytes_to_hex(digest) - // Convert a printable ASCII string (0x20..0x7E) to byte array - fun string_to_bytes_ascii(this, s) - str = to_string(s) - out = [] - number i = 0 - // ASCII printable ranges - P1 = " !\"#$%&'()*+,-./" // 32..47 - P2 = "0123456789" // 48..57 - P3 = ":;<=>?@" // 58..64 - P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90 - P5 = "[\\]^_`" // 91..96 - P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122 - P7 = "{|}~" // 123..126 - while true - ch = substr(str, i, 1) - if (typeof(ch) != "String" || ch == "") - break - number code = -1 - idx = find(P1, ch) - if (idx >= 0) - code = 32 + idx - else - idx = find(P2, ch) - if (idx >= 0) - code = 48 + idx - else - idx = find(P3, ch) - if (idx >= 0) - code = 58 + idx - else - idx = find(P4, ch) - if (idx >= 0) - code = 65 + idx - else - idx = find(P5, ch) - if (idx >= 0) - code = 91 + idx - else - idx = find(P6, ch) - if (idx >= 0) - code = 97 + idx - else - idx = find(P7, ch) - if (idx >= 0) - code = 123 + idx - else - // non-printable -> 0 - code = 0 - push(out, code) - i = i + 1 - return out - // Hash raw string bytes (printable ASCII). Example: sha256_str("616263") -> ee2109... fun sha256_str(this, str) - bytes = this.string_to_bytes_ascii(str) + bytes = string_to_bytes_ascii(str) digest = this.sha256_bytes(bytes) return this.bytes_to_hex(digest) diff --git a/lib/crypt/sha512.fun b/lib/crypt/sha512.fun index c565143..63995eb 100644 --- a/lib/crypt/sha512.fun +++ b/lib/crypt/sha512.fun @@ -24,6 +24,8 @@ // ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a // 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f +#include + class SHA512() // -------- hex helpers -------- fun hex_val(this, ch) @@ -360,60 +362,8 @@ class SHA512() digest = this.sha512_bytes(bytes) return this.bytes_to_hex(digest) - // Convert a printable ASCII string (0x20..0x7E) to byte array - fun string_to_bytes_ascii(this, s) - str = to_string(s) - out = [] - number i = 0 - // ASCII printable ranges - P1 = " !\"#$%&'()*+,-./" // 32..47 - P2 = "0123456789" // 48..57 - P3 = ":;<=>?@" // 58..64 - P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90 - P5 = "[\\]^_`" // 91..96 - P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122 - P7 = "{|}~" // 123..126 - while true - ch = substr(str, i, 1) - if (typeof(ch) != "String" || ch == "") - break - number code = -1 - idx = find(P1, ch) - if (idx >= 0) - code = 32 + idx - else - idx = find(P2, ch) - if (idx >= 0) - code = 48 + idx - else - idx = find(P3, ch) - if (idx >= 0) - code = 58 + idx - else - idx = find(P4, ch) - if (idx >= 0) - code = 65 + idx - else - idx = find(P5, ch) - if (idx >= 0) - code = 91 + idx - else - idx = find(P6, ch) - if (idx >= 0) - code = 97 + idx - else - idx = find(P7, ch) - if (idx >= 0) - code = 123 + idx - else - // non-printable -> 0 - code = 0 - push(out, code) - i = i + 1 - return out - // Hash raw string bytes (printable ASCII). Example: sha512_str("616263") -> ee2109... fun sha512_str(this, str) - bytes = this.string_to_bytes_ascii(str) + bytes = string_to_bytes_ascii(str) digest = this.sha512_bytes(bytes) return this.bytes_to_hex(digest) diff --git a/lib/strings.fun b/lib/strings.fun new file mode 100644 index 0000000..9057910 --- /dev/null +++ b/lib/strings.fun @@ -0,0 +1,62 @@ + /* + * This file is part of the Fun programming language. + * https://hanez.org/project/fun/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2025-10-01 + */ + +// ASCII string to bytes (printable ASCII 0x20..0x7E) +fun string_to_bytes_ascii(this, s) + str = to_string(s) + out = [] + number i = 0 + // ASCII printable ranges + P1 = " !\"#$%&'()*+,-./" // 32..47 + P2 = "0123456789" // 48..57 + P3 = ":;<=>?@" // 58..64 + P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90 + P5 = "[\\]^_`" // 91..96 + P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122 + P7 = "{|}~" // 123..126 + while true + ch = substr(str, i, 1) + if (typeof(ch) != "String" || ch == "") + break + number code = -1 + idx = find(P1, ch) + if (idx >= 0) + code = 32 + idx + else + idx = find(P2, ch) + if (idx >= 0) + code = 48 + idx + else + idx = find(P3, ch) + if (idx >= 0) + code = 58 + idx + else + idx = find(P4, ch) + if (idx >= 0) + code = 65 + idx + else + idx = find(P5, ch) + if (idx >= 0) + code = 91 + idx + else + idx = find(P6, ch) + if (idx >= 0) + code = 97 + idx + else + idx = find(P7, ch) + if (idx >= 0) + code = 123 + idx + else + // non-printable -> 0 + code = 0 + push(out, code) + i = i + 1 + return out