/** * debug.c * * Post Scarcity Software Environment: debugging messages. * * Print debugging output. * * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ #include #include #include "debug.h" #include "io/fopen.h" #include "io/io.h" #include "io/print.h" #include "memory/dump.h" int verbosity = 0; /** * @brief print this debug `message` to stderr, if `verbosity` matches `level`. * * `verbosity` is a set of flags, see debug_print.h; so you can * turn debugging on for only one part of the system. * * NOTE THAT: contrary to behaviour in the 0.0.X prototypes, a line feed is * always printed before a debug_print message. Hopefully this will result * in clearer formatting. * * @param message The message to be printed, in *wide* (32 bit) characters. * @param level a mask for `verbosity`. If a bitwise and of `verbosity` and * `level` is non-zero, print this `message`, else don't. * @param indent print `indent` spaces before the message. */ void debug_print( char32_t *message, int level, int indent ) { #ifdef DEBUG if ( level & verbosity ) { fwide( stderr, 1 ); fputws( L"\n", stderr ); for ( int i = 0; i < indent; i++ ) { fputws( L" ", stderr ); } fputws( message, stderr ); } #endif } /** * @brief print a 128 bit integer value to stderr, if `verbosity` matches `level`. * * `verbosity` is a set of flags, see debug_print.h; so you can * turn debugging on for only one part of the system. * * stolen from https://stackoverflow.com/questions/11656241/how-to-print-uint128-t-number-using-gcc * * @param n the large integer to print. * @param level a mask for `verbosity`. If a bitwise and of `verbosity` and * `level` is non-zero, print this `message`, else don't. */ void debug_print_128bit( __int128_t n, int level ) { #ifdef DEBUG if ( level & verbosity ) { if ( n == 0 ) { fwprintf( stderr, L"0" ); } else { char str[40] = { 0 }; // log10(1 << 128) + '\0' char *s = str + sizeof( str ) - 1; // start at the end while ( n != 0 ) { if ( s == str ) return; // never happens *--s = "0123456789"[n % 10]; // save last digit n /= 10; // drop it } fwprintf( stderr, L"%s", s ); } } #endif } /** * @brief print a line feed to stderr, if `verbosity` matches `level`. * * `verbosity` is a set of flags, see debug_print.h; so you can * turn debugging on for only one part of the system. * * @param level a mask for `verbosity`. If a bitwise and of `verbosity` and * `level` is non-zero, print this `message`, else don't. */ void debug_println( int level ) { #ifdef DEBUG if ( level & verbosity ) { fwide( stderr, 1 ); fputws( L"\n", stderr ); } #endif } /** * @brief `wprintf` adapted for the debug logging system. * * Print to stderr only if `verbosity` matches `level`. All other arguments * as for `wprintf`. * * @param level a mask for `verbosity`. If a bitwise and of `verbosity` and * `level` is non-zero, print this `message`, else don't. * @param indent print `indent` spaces before the message. * @param format Format string in *wide characters*, but otherwise as used by * `printf` and friends. * * Remaining arguments should match the slots in the format string. */ void debug_printf( int level, int indent, char32_t *format, ... ) { #ifdef DEBUG if ( level & verbosity ) { fwide( stderr, 1 ); for ( int i = 0; i < indent; i++ ) { fputws( L" ", stderr ); } va_list( args ); va_start( args, format ); vfwprintf( stderr, format, args ); } #endif } /** * @brief print the object indicated by this `pointer` to stderr, if `verbosity` * matches `level`. * * `verbosity` is a set of flags, see debug_print.h; so you can * turn debugging on for only one part of the system. */ void debug_print_object( struct pso_pointer pointer, int level, int indent ) { #ifdef DEBUG if ( level & verbosity ) { URL_FILE *ustderr = file_to_url_file( stderr ); fwide( stderr, 1 ); in_write( pointer, ustderr, PRINT_VARIANT_PRINT, indent ); free( ustderr ); } #endif } /** * @brief Like `dump_object`, q.v., but protected by the verbosity mechanism. * * `verbosity` is a set of flags, see debug_print.h; so you can * turn debugging on for only one part of the system. */ void debug_dump_object( struct pso_pointer pointer, int level, int indent ) { #ifdef DEBUG if ( level & verbosity ) { URL_FILE *ustderr = file_to_url_file( stderr ); fwide( stderr, 1 ); dump_object( pointer ); free( ustderr ); } #endif } ///** // * Standardise printing of binding trace messages. // */ //void debug_print_binding( struct cons_pointer key, struct cons_pointer val, // bool deep, int level, int indent ) { //#ifdef DEBUG // // char32_t * depth = (deep ? L"Deep" : L"Shallow"); // // debug_print( ( deep ? L"Deep" : L"Shallow" ), level, indent ); // debug_print( L" binding `", level, indent ); // debug_print_object( key, level, indent ); // debug_print( L"` to `", level, indent ); // debug_print_object( val, level, indent ); // debug_print( L"`\n", level, indent ); //#endif //}