Esercizi di "lettura" programmi in C 2018/19
Read carefully and describe the tricks used in these programs.
C language - No Libraries
The following programs do not use library functions (only printf, just to have a feedback of the results).
Quine
#include<stdio.h>
char *s="#include<stdio.h>%cchar *s=%c%s%c;%cint main() {printf(s,10,34,s,34,10,10);}%c";
int main() {printf(s,10,34,s,34,10,10);}
int printf(const char *format, ...);char *s="int printf(const char *format, ...);char *s=%c%s%c;int main(){printf(s,34,s,34,10);};%c";int main(){printf(s,34,s,34,10);};
enum
#include <stdio.h>
enum numbers { zero, uno, due, quarantadue = 42 };
int main() {
enum numbers n;
n = 44;
printf("%d %d %d %d %d\n", zero, uno, due, quarantadue, n);
}
arrays, pointers and structs
#include <stdio.h>
char *spoint="hello";
char sarr[]="hello";
struct strs {
char s[6];
} sstruct = {"hello"};
void foo(char *s) {
s[4]=0;
}
void bar(struct strs s) {
s.s[4]=0;
printf("from bar %s\n", s.s);
}
int main(int argc, char *argv[]) {
printf("%s %s %s\n", spoint, sarr, sstruct.s);
foo(sarr);
printf("%s %s %s\n", spoint, sarr, sstruct.s);
bar(sstruct);
printf("%s %s %s\n", spoint, sarr, sstruct.s);
// test the following statements, one at a time
//spoint = sarr;
//sarr = spoint;
foo(spoint);
printf("%s %s %s\n", spoint, sarr, sstruct.s);
}
alignment
#include <stdio.h>
struct A {
char a1;
long a2;
char a3;
};
struct B {
char b1;
char b2;
long b3;
};
int main() {
printf("%d %d\n", sizeof(struct A), sizeof(struct B));
}
iteration and recursion
#include <stdio.h>
struct elem {
int val;
struct elem *next;
};
struct elem *head = NULL;
struct elem *rinsert(struct elem *new, struct elem *head) {
if (head == NULL || new->val < head->val) {
new->next = head;
return new;
} else {
head->next = rinsert(new, head->next);
return head;
}
}
struct elem *iinsert(struct elem *new, struct elem *head) {
struct elem **pnext;
for (pnext = &head;
*pnext != NULL && new->val > (*pnext)->val;
pnext = &((*pnext)->next))
;
new->next = *pnext;
*pnext = new;
return head;
}
void rprint(struct elem *this) {
if (this) {
printf("%d ",this->val);
rprint(this->next);
}
}
void iprint(struct elem *this) {
for ( ; this != NULL; this = this->next)
printf("%d ",this->val);
}
struct elem test[]={{5},{3},{9},{1},{7}};
#define NELEM (sizeof(test) / sizeof(struct elem))
int main(int argc, char *argv[]) {
int i;
for (i = 0; i < NELEM; i++)
head = rinsert(&test[i], head);
rprint(head);
printf("\n");
iprint(head);
printf("\n");
head = NULL;
for (i = 0; i < NELEM; i++)
head = iinsert(&test[i], head);
rprint(head);
printf("\n");
iprint(head);
printf("\n");
}
comma operator
#include <stdio.h>
int main() {
int a, b;
a = 1, 2, 3;
b = (1, 2, 3);
printf("%d %d\n", a, b);
}
#include <stdio.h>
int slen(char *s) { /* in real programs use strlen instead */
size_t rval;
for (rval = 0; *s != 0; s++, rval++)
;
return rval;
}
int ispal(char *s) {
int i,j;
for (i=0, j=slen(s)-1; i < j; i++, j--) {
if (s[i] != s[j])
return 0;
}
return 1;
}
void reverse(char *s) {
int i,j;
for (i=0, j=slen(s)-1; i < j; i++, j--)
s[j] ^= s[i] ^= s[j] ^= s[i];
}
int main(int argc, char *argv[1]) {
for ( ;argc > 1; argv++, argc--) {
printf("\"%s\" is%s palindrome\n", argv[1],
ispal(argv[1])?"":"n't");
reverse(argv[1]);
printf("\"%s\"\n", argv[1]);
}
}
string by value
#include <stdio.h>
int slen(char *s) { /* in real programs use strlen instead */
int rval;
for (rval = 0; *s != 0; s++, rval++)
;
return rval;
}
void printxvowel(char v, char *s) {
int s_len = slen(s);
char locals[s_len];
int i;
for (i=0; i<s_len; i++) {
switch (s[i]) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
locals[i] = v;
break;
default:
locals[i] = s[i];
break;
}
}
printf("-> %s\n<- %s\n",s,locals);
}
int main(int argc, char *argv[]) {
for ( ; argc > 1; argc--, argv++) {
printxvowel('a',argv[1]);
printxvowel('e',argv[1]);
printxvowel('i',argv[1]);
printxvowel('o',argv[1]);
printxvowel('u',argv[1]);
}
return 0;
}
test it using "Garibaldi fu ferito, fu ferito ad una gamba, Garibaldi che comanda, che comanda il battaglion" as argv[1].
tables and preprocessor tricks
#include <stdio.h>
#define rows_of(X) (sizeof(X) / sizeof((X)[0]))
#define printTable(X) do { \
int i; \
printf("TABLE " #X ": size of element %d\n" \
"(printed by the line %d of source file %s)\n", \
sizeof(*(table ## X)), __LINE__, __FILE__); \
for (i = 0; i < rows_of(table ## X); i++) \
printf(#X " %02d %s\n",i,table ## X [i]); \
} while (0);
char tableA[][50] = {"Sempre caro mi fu quest'ermo colle,",
"e questa siepe, che da tanta parte",
"dell’ultimo orizzonte il guardo esclude."};
char *tableB[] = {"Sempre caro mi fu quest'ermo colle,",
"e questa siepe, che da tanta parte",
"dell’ultimo orizzonte il guardo esclude."};
int main(int argc, char *argv[1]) {
int i;
printTable(A);
printf("\n");
printTable(B);
}
arrays and pointers
#include <stdio.h>
int slen(char *s) { /* in real programs use strlen instead */
size_t rval;
for (rval = 0; *s != 0; s++, rval++)
;
return rval;
}
void echoargs(int argc, char *argv[]) {
int i;
for (i = 0; i < argc; i++)
printf("argv[%d] = \"%s\"\n",i,argv[i]);
printf("\n");
}
enum state {SPACE, CHAR};
int splitargv(char *s, char **argv) {
enum state state = SPACE;
int count = 0;
for (; *s != 0; s++) {
if (*s == ' ' || *s == '\t' || *s == '\n') {
if (state != SPACE)
count++;
if (argv != NULL)
*s = 0;
state = SPACE;
} else {
if (state == SPACE && argv != NULL)
*argv++ = s;
state = CHAR;
}
};
if (state != SPACE)
count++;
if (argv != NULL)
*argv = NULL;
return count;
}
void splitargs(char *args) {
int newargc = splitargv(args, NULL);
char *newargv[newargc + 1];
splitargv(args, newargv);
echoargs(newargc, newargv);
}
int main(int argc, char *argv[1]) {
echoargs(argc, argv);
for ( ; *argv != NULL; argv++) {
printf("Split \"%s\"\n",*argv);
splitargs(*argv);
}
}
This is a simplified version of the idea used in the libexecs library. Test this program using args like:
./a.out "ciao mare" "a b c"
void * and function pointers
#include <stdio.h>
typedef void (*voidfun) (void *arg);
void printint(void *arg) {
int *iarg = arg;
printf("int %d\n", *iarg);
}
void printstring(void *arg) {
char *sarg = arg;
printf("int %s\n", sarg);
}
void printpointer(void *arg) {
printf("pointer %p\n", arg);
}
void printfun(void *arg) {
voidfun fun = arg;
fun((void *) 0x42);
}
void launch(voidfun f, void *opaque) {
f(opaque);
}
int main(int argc, char *argv[1]) {
int v = 235;
char *s = "Lasciate ogni speranza, o voi ch'entrate";
launch(printint, &v);
launch(printstring, s);
launch(printfun, printpointer);
return 0;
}
This technique is used to implement callbacks with opaque args.
Programs using libraries
char by char copy (stdio)
#include <stdio.h>
int main(int argc, char *argv[]) {
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
similar programs, different approaches (stdio, string, stdlib, ctype)
First program:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define BUFLEN 4096
char *loadfile(char *path) {
char *contents = NULL;
size_t contents_len = 0;
char buffer[BUFLEN];
size_t len;
FILE *fin = fopen(path, "r");
FILE *fout = open_memstream(&contents, &contents_len);
if (fin == NULL || fout == NULL)
exit(1);
while ((len = fread(buffer, sizeof(char), BUFLEN, fin)) > 0)
fwrite(buffer, sizeof(char), len, fout);
fclose(fin);
fclose(fout);
return(contents);
}
enum state {SPACE, CHAR};
int splitwords(char *s, char **words) {
enum state state = SPACE;
int count = 0;
for (; *s != 0; s++) {
if (isalnum(*s)) {
if (state == SPACE && words != NULL)
*words++ = s;
state = CHAR;
} else {
if (state != SPACE)
count++;
if (words != NULL)
*s = 0;
state = SPACE;
}
};
if (state != SPACE)
count++;
return count;
}
static int sortcmp(const void *p1, const void *p2) {
const char *s1 = *(char * const *) p1;
const char *s2 = *(char * const *) p2;
int rval = strlen(s1) - strlen(s2);
if (rval == 0)
rval = strcmp(s1, s2);
return rval;
}
int main(int argc, char *argv[1]) {
if (argc == 2) {
char *contents = loadfile(argv[1]);
int count = splitwords(contents, NULL);
char **words = malloc(count * sizeof(char *));
if (words == NULL)
return 1;
else {
int i;
splitwords(contents, words);
qsort(words, count, sizeof(char *), sortcmp);
for (i = 0; i < count; i++)
printf("%s\n", words[i]);
return 0;
}
} else
return 1;
}
Second program:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct word {
struct word *next;
int count;
char word[];
};
static int lenalphacmp(const char *s1, const char *s2) {
int rval = strlen(s1) - strlen(s2);
if (rval == 0)
rval = strcmp(s1, s2);
return rval;
}
struct word *addword(char *word, struct word *wlist) {
struct word **scan;
int cmpvalue;
for (scan = &wlist;
*scan != NULL && ((cmpvalue = lenalphacmp(word, (*scan)->word)) > 0);
scan = &((*scan)->next))
;
if (scan != NULL && cmpvalue == 0)
(*scan)->count ++;
else {
struct word *new = malloc(sizeof(struct word) + strlen(word) + 1);
if (new) {
new->next = *scan;
new->count = 1;
strcpy(new->word, word);
*scan = new;
}
}
return wlist;
}
struct word *addwordlen(char *word, size_t len, struct word *wlist) {
char word0[len+1];
strncpy(word0,word,len);
word0[len]=0;
return addword(word0, wlist);
}
struct word *processline(char *line, struct word *wlist) {
char *thisword = NULL;
for ( ;*line != 0; line++) {
if (isalnum(*line)) {
if (thisword == NULL)
thisword = line;
} else {
if (thisword != NULL) {
wlist = addwordlen(thisword, line - thisword, wlist);
thisword = NULL;
}
}
}
return wlist;
}
void printwlist(struct word *wlist) {
for ( ; wlist != NULL; wlist = wlist->next)
printf("%s : %d\n", wlist->word, wlist->count);
}
int main(int argc, char *argv[1]) {
if (argc == 2) {
FILE *fin = fopen(argv[1], "r");
ssize_t len;
char *linebuf = NULL;
size_t linebuflen = 0;
struct word *wlist = NULL;
while ((len = getline(&linebuf, &linebuflen, fin)) > 0)
wlist = processline(linebuf, wlist);
fclose(fin);
free(linebuf);
printwlist(wlist);
return 0;
} else
return 1;
}
Command line args management (getopt)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <libgen.h>
void usage_and_exit(char *progname) {
fprintf(stderr,
"Usage:\n"
" %s OPTIONS [value] ... [value]\n"
"Options:\n"
" -v | --verbose: verbose mode\n"
" -h | --help: print a short usage helping message\n"
" -a val | --add val add a value\n"
" -s val | --sub val subtract a value\n"
" --double double the final result\n"
"This program computes an integer value\n", progname);
exit(1);
}
int main(int argc, char *argv[]) {
static struct option long_options[] = {
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"add", required_argument, 0, 'a'},
{"sub", required_argument, 0, 's'},
{"double", no_argument, 0, 0x101},
};
static char *short_options = "vha:s:";
int opt;
int value = 0;
int verbose = 0;
int doubleval = 1;
char *progname = basename(argv[0]);
while((opt = getopt_long(argc, argv, short_options, long_options, NULL)) > 0) {
switch (opt) {
case 'v': verbose = 1;
break;
case 'a': value += atoi(optarg);
break;
case 's': value -= atoi(optarg);
break;
case 0x101: doubleval *= 2;
break;
case 'h':
case '?': usage_and_exit(progname);
break;
}
}
for (; optind < argc; optind++)
value += atoi(argv[optind]);
value *= doubleval;
if (verbose)
printf("the result is %d\n", value);
return value;
}
dynamic allocation on the heap, qsort, getline (stdlib)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define AOS_LENSTEP 8
struct array_of_strings {
char **strings;
size_t currentlength;
size_t arraylength;
};
typedef struct array_of_strings array_of_strings;
void array_of_strings_add(array_of_strings *arrayOfStrings, char *string) {
if (arrayOfStrings->currentlength >= arrayOfStrings->arraylength) {
size_t newlength = arrayOfStrings->arraylength + AOS_LENSTEP;
char **new_string = realloc(arrayOfStrings->strings, newlength * sizeof(arrayOfStrings->strings[0]));
if (new_string != NULL) {
arrayOfStrings->arraylength = newlength;
arrayOfStrings->strings = new_string;
}
}
if (arrayOfStrings->currentlength < arrayOfStrings->arraylength)
arrayOfStrings->strings[arrayOfStrings->currentlength++] = strdup(string);
}
void array_of_strings_print(array_of_strings *v) {
size_t i;
for (i = 0; i < v->currentlength; i++)
printf("[%3lu]: %s\n", i, v->strings[i]);
}
static int alphasort(const void *a, const void *b) {
return strcmp(*(char **) a, *(char **) b);
}
void array_of_strings_sort(array_of_strings *v) {
qsort(v->strings, v->currentlength, sizeof(v->strings[0]), alphasort);
}
void array_of_strings_free(array_of_strings *v) {
size_t i;
for (i = 0; i < v->currentlength; i++)
free(v->strings[i]);
if (v->arraylength > 0)
free(v->strings);
}
int main(int argc, char *argv[]) {
char* line = NULL;
size_t lineLength = 0;
ssize_t numberOfCharactersRead;
static array_of_strings arrayOfStrings;
if (argc != 1)
exit(1);
while ((numberOfCharactersRead = getline(&line, &lineLength, stdin)) >= 0) {
if (line[numberOfCharactersRead - 1] == '\n')
line[numberOfCharactersRead - 1] = 0;
array_of_strings_add(&arrayOfStrings, line);
}
free(line);
array_of_strings_sort(&arrayOfStrings);
array_of_strings_print(&arrayOfStrings);
array_of_strings_free(&arrayOfStrings);
}
open_memstream (quite tricky)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int alphasort(const void *a, const void *b) {
return strcmp(* (char **) a, * (char **) b);
}
int main(int argc, char *argv[]) {
char *line = NULL;
size_t lineLength = 0;
ssize_t numberOfCharacterRead;
FILE *fakefile;
char *fakeMemoryFile = NULL;
char **stringsarray;
size_t stringsArrayLength = 0;
char **scan;
char *dups;
if (argc != 1)
exit(1);
fakefile = open_memstream(&fakeMemoryFile, &stringsArrayLength);
if (fakefile == NULL)
exit(1);
while ((numberOfCharacterRead = getline(&line, &lineLength, stdin)) >= 0) {
if (line[numberOfCharacterRead - 1] == '\n')
line[numberOfCharacterRead - 1] = 0;
if ((dups = strdup(line)) != NULL)
fwrite(&dups, sizeof(dups), 1, fakefile);
}
free(line);
dups = NULL;
fwrite(&dups, sizeof(dups), 1, fakefile);
fclose(fakefile);
stringsarray = (char **) fakeMemoryFile;
stringsArrayLength /= sizeof(char *);
stringsArrayLength--;
printf("%lu\n",stringsArrayLength);
qsort(stringsarray, stringsArrayLength, sizeof(stringsarray[0]), alphasort);
for (scan = stringsarray; *scan != NULL; scan++)
printf("[%3lu]: %s\n", scan - stringsarray, *scan);
for (scan = stringsarray; *scan != NULL; scan++)
free(*scan);
free(stringsarray);
}
fantasy of strcpy (time, stdint, string)
Cit. Cirano page 33.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
char *strcpy0(char *dest, const char *src) {
int i;
int len;
for (len = 0; src[len] != 0; len++)
;
for (i = 0; i <= len; i++)
dest[i] = src[i];
return dest;
}
char *strcpy1(char *dest, const char *src) {
int i;
for (i = 0; src[i] != 0; i++)
;
for ( ; i >= 0; i--)
dest[i] = src[i];
return dest;
}
char *strcpy2(char *dest, const char *src) {
char *rval = dest;
while ((*dest++ = *src++) != 0)
;
return rval;
}
char *strcpy3(char *dest, const char *src) {
int i;
for (i=0; (dest[i] = src[i]) != 0; i++)
;
return dest;
}
char *strcpy4(char *dest, const char *src) {
if ((*dest = *src) != 0)
strcpy4(dest+1, src+1);
return dest;
}
char *strcpy5(char *dest, const char *src) {
char *rval = dest;
while (*src != 0)
*dest++ = *src++;
*dest = 0;
return rval;
}
char *strcpy6(char *dest, const char *src) {
uint64_t *src64 = (uint64_t *) src;
uint64_t *dest64 = (uint64_t *) dest;
while (1) {
register uint64_t tmp = *src64;
register uint64_t scan;
for (scan = 0xffULL; (tmp & scan) != 0; scan <<= 8)
;
//printf("%llx %llx %p %p %s\n",scan, tmp, src64, dest64, (char *) src64);
if (scan != 0) {
strcpy2((char *) dest64, (char *) src64);
break;
}
*dest64++ = tmp;
src64++;
}
return dest;
}
#define NUMBER_OF_TEST 1000000
double time_strcpy(char * (*cpy)(char *, const char *), char *d, const char *s)
{
clock_t starttime, time;
int i;
starttime = clock();
for (i = 0; i< NUMBER_OF_TEST; i++)
cpy(d, s);
time = clock() - starttime;
return (1.0) * time / CLOCKS_PER_SEC;
}
#define TESTSTRCPY(N,D,S) \
printf("strcpy" #N " %s time %lf\n", strcpy ##N ((D),(S)), time_strcpy(strcpy ##N, (D),(S)))
int main(int argc, char *argv[]) {
if (argc != 2)
return 1;
else {
size_t argv1len=strlen(argv[1]);
char argcpy[argv1len+1];
strncpy(argcpy, argv[1], argv1len);
printf("strncpy %s\n", argcpy);
TESTSTRCPY(, argcpy, argv[1]);
TESTSTRCPY(0, argcpy, argv[1]);
TESTSTRCPY(1, argcpy, argv[1]);
TESTSTRCPY(2, argcpy, argv[1]);
TESTSTRCPY(3, argcpy, argv[1]);
TESTSTRCPY(4, argcpy, argv[1]);
TESTSTRCPY(5, argcpy, argv[1]);
TESTSTRCPY(6, argcpy, argv[1]);
}
}
This program compares various homemade implementation of string copy function with the library one.
math and printf
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#define DELAY 10000
#define DURATION 30
int main(int argc, char *argv[]) {
double x;
int i;
for (i = 0; i < DURATION * 1000000 / DELAY; i++) {
double y = sin(M_PI * i / 100);
int pos = 40 + (40 * y);
printf("\r%*s\b",pos,"*");
fflush(stdout);
usleep(DELAY);
printf("\n");
}
}
minishell (history and execs)
this program needs some libraries: history/readline should be provided in yur distribution, execs is in Debian SID (or it is available in GitHUB).
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <execs.h>
int main(int argc, char *argv[]) {
while (1) {
char *cmd = readline("% ");
if (cmd == NULL)
break;
if (*cmd != 0) {
add_history(cmd);
system_nosh(cmd);
}
free(cmd);
}
printf("\n");
return 0;
}
You may need to define the environment variable LD_LIBRARY_PATH to load locally installed libraries.
LD_LIBRARY_PATH=/usr/local/lib
export LD_LIBRARY_PATH
conversions (math)
#include <stdio.h>
#include <math.h>
int main() {
char c;
short s;
int i;
long l;
long long ll;
unsigned char uc;
unsigned short us;
unsigned int ui;
unsigned long ul;
unsigned long long ull;
float f;
double d;
long double ld;
c = s = i = l = ll = 0xc1c2c3c4c5c6c7c8;
printf("%d %llx %lld\n", sizeof(ll), ll, ll);
printf("%d %lx %ld\n", sizeof(l), l, l);
printf("%d %x %d\n", sizeof(i), i, i);
printf("%d %x %d\n", sizeof(s), s, s);
printf("%d %x %d\n", sizeof(c), c, c);
ll = l = i = s = c;
printf("%d %x %d\n", sizeof(s), s, s);
printf("%d %x %d\n", sizeof(i), i, i);
printf("%d %lx %ld\n", sizeof(l), l, l);
printf("%d %llx %lld\n", sizeof(ll), ll, ll);
i = 1 << (sizeof(i) * 8 - 1);
printf("%d %x %d\n", sizeof(i), i, i);
i >>= 1;
printf("%d %x %d\n", sizeof(i), i, i);
i = -1;
printf("%d %x %d\n", sizeof(i), i, i);
i >>= 1;
printf("%d %x %d\n", sizeof(i), i, i);
uc = us = ui = ul = ull = 0xc1c2c3c4c5c6c7c8;
printf("%d %llx %llu\n", sizeof(ull), ull, ull);
printf("%d %lx %lu\n", sizeof(ul), ul, ul);
printf("%d %x %u\n", sizeof(ui), ui, ui);
printf("%d %x %u\n", sizeof(us), us, us);
printf("%d %x %u\n", sizeof(uc), uc, uc);
ull = ul = ui = us = uc;
printf("%d %x %u\n", sizeof(us), us, us);
printf("%d %x %u\n", sizeof(ui), ui, ui);
printf("%d %lx %lu\n", sizeof(ul), ul, ul);
printf("%d %llx %llu\n", sizeof(ull), ull, ull);
f = d = ld = acosl(-1);
printf("%2d %80.78llf\n", sizeof(ld), ld);
printf("%2d %80.78lf\n", sizeof(d), d);
printf("%2d %80.78f\n", sizeof(f), f);
return 0;
}
Explanation of program's output for a LP64 architecture:
8 c1c2c3c4c5c6c7c8 -4484807029008447544
8 c1c2c3c4c5c6c7c8 -4484807029008447544
4 c5c6c7c8 -976828472
2 ffffc7c8 -14392
1 ffffffc8 -56
2 ffffffc8 -56
4 ffffffc8 -56
8 ffffffffffffffc8 -56
8 ffffffffffffffc8 -56
4 80000000 -2147483648
4 c0000000 -1073741824
4 ffffffff -1
4 ffffffff -1
8 c1c2c3c4c5c6c7c8 13961937044701104072
8 c1c2c3c4c5c6c7c8 13961937044701104072
4 c5c6c7c8 3318138824
2 c7c8 51144
1 c8 200
2 c8 200
4 c8 200
8 c8 200
8 c8 200
16 3.141592653589793238512808959406186204432742670178413391113281250000000000000000
8 3.141592653589793115997963468544185161590576171875000000000000000000000000000000
4 3.141592741012573242187500000000000000000000000000000000000000000000000000000000
A home-brewed mini-printf (variadic functions, indirect recursion)
#include <stdio.h>
#include <stdarg.h>
int vrprintf(const char *format, va_list ap);
static int putcx(int c) {
if (c!=0) {
putchar(c);
return 1;
} else
return 0;
}
static char backchar[128] = {
[0 ... 127] = 0,
['a'] = '\a',
['b'] = '\b',
['f'] = '\f',
['n'] = '\n',
['r'] = '\r',
['t'] = '\t',
['v'] = '\v',
['\\'] = '\\',
['\''] = '\'',
['"'] = '"',
['?'] = '?',
};
static int put_backslash(char escapeChar) {
return putcx(backchar[escapeChar & 0x7f]);
}
static int rvrp_int(int val) {
if (val == 0)
return 0;
else
return rvrp_int(val / 10) + putcx('0' + val % 10);
}
static int vrp_int(int val) {
if (val != 0) {
if (val < 0)
return putcx('-') + rvrp_int(-val);
else
return rvrp_int(val);
} else
return putcx('0');
}
static int vrp_string(char *s) {
switch (*s) {
case 0:
return 0;
case '\\':
return put_backslash(*(s+1)) ? vrp_string(s + 2) + 1 : 0;
default:
return putcx(*s) + vrp_string(s + 1);
}
}
static int vrp_percent(const char *format, va_list ap) {
switch (*format) {
case 0:
return 0;
case '%':
return putcx(*format) + vrprintf(format + 1, ap);
case 'd':
return vrp_int(va_arg(ap, int)) + vrprintf(format + 1, ap);
case 's':
return vrp_string(va_arg(ap, char *)) + vrprintf(format + 1, ap);;
default:
printf("ERROR\n");
return 0;
}
}
int vrprintf(const char *format, va_list ap) {
switch (*format) {
case 0:
return 0;
case '%':
return vrp_percent(format + 1, ap);
case '\\':
return put_backslash(*(format+1)) ? vrprintf(format + 2, ap) + 1 : 0;
default:
return putcx(*format) + vrprintf(format + 1, ap);
}
}
int rprintf(const char *format, ...) {
int rval;
va_list ap;
va_start (ap, format);
rval = vrprintf(format, ap);
va_end(ap);
return rval;
}
int main() {
int v;
v = rprintf("hello world\n");
printf("%d\n", v);
v = printf("hello world\n");
printf("%d\n", v);
v = rprintf("hello world %d\n", 10);
printf("%d\n", v);
v = printf("hello world %d\n", 10);
printf("%d\n", v);
v = rprintf("hello world %s %d\n", "piripicchio", 42);
printf("%d\n", v);
v = printf("hello world %s %d\n", "piripicchio", 42);
printf("%d\n", v);
v = rprintf("hello world %% \"%s\" %d\n", "piripicchio\tbackslash", 42);
printf("%d\n", v);
v = printf("hello world %% \"%s\" %d\n", "piripicchio\tbackslash", 42);
printf("%d\n", v);
v = rprintf("%%\n");
printf("%d\n", v);
v = printf("%%\n");
printf("%d\n", v);
}