/* * color_printf.h * * printf() cagrilarindaki her degeri (mesaj metnini degil) kendi * "kimligine" gore renklendirir: * * - Ayni degisken (ornegin j) her printf'te ayni renkte basilir. * - &j gibi adres alma ifadeleri, j ile AYNI renk tonunu (hue) kullanir * ama "dim" (soluk) yapilir; boylece "j'nin degeri" ile "j'nin adresi" * birbiriyle iliskili ama ayirt edilebilir gorunur. * - Her farkli degisken/ifade icin paletten yeni bir renk atanir, 16 * farkli tondan sonra tekrar dolasmaya baslar. * * Kullanim: * gcc -g -include color_printf.h main.c -o main && ./main * * NOT: Bu bir preprocessor + calisma-zamani hile'sidir; C tip sistemini * gercekten anlamaz, printf argumanlarinin KAYNAK METNINI (# ile * stringize edilmis halini) okuyarak degisken ismini tahmin eder. * Yani "arr[i]", "s->field", "(int)x" gibi ifadelerde ilk identifier'i * (arr, s, x) baz alir. %n desteklenmez. Genis/wchar specifier'lar * (%ls, %lc) desteklenmez. GCC/Clang'a ozgu ##__VA_ARGS__ genisletmesini * kullanir. */#ifndef COLOR_PRINTF_H#define COLOR_PRINTF_H#include <stdio.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <stdint.h>#ifdef __cplusplusextern "C" {#endif/* printf'i makro ile yakala: format metni + argumanlarin kaynak-kodu * (stringize edilmis) + gercek argumanlar birlikte gonderilir. */#ifdef printf#undef printf#endif#define printf(fmt, ...) \ __color_printf(fmt, "" #__VA_ARGS__, ##__VA_ARGS__)int __color_printf(const char *fmt, const char *argtext, ...);/* ------------------------------------------------------------------ *//* Dahili uygulama *//* ------------------------------------------------------------------ */#define __CP_MAX_NAMES 64#define __CP_NAME_LEN 48static char __cp_names[__CP_MAX_NAMES][__CP_NAME_LEN];static int __cp_color_idx[__CP_MAX_NAMES];static int __cp_name_count = 0;static int __cp_next_color = 0;/* 16 birbirinden belirgin xterm-256 renk kodu */static const int __cp_palette[] = { 203, 208, 220, 190, 118, 85, 80, 45, 75, 111, 141, 177, 213, 205, 174, 150};#define __CP_PALETTE_SIZE (int)(sizeof(__cp_palette) / sizeof(__cp_palette[0]))/* base isim icin renk indeksi bul/olustur */static int __cp_color_for(const char *name) { for (int i = 0; i < __cp_name_count; i++) { if (strcmp(__cp_names[i], name) == 0) return __cp_color_idx[i]; } int idx = __cp_next_color % __CP_PALETTE_SIZE; __cp_next_color++; if (__cp_name_count < __CP_MAX_NAMES) { strncpy(__cp_names[__cp_name_count], name, __CP_NAME_LEN - 1); __cp_names[__cp_name_count][__CP_NAME_LEN - 1] = '\0'; __cp_color_idx[__cp_name_count] = idx; __cp_name_count++; } return idx;}/* argtext icindeki N'inci top-level virgul ile ayrilmis token'i * out'a kopyalar (parantez derinligini takip eder). basari -> 1 */static int __cp_nth_token(const char *argtext, int n, char *out, size_t outsz) { int depth = 0; int cur = 0; const char *tok_start = argtext; const char *p = argtext; if (argtext == NULL || argtext[0] == '\0') return 0; for (;; p++) { char c = *p; int is_end = (c == '\0'); if (c == '(' || c == '[') depth++; else if (c == ')' || c == ']') depth--; if ((c == ',' && depth == 0) || is_end) { if (cur == n) { size_t len = (size_t)(p - tok_start); if (len >= outsz) len = outsz - 1; /* basta/sonda bosluk kirp */ while (len > 0 && isspace((unsigned char)tok_start[0])) { tok_start++; len--; } while (len > 0 && isspace((unsigned char)tok_start[len - 1])) len--; memcpy(out, tok_start, len); out[len] = '\0'; return 1; } cur++; tok_start = p + 1; if (is_end) break; } } return 0;}/* token'i temizler: onde parantezli cast'leri ((void *), (int) vb.) * ve tek bir '&' ya da '*' onekini soyar. base_name = ilk identifier. * is_addr = '&' onekiyle basladiysa ya da tur olarak adres gibi * kullanildiysa 1 doner. */static void __cp_clean(const char *tok, char *base_name, size_t bn_sz, int *is_addr) { *is_addr = 0; const char *p = tok; while (isspace((unsigned char)*p)) p++; /* onde bir ya da daha fazla "(...)" cast varsa atla */ while (*p == '(') { int depth = 1; const char *q = p + 1; while (*q && depth > 0) { if (*q == '(') depth++; else if (*q == ')') depth--; q++; } p = q; while (isspace((unsigned char)*p)) p++; } if (*p == '&') { *is_addr = 1; p++; } else if (*p == '*') { p++; } while (isspace((unsigned char)*p)) p++; size_t i = 0; while (p[i] && (isalnum((unsigned char)p[i]) || p[i] == '_') && i < bn_sz - 1) { base_name[i] = p[i]; i++; } base_name[i] = '\0'; if (i == 0) { /* identifier bulunamadi (literal, ifade vb.) -> tum token'i * anahtar olarak kullan ki en azindan tutarli olsun */ strncpy(base_name, tok, bn_sz - 1); base_name[bn_sz - 1] = '\0'; }}/* '%'den baslayan spec'i cikarir, conv karakterini ve uzunluk * belirtecini raporlar. donen deger spec'ten SONRAKI karaktere isaret eder. */static const char *__cp_parse_spec(const char *p, char *spec_out, size_t spec_sz, char *conv_out, char *len_out) { const char *start = p; p++; /* '%' */ while (*p && strchr("-+ 0#", *p)) p++; /* flags */ while (*p && isdigit((unsigned char)*p)) p++; /* width */ if (*p == '*') p++; if (*p == '.') { p++; while (*p && isdigit((unsigned char)*p)) p++; /* precision */ if (*p == '*') p++; } len_out[0] = '\0'; int li = 0; while (*p && strchr("hlLzjt", *p) && li < 3) { len_out[li++] = *p; p++; } len_out[li] = '\0'; if (*p) { *conv_out = *p; p++; } else { *conv_out = '\0'; } size_t len = (size_t)(p - start); if (len >= spec_sz) len = spec_sz - 1; memcpy(spec_out, start, len); spec_out[len] = '\0'; return p;}int __color_printf(const char *fmt, const char *argtext, ...) { va_list ap; va_start(ap, argtext); int arg_index = 0; const char *p = fmt; int total = 0; while (*p) { if (*p != '%') { fputc(*p, stdout); p++; total++; continue; } if (*(p + 1) == '%') { fputc('%', stdout); p += 2; total++; continue; } char spec[32]; char conv = 0; char lenmod[4]; p = __cp_parse_spec(p, spec, sizeof spec, &conv, lenmod); if (conv == '\0') break; /* bozuk spec, dur */ char token[256] = {0}; char base_name[__CP_NAME_LEN] = {0}; int is_addr = 0; if (__cp_nth_token(argtext, arg_index, token, sizeof token)) { __cp_clean(token, base_name, sizeof base_name, &is_addr); } else { snprintf(base_name, sizeof base_name, "?%d", arg_index); } if (conv == 'p') is_addr = 1; /* %p her zaman adres gibi davran */ char valbuf[512]; valbuf[0] = '\0'; switch (conv) { case 'd': case 'i': { if (strcmp(lenmod, "ll") == 0) { long long v = va_arg(ap, long long); snprintf(valbuf, sizeof valbuf, spec, v); } else if (strcmp(lenmod, "l") == 0) { long v = va_arg(ap, long); snprintf(valbuf, sizeof valbuf, spec, v); } else if (strcmp(lenmod, "z") == 0 || strcmp(lenmod, "j") == 0 || strcmp(lenmod, "t") == 0) { long v = va_arg(ap, long); snprintf(valbuf, sizeof valbuf, spec, v); } else { int v = va_arg(ap, int); snprintf(valbuf, sizeof valbuf, spec, v); } break; } case 'u': case 'o': case 'x': case 'X': { if (strcmp(lenmod, "ll") == 0) { unsigned long long v = va_arg(ap, unsigned long long); snprintf(valbuf, sizeof valbuf, spec, v); } else if (strcmp(lenmod, "l") == 0) { unsigned long v = va_arg(ap, unsigned long); snprintf(valbuf, sizeof valbuf, spec, v); } else if (strcmp(lenmod, "z") == 0 || strcmp(lenmod, "j") == 0 || strcmp(lenmod, "t") == 0) { unsigned long v = va_arg(ap, unsigned long); snprintf(valbuf, sizeof valbuf, spec, v); } else { unsigned int v = va_arg(ap, unsigned int); snprintf(valbuf, sizeof valbuf, spec, v); } break; } case 'c': { int v = va_arg(ap, int); snprintf(valbuf, sizeof valbuf, spec, v); break; } case 's': { char *v = va_arg(ap, char *); int needed = snprintf(NULL, 0, spec, v); if (needed > 0 && (size_t)needed < sizeof valbuf) { snprintf(valbuf, sizeof valbuf, spec, v); } else if (needed >= (int)sizeof valbuf) { char *tmp = (char *)malloc((size_t)needed + 1); if (tmp) { snprintf(tmp, (size_t)needed + 1, spec, v); strncpy(valbuf, tmp, sizeof valbuf - 1); valbuf[sizeof valbuf - 1] = '\0'; free(tmp); } } break; } case 'p': { void *v = va_arg(ap, void *); snprintf(valbuf, sizeof valbuf, spec, v); break; } case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': { if (strcmp(lenmod, "L") == 0) { long double v = va_arg(ap, long double); snprintf(valbuf, sizeof valbuf, spec, v); } else { double v = va_arg(ap, double); snprintf(valbuf, sizeof valbuf, spec, v); } break; } default: { /* bilinmeyen conv: elimizden geldigince spec'i oldugu * gibi yazdir, argument tuketmeye calisma */ snprintf(valbuf, sizeof valbuf, "%s", spec); break; } } int color = __cp_color_for(base_name); int code = __cp_palette[color]; if (is_addr) { /* ayni ton, soluk (dim) */ fprintf(stdout, "\x1b[2;38;5;%dm%s\x1b[0m", code, valbuf); } else { fprintf(stdout, "\x1b[1;38;5;%dm%s\x1b[0m", code, valbuf); } total += (int)strlen(valbuf); arg_index++; } va_end(ap); return total;}#ifdef __cplusplus}#endif#endif /* COLOR_PRINTF_H */
# compile.fishfunction compile --description 'gcc -include color_printf.h ile derle ve calistir' if test (count $argv) -lt 1 echo "kullanim: compile <dosya.c> [ekstra gcc bayraklari...]" return 1 end set -l src $argv[1] set -l extra_args $argv[2..-1] if not test -f $src echo "compile: '$src' bulunamadi" return 1 end # color_printf.h nerede? once ayni klasor, sonra $COLOR_PRINTF_H, sonra ~/.local/include set -l src_dir (path dirname $src) set -l header "" if test -f $src_dir/color_printf.h set header $src_dir/color_printf.h else if set -q COLOR_PRINTF_H; and test -f $COLOR_PRINTF_H set header $COLOR_PRINTF_H else if test -f ~/.local/include/color_printf.h set header ~/.local/include/color_printf.h else echo "compile: color_printf.h bulunamadi (ne $src_dir/, ne \$COLOR_PRINTF_H, ne ~/.local/include/)" return 1 end set -l out (path change-extension '' (path basename $src)) if test -z "$out" set out a.out end set -l out_path $src_dir/$out echo "gcc -g -include $header $src -o $out_path $extra_args" gcc -g -include $header $src -o $out_path $extra_args or return 1 $out_pathend