from stdint import * import platmacro import memhub import stdio # Windows backend dependencies import w32.win32base import w32.win32process # POSIX backend dependencies import posix # Module global MBuddy pointer (initialized in user main), Plans to ban _mbuddy: memhub.MemBuddy* # ============================================================================= # C Standard Library IO Declarations # ============================================================================= extern def fgets(buf: bytes, size: int, stream: rawptr) -> str extern def fflush(stream: rawptr) -> int # C standard library exit (terminates the process after flushing the buffer, cross-platform) extern def exit(status: int) # ============================================================================= # Platform Information # ============================================================================= # Maximum integer value (64-bit platform ssize_t upper limit) define maxsize = 9223372036854775807 # 2^63 - 1 def platform() -> str: """Returns the platform identifier string ('win32' or 'linux').""" if platmacro.IS_WINDOWS: return "win32" return "linux" # ============================================================================= # Process Information # ============================================================================= def get_pid() -> int: """Return the current process ID""" if platmacro.IS_WINDOWS: return w32.win32process.GetCurrentProcessId() return posix.getpid() # ============================================================================= # Command Line Arguments (argv) # ============================================================================= # global argv status (initialized on first access) _argc: int = 0 _argv: str* def _init_argv(): """Initialize global argv once on first access""" global _argc, _argv if _argc != 0: return # Must dispatch with if/else: the compiler only translates call-expression statements; a ternary statement is dropped (argv stays empty) if platmacro.IS_WINDOWS: _init_argv_win32() else: _init_argv_posix() def _init_argv_win32(): """Windows: GetCommandLineA + manual parsing (handle spaces/double quotes/backslashes)""" global _argc, _argv cmdline: str = w32.win32base.GetCommandLineA() if cmdline == None: stdio.printf("ERROR: GetCommandLineA returned NULL, cannot obtain command line, argv will be empty\n") return cmdlen: sizet = len(cmdline) if cmdlen == 0: stdio.printf("ERROR: command line string is empty, cannot obtain arguments, argv will be empty\n") return # Allocate buffer for parameter strings (worst case: entire command line + argc \0s) buf: bytes = _mbuddy.alloc(cmdlen + 1) if buf == None: return # Allocate pointer array for argv (worst case: each character is a parameter) max_args: sizet = cmdlen + 1 argv_arr: str* = str*(_mbuddy.alloc(max_args * platmacro.SIZEOF_POINTER)) if argv_arr == None: return argc: int = 0 j: sizet = 0 in_quote: bool = False in_arg: bool = False for i in range(cmdlen): ch: int = cmdline[i] if ch == 34: # Double quote in_quote = not in_quote if not in_arg: argv_arr[argc] = str(buf + j) argc += 1 in_arg = True elif (ch == 32 or ch == 9) and not in_quote: # Space or Tab (outside quotes): parameter delimiter if in_arg: buf[j] = 0 j += 1 in_arg = False else: if not in_arg: argv_arr[argc] = str(buf + j) argc += 1 in_arg = True buf[j] = ch j += 1 if in_arg: buf[j] = 0 _argc = argc _argv = argv_arr def _init_argv_posix(): """POSIX: Read cmdline from /proc/self/cmdline (\0) separated parameters""" global _argc, _argv fd: int = posix.open("/proc/self/cmdline", posix.O_RDONLY, 0) if fd < 0: return # Read cmdline (4KB) buf: bytes = _mbuddy.alloc(4096) # Need to verify size of buffer if buf == None: posix.close(fd) return total: ssize_t = posix.read(fd, buf, 4096) posix.close(fd) if total <= 0: return # Calculate argument count (\0 delimited) argc: int = 0 total_size: sizet = sizet(total) for i in range(total_size): if buf[i] == 0: argc += 1 if argc == 0: return # Allocate pointer array for argv (argc pointers) argv_arr: str* = str*(_mbuddy.alloc(argc * platmacro.SIZEOF_POINTER)) if argv_arr == None: return # Populate pointer array (start address of each parameter) argv_arr[0] = str(buf) idx: int = 1 i = 0 while i < total_size and idx < argc: if buf[i] == 0: argv_arr[idx] = str(buf + i + 1) idx += 1 i += 1 _argc = argc _argv = argv_arr def argc() -> int: """Returns the number of command line arguments. Automatically initializes on the first call.""" if _argc == 0: _init_argv() return _argc def argv(index: int) -> str: """Returns the command line argument at index `index` (starting from 0). Automatically initializes on first call. Returns None if the index is out of range.""" if _argc == 0: _init_argv() if index < 0 or index >= _argc: return None return _argv[index]