Skip to content

Commit 9acf106

Browse files
authored
Merge pull request #208 from choco-technologies/copilot/add-standard-format-specifiers
Add missing standard printf format specifiers (l, h, hh, z, o)
2 parents a008a93 + 4148e32 commit 9acf106

4 files changed

Lines changed: 408 additions & 11 deletions

File tree

inc/private/dmod_prf.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,18 @@ extern "C" {
6262
* - %u: unsigned integer
6363
* - %x: hexadecimal (lowercase)
6464
* - %X: hexadecimal (uppercase)
65+
* - %o: octal
6566
* - %p: pointer
6667
* - %%: literal %
6768
*
6869
* Supported format modifiers:
6970
* - Width: Minimum field width (e.g., %30s for 30 characters)
7071
* - Left-align: '-' flag for left-justification (e.g., %-30s)
71-
* - Length modifier 'll': long long (64-bit) for d, i, u, x, X (e.g., %lld, %llu, %llx, %llX)
72+
* - Length modifier 'hh': char (8-bit) for d, i, u, x, X, o (e.g., %hhd, %hhu)
73+
* - Length modifier 'h': short (16-bit) for d, i, u, x, X, o (e.g., %hd, %hu)
74+
* - Length modifier 'l': long for d, i, u, x, X, o (e.g., %ld, %lu, %lx)
75+
* - Length modifier 'll': long long (64-bit) for d, i, u, x, X, o (e.g., %lld, %llu, %llx, %llX)
76+
* - Length modifier 'z': size_t for d, i, u, x, X, o (e.g., %zu, %zd, %zx)
7277
*/
7378
extern int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list Args );
7479

src/system/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ DMOD_SOURCES=private/dmod_vars.c\
3939
if/dmod_if_str.c\
4040
if/dmod_if_input.c\
4141
if/dmod_if_proc.c\
42-
Dmod.cpp
42+
Dmod.cpp\
43+
if/dmod_prf.c
4344
DMOD_INC_DIRS = $(DMOD_DIR)/src/system\
4445
$(DMOD_DIR)/inc\
4546
$(DMOD_BUILD_DIR)\

src/system/if/dmod_prf.c

Lines changed: 216 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <stddef.h>
3737
#include <stdint.h>
3838
#include <stdbool.h>
39+
#include <limits.h>
3940

4041
//==============================================================================
4142
// HELPER FUNCTIONS
@@ -308,6 +309,44 @@ static void Dmod_Print_Hex64( char** Buffer, size_t* Pos, size_t Size, uint64_t
308309
}
309310
}
310311

312+
static void Dmod_Print_Octal( char** Buffer, size_t* Pos, size_t Size, uint32_t Value, int* Count )
313+
{
314+
char Temp[12]; // Enough for 11 octal digits (32-bit)
315+
int i = 0;
316+
317+
// Convert to octal string (reversed)
318+
do
319+
{
320+
Temp[i++] = '0' + (Value & 0x7);
321+
Value >>= 3;
322+
} while( Value > 0 );
323+
324+
// Print in correct order
325+
while( i > 0 )
326+
{
327+
Dmod_Print_Char( Buffer, Pos, Size, Temp[--i], Count );
328+
}
329+
}
330+
331+
static void Dmod_Print_Octal64( char** Buffer, size_t* Pos, size_t Size, uint64_t Value, int* Count )
332+
{
333+
char Temp[23]; // Enough for 22 octal digits (64-bit)
334+
int i = 0;
335+
336+
// Convert to octal string (reversed)
337+
do
338+
{
339+
Temp[i++] = '0' + (Value & 0x7);
340+
Value >>= 3;
341+
} while( Value > 0 );
342+
343+
// Print in correct order
344+
while( i > 0 )
345+
{
346+
Dmod_Print_Char( Buffer, Pos, Size, Temp[--i], Count );
347+
}
348+
}
349+
311350
//==============================================================================
312351
// PUBLIC FUNCTIONS
313352
//==============================================================================
@@ -356,11 +395,47 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
356395
}
357396

358397
// Parse length modifier
359-
bool IsLongLong = false;
360-
if( *Format == 'l' && *(Format + 1) == 'l' )
398+
typedef enum {
399+
LEN_NONE, // default (int/unsigned int)
400+
LEN_HH, // char
401+
LEN_H, // short
402+
LEN_L, // long
403+
LEN_LL, // long long
404+
LEN_Z // size_t
405+
} LengthModifier;
406+
407+
LengthModifier LenMod = LEN_NONE;
408+
409+
if( *Format == 'h' )
361410
{
362-
IsLongLong = true;
363-
Format += 2;
411+
if( *(Format + 1) == 'h' )
412+
{
413+
LenMod = LEN_HH;
414+
Format += 2;
415+
}
416+
else
417+
{
418+
LenMod = LEN_H;
419+
Format++;
420+
}
421+
}
422+
else if( *Format == 'l' )
423+
{
424+
if( *(Format + 1) == 'l' )
425+
{
426+
LenMod = LEN_LL;
427+
Format += 2;
428+
}
429+
else
430+
{
431+
LenMod = LEN_L;
432+
Format++;
433+
}
434+
}
435+
else if( *Format == 'z' )
436+
{
437+
LenMod = LEN_Z;
438+
Format++;
364439
}
365440

366441
// Handle format specifiers
@@ -389,11 +464,33 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
389464

390465
case 'd':
391466
case 'i': {
392-
if( IsLongLong )
467+
if( LenMod == LEN_LL )
393468
{
394469
int64_t Value = va_arg( Args, int64_t );
395470
Dmod_Print_LongLong( BufPtr, &Pos, Size, Value, &Count );
396471
}
472+
else if( LenMod == LEN_L || LenMod == LEN_Z )
473+
{
474+
// long and size_t/ssize_t are typically same size
475+
long Value = va_arg( Args, long );
476+
#if LONG_MAX == INT64_MAX
477+
Dmod_Print_LongLong( BufPtr, &Pos, Size, (int64_t)Value, &Count );
478+
#else
479+
Dmod_Print_Int( BufPtr, &Pos, Size, (int32_t)Value, &Count );
480+
#endif
481+
}
482+
else if( LenMod == LEN_HH )
483+
{
484+
// char is promoted to int in varargs
485+
int Value = va_arg( Args, int );
486+
Dmod_Print_Int( BufPtr, &Pos, Size, (int32_t)(signed char)Value, &Count );
487+
}
488+
else if( LenMod == LEN_H )
489+
{
490+
// short is promoted to int in varargs
491+
int Value = va_arg( Args, int );
492+
Dmod_Print_Int( BufPtr, &Pos, Size, (int32_t)(short)Value, &Count );
493+
}
397494
else
398495
{
399496
int32_t Value = va_arg( Args, int32_t );
@@ -403,11 +500,33 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
403500
}
404501

405502
case 'u': {
406-
if( IsLongLong )
503+
if( LenMod == LEN_LL )
407504
{
408505
uint64_t Value = va_arg( Args, uint64_t );
409506
Dmod_Print_ULongLong( BufPtr, &Pos, Size, Value, &Count );
410507
}
508+
else if( LenMod == LEN_L || LenMod == LEN_Z )
509+
{
510+
// unsigned long and size_t are typically same size
511+
unsigned long Value = va_arg( Args, unsigned long );
512+
#if ULONG_MAX == UINT64_MAX
513+
Dmod_Print_ULongLong( BufPtr, &Pos, Size, (uint64_t)Value, &Count );
514+
#else
515+
Dmod_Print_UInt( BufPtr, &Pos, Size, (uint32_t)Value, &Count );
516+
#endif
517+
}
518+
else if( LenMod == LEN_HH )
519+
{
520+
// unsigned char is promoted to int in varargs
521+
unsigned int Value = va_arg( Args, unsigned int );
522+
Dmod_Print_UInt( BufPtr, &Pos, Size, (uint32_t)(unsigned char)Value, &Count );
523+
}
524+
else if( LenMod == LEN_H )
525+
{
526+
// unsigned short is promoted to int in varargs
527+
unsigned int Value = va_arg( Args, unsigned int );
528+
Dmod_Print_UInt( BufPtr, &Pos, Size, (uint32_t)(unsigned short)Value, &Count );
529+
}
411530
else
412531
{
413532
uint32_t Value = va_arg( Args, uint32_t );
@@ -417,11 +536,30 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
417536
}
418537

419538
case 'x': {
420-
if( IsLongLong )
539+
if( LenMod == LEN_LL )
421540
{
422541
uint64_t Value = va_arg( Args, uint64_t );
423542
Dmod_Print_Hex64( BufPtr, &Pos, Size, Value, false, &Count );
424543
}
544+
else if( LenMod == LEN_L || LenMod == LEN_Z )
545+
{
546+
unsigned long Value = va_arg( Args, unsigned long );
547+
#if ULONG_MAX == UINT64_MAX
548+
Dmod_Print_Hex64( BufPtr, &Pos, Size, (uint64_t)Value, false, &Count );
549+
#else
550+
Dmod_Print_Hex( BufPtr, &Pos, Size, (uint32_t)Value, false, &Count );
551+
#endif
552+
}
553+
else if( LenMod == LEN_HH )
554+
{
555+
unsigned int Value = va_arg( Args, unsigned int );
556+
Dmod_Print_Hex( BufPtr, &Pos, Size, (uint32_t)(unsigned char)Value, false, &Count );
557+
}
558+
else if( LenMod == LEN_H )
559+
{
560+
unsigned int Value = va_arg( Args, unsigned int );
561+
Dmod_Print_Hex( BufPtr, &Pos, Size, (uint32_t)(unsigned short)Value, false, &Count );
562+
}
425563
else
426564
{
427565
uint32_t Value = va_arg( Args, uint32_t );
@@ -431,11 +569,30 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
431569
}
432570

433571
case 'X': {
434-
if( IsLongLong )
572+
if( LenMod == LEN_LL )
435573
{
436574
uint64_t Value = va_arg( Args, uint64_t );
437575
Dmod_Print_Hex64( BufPtr, &Pos, Size, Value, true, &Count );
438576
}
577+
else if( LenMod == LEN_L || LenMod == LEN_Z )
578+
{
579+
unsigned long Value = va_arg( Args, unsigned long );
580+
#if ULONG_MAX == UINT64_MAX
581+
Dmod_Print_Hex64( BufPtr, &Pos, Size, (uint64_t)Value, true, &Count );
582+
#else
583+
Dmod_Print_Hex( BufPtr, &Pos, Size, (uint32_t)Value, true, &Count );
584+
#endif
585+
}
586+
else if( LenMod == LEN_HH )
587+
{
588+
unsigned int Value = va_arg( Args, unsigned int );
589+
Dmod_Print_Hex( BufPtr, &Pos, Size, (uint32_t)(unsigned char)Value, true, &Count );
590+
}
591+
else if( LenMod == LEN_H )
592+
{
593+
unsigned int Value = va_arg( Args, unsigned int );
594+
Dmod_Print_Hex( BufPtr, &Pos, Size, (uint32_t)(unsigned short)Value, true, &Count );
595+
}
439596
else
440597
{
441598
uint32_t Value = va_arg( Args, uint32_t );
@@ -444,6 +601,39 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
444601
break;
445602
}
446603

604+
case 'o': {
605+
if( LenMod == LEN_LL )
606+
{
607+
uint64_t Value = va_arg( Args, uint64_t );
608+
Dmod_Print_Octal64( BufPtr, &Pos, Size, Value, &Count );
609+
}
610+
else if( LenMod == LEN_L || LenMod == LEN_Z )
611+
{
612+
unsigned long Value = va_arg( Args, unsigned long );
613+
#if ULONG_MAX == UINT64_MAX
614+
Dmod_Print_Octal64( BufPtr, &Pos, Size, (uint64_t)Value, &Count );
615+
#else
616+
Dmod_Print_Octal( BufPtr, &Pos, Size, (uint32_t)Value, &Count );
617+
#endif
618+
}
619+
else if( LenMod == LEN_HH )
620+
{
621+
unsigned int Value = va_arg( Args, unsigned int );
622+
Dmod_Print_Octal( BufPtr, &Pos, Size, (uint32_t)(unsigned char)Value, &Count );
623+
}
624+
else if( LenMod == LEN_H )
625+
{
626+
unsigned int Value = va_arg( Args, unsigned int );
627+
Dmod_Print_Octal( BufPtr, &Pos, Size, (uint32_t)(unsigned short)Value, &Count );
628+
}
629+
else
630+
{
631+
uint32_t Value = va_arg( Args, uint32_t );
632+
Dmod_Print_Octal( BufPtr, &Pos, Size, Value, &Count );
633+
}
634+
break;
635+
}
636+
447637
case 'p': {
448638
void* Ptr = va_arg( Args, void* );
449639
Dmod_Print_Pointer( BufPtr, &Pos, Size, Ptr, &Count );
@@ -471,11 +661,28 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
471661
}
472662
}
473663
// Print length modifier if present
474-
if( IsLongLong )
664+
if( LenMod == LEN_HH )
665+
{
666+
Dmod_Print_Char( BufPtr, &Pos, Size, 'h', &Count );
667+
Dmod_Print_Char( BufPtr, &Pos, Size, 'h', &Count );
668+
}
669+
else if( LenMod == LEN_H )
670+
{
671+
Dmod_Print_Char( BufPtr, &Pos, Size, 'h', &Count );
672+
}
673+
else if( LenMod == LEN_L )
674+
{
675+
Dmod_Print_Char( BufPtr, &Pos, Size, 'l', &Count );
676+
}
677+
else if( LenMod == LEN_LL )
475678
{
476679
Dmod_Print_Char( BufPtr, &Pos, Size, 'l', &Count );
477680
Dmod_Print_Char( BufPtr, &Pos, Size, 'l', &Count );
478681
}
682+
else if( LenMod == LEN_Z )
683+
{
684+
Dmod_Print_Char( BufPtr, &Pos, Size, 'z', &Count );
685+
}
479686
Dmod_Print_Char( BufPtr, &Pos, Size, *Format, &Count );
480687
break;
481688
}

0 commit comments

Comments
 (0)