#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
HANDLE inHandle = INVALID_HANDLE_VALUE;
HANDLE outHandle = INVALID_HANDLE_VALUE;
#else
#include <unistd.h>
#endif
int stdoutFunction(const char* buffer, size_t bufferSize) {
#ifdef _WIN32
int bytesWritten = 0;
WriteConsoleA(outHandle, buffer, bufferSize, &bytesWritten, NULL);
return bytesWritten;
#else
return write(1, buffer, bufferSize);
#endif
}
size_t copyAscii(char* buffer, const char* src, size_t charSize, size_t bufferIdx, const size_t maxBufferIdx) {
for (; *src != '\0'; src += charSize) {
buffer[bufferIdx] = *src;
bufferIdx += (bufferIdx < maxBufferIdx);
}
return bufferIdx;
}
size_t intToHexStr(char* buffer, const size_t n, size_t bufferIdx, const size_t maxBufferIdx) {
const char hexCharacters[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
for (int32_t shiftRightBy = (sizeof(size_t) * 8) - 4; shiftRightBy >= 0; shiftRightBy -= 4) {
buffer[bufferIdx] = hexCharacters[(n >> shiftRightBy) % 16];
bufferIdx += (bufferIdx < maxBufferIdx);
}
return bufferIdx;
}
size_t intToStr(char* buffer, size_t n, size_t bufferIdx, const size_t maxBufferIdx) {
size_t frontIdx = bufferIdx;
do {
buffer[bufferIdx] = '0' + (n % 10);
bufferIdx += (bufferIdx < maxBufferIdx);
n /= 10;
} while (n > 0);
size_t backIdx = bufferIdx - 1;
while (frontIdx < backIdx) {
char tmp = buffer[frontIdx];
buffer[frontIdx] = buffer[backIdx];
buffer[backIdx] = tmp;
frontIdx += 1;
backIdx -= 1;
}
return bufferIdx;
}
// working format specifiers: s, ls, d, u, zu, x, %
int dumberPrintf(const char* fmt, ...) {
if (fmt[0] == '\0') {
return 0;
}
char buffer[512];
size_t bufferIdx = 0;
size_t maxBufferIdx = sizeof(buffer) - 1;
va_list args;
va_start(args, fmt);
for (size_t fmtIdx = 0; fmt[fmtIdx] != '\0'; fmtIdx++) {
if (fmt[fmtIdx] == '%') {
if (
fmt[fmtIdx + 1] == 's'
|| (fmt[fmtIdx + 1] == 'l' && fmt[fmtIdx + 2] == 's')
) {
bufferIdx = copyAscii(
buffer,
fmt[fmtIdx + 1] == 's' ? va_arg(args, char*) : (char*)va_arg(args, wchar_t*),
fmt[fmtIdx + 1] == 's' ? sizeof(char) : sizeof(wchar_t),
bufferIdx,
maxBufferIdx
);
fmtIdx += (fmt[fmtIdx + 1] == 'l');
}
else if (
fmt[fmtIdx + 1] == 'd'
|| fmt[fmtIdx + 1] == 'u'
|| (fmt[fmtIdx + 1] == 'z' && fmt[fmtIdx + 2] == 'u')
) {
bufferIdx = intToStr(buffer, va_arg(args, size_t), bufferIdx, maxBufferIdx);
fmtIdx += (fmt[fmtIdx + 1] == 'z');
}
else if (fmt[fmtIdx + 1] == 'x') {
bufferIdx = intToHexStr(buffer, va_arg(args, size_t), bufferIdx, maxBufferIdx);
}
else {
buffer[bufferIdx] = '%';
bufferIdx += (bufferIdx < maxBufferIdx);
}
fmtIdx += 1;
}
else {
buffer[bufferIdx] = fmt[fmtIdx];
bufferIdx += (bufferIdx < maxBufferIdx);
}
}
va_end(args);
return stdoutFunction(buffer, bufferIdx);
}
int main() {
#ifdef _WIN32
inHandle = GetStdHandle(STD_INPUT_HANDLE);
outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (inHandle == INVALID_HANDLE_VALUE || outHandle == INVALID_HANDLE_VALUE) {
return GetLastError();
}
#endif
dumberPrintf("%%s test: %s\n%%ls test: %ls\n%%d test: %d\n%%u test: %u\n%%zu test: %zu\n%%x test: %x\n",
"char string",
L"wchar_t string",
12345,
54321,
56789,
0xabcdef
);
return 0;
}
/*
int __stdcall mainCRTStartup() {
int result = main();
return result;
}
*/
I'm making something which I'm going to update to not use any C runtime functions, including printf. I'm going to compile with /NODEFAULTLIB. I made this function to imitate printf. It works with the format specifiers s, ls, d, u, zu, x, and %. It's not expected to print any negative numbers. It's also not expected to print anything longer than 512 bytes, so it cuts off anything beyond that length.
printfthen just... Use that and don't passNODEFAULTLIB. \$\endgroup\$