/* The C Programming Language
My solutions to exercises in chapter 3. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <math.h>
#define __DEBUG__ 0
#define SORTED_MAXSIZE 6
#define COUNT_MAXSIZE 3
#define EXPAND_MAXSIZE 1024
#define MAX(x,y) (x>y) ? x : y
#define MIN(x,y) (x<y) ? x : y
enum WHITESPACE{ SPACE = 0, TAB, NEWLINE };
void whitespace_count(char[], int[]);
/* e 3-1 */
int binsearch(int,int[],int);
/* e 3-2 */
void escape(char[], int);
void escape2(char[], int);
void unescape(char[]);
/* e 3-3 */
void expand(char[], char[]);
/* e3-4 */
void reverse(char[]);
void tcpl_itoa(int, char[]);
void my_itoa(int, char[]);
/* e3-5 */
void itob(int, char[], int);
/* e3-6 */
void fitoa(int, char[], int); /* I think I sorta cheated. */
int main(int argc, char* argv[])
{
int i;
int somenum = 3123;
int sorted[SORTED_MAXSIZE] = {0,5,10,15,20,30};
int count[COUNT_MAXSIZE] = {0};
int find = 5;
char escape_me[32] = "This should \n be \t escaped!";
char expand_me[EXPAND_MAXSIZE] = "-A-Z hi to you sir, 0-9, a-z-";
char expand_to[EXPAND_MAXSIZE];
char reverse_me[6] = "Hello";
char s_tcpl_itoa[32];
char s_my_itoa[32];
char s_itob[32];
char s_fitoa[32];
tcpl_itoa(somenum, s_tcpl_itoa);
my_itoa(somenum, s_my_itoa);
itob(312, s_itob, 2);
fitoa(312, s_fitoa, 10);
escape2(escape_me, 32);
expand(expand_me, expand_to);
whitespace_count("Counting the whitespace\n in this\t!", count);
for (i = 0; i < COUNT_MAXSIZE; ++i)
printf("Whitespace count: %d\n", count[i]);
printf("Found '5' at index: %d\n", binsearch(find, sorted, SORTED_MAXSIZE));
printf("Escaped: %s\n", escape_me);
unescape(escape_me);
printf("Unescaped: %s\n", escape_me);
printf("Expand: %s\n", expand_me);
printf("Expanded to: %s\n", expand_to);
printf("Sizeof int: %lu\n", sizeof(int));
printf("Max negative int: %d\n", INT_MAX);
printf("Reverse of %s\n", reverse_me);
reverse(reverse_me);
printf("is: %s\n", reverse_me);
printf("k&r ITOA: %s\n", s_tcpl_itoa);
printf("My ITOA: %s\n", s_my_itoa);
printf("My itob: %s\n", s_itob);
printf("fixed-width itoa: %s\n", s_fitoa);
return 0;
}
void fitoa(int n, char s[], int w)
{
const char fmt[32] = "%*d";
sprintf(s, fmt, w, n);
}
void itob(int n, char s[], int b)
{
int i, x, sign;
i = sign = 0;
if(n < 0)
sign = 1;
do
{
x = n % b;
if(x > 9)
s[i++] = x + 'A' - 9;
else
s[i++] = x + '0';
} while ( n /= b );
if(sign)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
void reverse(char s[])
{
int i, j;
char c;
for( i = 0, j = strlen(s)-1; i < j; i++, j-- )
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
void my_itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0)
n = -n;
i = 0;
do {
s[i++] = n % 10 + '0';
} while (n /= 10);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
void tcpl_itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0)
n = -n;
i = 0;
do {
s[i++] = n % 10 + '0';
} while ((n /= 10) > 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
void whitespace_count(char s[], int count[])
{
int i;
for( i = 0; i < strlen(s); ++i ){
switch(s[i]) {
case ' ':
count[SPACE]++;
break;
case '\n':
count[NEWLINE]++;
break;
case '\t':
count[TAB]++;
break;
default:
break;
}
}
}
/* Searches for value x in v[] where n is highest element to
be searched. */
int binsearch(int x, int v[], int n)
{
int mid;
int low = 0;
int high = n - 1;
mid = (low+high)/2;
while( low <= high && x != v[mid]){
if(__DEBUG__)
printf("low:%d, high:%d, mid:%d, x:%d\n", low, high, mid, x);
if( x > v[mid] )
low = mid+1;
else
high = mid+1;
mid = (low+high)/2;
}
if( x == v[mid])
return mid;
return -1;
}
/*re-wrote escape to work in-place */
void escape2(char s[], int bufsize)
{
int i, j, count = -2;
int len = strlen(s)-1;
/* Scan over string once counting
our characters to expand */
for( i = 0; i < len; ++i)
if(s[i] == '\t' || s[i] == '\n')
count+=2;
if( count > bufsize)
return;
s[len+count+1] = '\0';
for( i = len, j=len+count; i >= 0; i--, j--)
if(s[i] == '\t' && j-1 >= 0){
s[j] = 't';
s[j-1] = '\\';
j--;
}
else if( s[i] == '\n' && j-1 >= 0){
s[j] = 'n';
s[j-1] = '\\';
j--;
}
else
s[j] = s[i];
}
/* converts escaped characters into actual visible character representations
in the string, a newline becomes literal '\n' */
void escape(char s[], int bufsize)
{
int i, j;
int len = strlen(s);
char tmp[SHRT_MAX];
if(bufsize < len)
return;
for( i = j = 0; i < len; ++i ){
switch(s[i]){
case '\n':
if( j+2 < bufsize ){
tmp[j] = '\\';
tmp[j+1] = 'n';
j+=2;
}
break;
case '\t':
if( j+2 < bufsize ){
tmp[j] = '\\';
tmp[j+1] = 't';
j+=2;
}
break;
default:
tmp[j] = s[i];
j++;
break;
}
}
s[j+1] = '\0';
strcpy(s, tmp);
}
/* converts all literal "\n" and "\t" in a string to actual newlines and tabs. */
void unescape(char s[])
{
int i, j;
int len = strlen(s)-1;
char tmp[SHRT_MAX];
for( i = j = 0; i < len; ++i) {
if( s[i] == '\\' && i+1 < len){
if (s[i+1] == 'n')
tmp[j] = '\n';
else if(s[i+1] == 't')
tmp[j] = '\t';
j++;
i++;
} else {
tmp[j] = s[i];
j++;
}
}
tmp[j] = '\0';
strcpy(s, tmp);
}
/* All constructs such as a-z, A-Z, and 0-9 present in s1 are expanded into
the full character set in s2, e.g. a-Z becomes abcdef...xyz */
void expand(char s1[], char s2[])
{
int i, min, max, p1, p2;
p1 = p2 = 0;
while (s1[p1] != '\0'){
if(s1[p1] == '-' && p1-1 != -1 && s1[p1+1] != '\0'){
p2--;
max = MAX((int)s1[p1-1],(int)s1[p1+1]);
min = MIN((int)s1[p1-1],(int)s1[p1+1]);
for( i=min; i < max; i++ ){
s2[p2] = (char)i;
p2++;
}
} else {
s2[p2] = s1[p1];
p2++;
}
p1++;
}
s2[p2] = '\0';
}