Friday, April 26, 2013

C source for printf (a minimal one without floating point)

While I was working with an 8K flash MCU, I found that the default printf provided by 'C' library occupies close to 1.8K (too much eh?). I decided to create a function of my own which generates approximately 850 Bytes of code. Posting it for my own reference and for others to use it

WARNING: I'm not responsible for the code if it cause night blindness to your pet DOG!
/**
 * @file     Minimal printf source file
 * @author   Sundarapandian A
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdarg.h>

#define F_UNS        1
#define F_BIG        2
#define F_ZERO       4

#define IBUFSZ       16

/* pputc function */
void pputc(int ch);

/* Print an integer in given format */
static int iprint(unsigned long int val, int flag, int prec, int base)
{
    static const char *lt = "0123456789ABCDEF";
    char buf[IBUFSZ];
    int i, j, neg = 0;

    if (!(flag & F_UNS) && (int) val < 0) {
        neg = 1;
        val = -val;
    }
    for (i = IBUFSZ - 1; i >= 0; i--) {
        buf[i] = lt[val - ((val / base) * base)];
        val = val / base;
        if (!val)
            break;
    }
    for (j = 0; j < prec - (IBUFSZ - i + neg); j++) {
        pputc((flag & F_ZERO) ? '0' : ' ');
    }
    if (neg) {
        pputc('-');
    }
    j = IBUFSZ - i + neg;
    for (; i < IBUFSZ; i++)
        pputc((flag & F_BIG) ? buf[i] : (buf[i] | 0x20));
    return prec > j ? prec : j;
}

/**
 * Minimal printf (Without floating point support)
 */
int min_printf(const char *fmt, ...)
{
    int apr = 0, pflag = 0, prec = 0, cnt = 0;
    va_list ap;
    const char *str;
    va_start(ap, fmt);
    for (; *fmt; fmt++) {
        if (!apr && *fmt == '%') {
            apr = 1;
            prec = pflag = 0;
            continue;
        }

        if (!apr) {
            pputc(*fmt);
            cnt++;
            continue;
        }
        switch (*fmt) {
        case '%':
            pputc('%');
            cnt++;
            apr = 0;
            break;
        case '0':
            if (!prec)
                pflag |= F_ZERO;
            else
                prec *= 10;
            break;
        case 's':
            str = va_arg(ap, const char *);
            while (*str) {
                pputc(*str++);
                cnt++;
            }
            apr = 0;
            break;
        case '#':
        case 'l':
            break;
        case 'u':
            cnt += iprint(va_arg(ap, unsigned int),
                          pflag | F_UNS, prec, 10);
            apr = 0;
            break;
        case 'c':
            pputc(va_arg(ap, int));
            cnt++;
            apr = 0;
            break;
        case 'd':
            cnt += iprint(va_arg(ap, long int), pflag, prec, 10);
            apr = 0;
            break;
        case 'X':
            pflag |= F_BIG;
        case 'x':
            cnt += iprint(va_arg(ap, unsigned int),
                          pflag | F_UNS, prec, 16);
            apr = 0;
            break;
        case '*':
            prec = va_arg(ap, int);
            break;
        default:
            if (*fmt >= '1' && *fmt <= '9') {
                prec = (prec * 10) + (*fmt - '0');
            } else {
                /* Something wrong */
                apr = 0;
            }
        }                       /* End of switch */
    }                           /* End of for loop */
    va_end(ap);
    return cnt;
}

#define TESTING

#ifdef TESTING
#include <stdio.h>
/**
 * Function to print a char on terminal/file
 */
void pputc(int ch)
{
    putchar(ch);
}

int main()
{
    int val;
    val = min_printf("0x%0*X %8d %lu %s %c\r\n",
                     8, 10, -567, (unsigned long int) -4,
                     "Test Str", 0x41);
    min_printf("Num chars printed on screen: %d\r\n", val);
    return 0;
}
#endif

Thursday, October 7, 2010

Values, Types and Representation (Decimal number system) - I

During my childhood my grandfather used to say me with a lot of pride "Ancient Indians invented Zero which is the cause for all the great revolution that led us to this Modern world". I never liked this idea, it is bullshit! I mean how could '0' be an invention??? It is just a bloody letter! I could've used 's' to represent zero, or anything of my choice! But then later when I came to know about the numbering system used to represent count prior to invention of '0', I understood what an important invention it is (not as a symbol but as a concept)! Think about Roman numerals, which never had a zero in it so how do they represent 10 with introduction of a new letter 'X', they used new symbols to represent higher values "I,V,X,L,C,D,M". This kind of representation makes life very hard when it comes to doing math (VI + IV = X [oh god!]) or representing a huge number (I always wonder how would they represent a billion :D). Then came the revolutionary idea of positional decimal number system (Hindu–Arabic numeral system) with the greatest invention of science Mr. Zero. Just follow this link to wikipedia article!

Positional representation of numbers are fairly simple you'll have a collection of unique symbols to represent count of 0 to N, having a total of N+1 symbols. This N+1 is the "base" for your numbering system. From now on I will use the term 'digit' to denote the unique symbol that represents a basic count (0,1,2,3,4,5,6,7,8 and 9 in a decimal system). Then use the combination of these symbols to represent any arbitrary count/value, in this combination the digit changes its value based on its position. Say, in number 548, 5 represents "five hundred" and not just "five", 4 represents "forty" and not just "four" and finally 8 represents the "eight" hence the count it represents is "five hundred and forty eight".

Let us try to understand the basics of decimal numbering system. We all know deci is 10 raised to the power of 1 i.e., 10. "Decimal number system" is called so because it has 10 (deci) unique symbols (digits) in it (0 - 9) to represent the count from zero to nine. A value of the digit is calculated by the "position" and the value it represents say for example if digit 9 is in (starting from position 0) 3rd position of a number then it is not "Nine" rather is is "Nine thousand"! i.e., 9 multiplied with ("base" raised to the power of "position"). With this number system we can represent any arbitrary value with just ten digits. Now we will see what is so special about zero, zero is used for one important purpose i.e., to give shift in position of all non-zero digits that precedes them, without adding a value! That means when 0 is not preceded by any non-zero digits, then that 0 really adds no value to the count, example 00009230 is the same as 9230, where the 0 that succeeds gives a shift of 1 position to the digits 3, 2 and 9, thus making 9 as "nine thousand", 2 as "two hundred" and 3 as "thirty" without altering the value. Preceding numbers with zero will help us in "fixed width" numbers.

Sometimes you would have come across fixed width numbers, say for example when filling in the postal code in your post card (the one in the picture has 6 boxes for postal code at the bottom of the address area). Fixed width numbers are always represented with fixed number of digits (6 digits in the post card shown in the picture below). If my postal code is "Five hundred and eighty seven" I cannot simply write 5, 8 and 7 as I have 6 boxes to fill, so I must write 0, 0, 0, 5, 8, 7, thus filling all the boxes without damaging the value. With fixed width number we also come across two interesting properties the maximum and minimum representation. With six boxes the minimum code one could use would be 0, 0, 0, 0, 0, 0 and the maximum number could be 9, 9, 9, 9, 9, 9 (Anything above this number cannot be fit in).

Typically the minimum value of any "fixed width" number be 0 and the maximum will be (base raised to the power of width - 1). That means, fixed width numbers could represent N unique values from "minimum" to "maximum" where N will be (base raised to the power of width). For example if my width is 2 and base is 10 then I can represent 100 unique values from 00,01,02, ... to 99.
(to be continued ...)

Wednesday, October 6, 2010

Understanding execution environment (Introduction) - I

If you have read 'C' standards, you would have come across two different execution environments

1. Hosted Environment
2. Freestanding Environment

You are well aware of what is meant by "Environment" eh? If not you could better consult an "Environmentalist" ;-) All right lets assume you know enough of 'Environment', now let us see what it means to a programmer or a system Engineer. Just like how you get whatever you need to live from the environment that surrounds you, your program also gets support from the environment that surrounds it. Understanding that will help you to write better programs, debug problems quickly etc. Let us try to map our environments to the real environment we live in.

Have you ever thought of what are the basic things that the environment that we live in provides? Below is a small list which comes from your environment, although we are not very much aware of it our life depends on it
  • Air you breathe
  • Light and Heat
  • A ground to stand (Gravity to hold :-D)
  • Water and Food
  • People around you (Drivers, Gas station assistants, tailors, farmers etc.)
  • Vehicles and Tools (Cars, buses, computers, etc.)
  • Houses, Shops and other support infra-structure
and many more...

In the above list the first 4 items are considered as essential requirements, without which life is not possible, all those items are provided by the planet and the universe you live in, rest of the items are optional but they are required to make your life incredibly easy. Just like how "you" (analogous to program) "live your life"(analogous to program execution), doing things you do, with the support from your environment; your program uses the environment provided by the system to do its tasks. It is quite suitable to think yourself as the program and the universe you live in as the system at which your program executes.

In computer, programs are provided with an environment comparable to our living environment, a quick list would be
  • Hardware Units (Memory, Input, Processing, Output, Network etc.)
  • Operating System
  • Shells (See shells chapter)
  • Support software (Libraries, BIOS routines etc)
  • Support applications

This case is similar to our own environment, the first item is essential requirement, of course without the correct hardware the program stands useless; the rest of all are optional yet it makes the program's development and execution incredibly easier. Having understood something about environment let us come to our "Hosted/Freestanding" environment.

Hosted Environment -- Is nothing but the current environment that you live in, you got everything to make your life possible as well as easy, when it comes to a program it gets all essential and luxury items for its execution. Say for example if you want to drive from place X to Y you can simply hop inside a car (Hire a driver if you want to) go to the gas station get your tank filled by the assistant and use the road to reach Y!

Freestanding Environment -- When you are given only the essential environment items and no or little optional items, then you are in a freestanding environment!!! (Have you seen the movie "I am Legend"?) Unlike hosted environment you will have almost million or more possibilities here, like you might get just Essential items + Vehicles + gas stations (You might have to fill in the gas yourself and drive the car yourself, repair yourself). Worst case you might be given only the essential environment items only, in that case you might have to build your own vehicle and make your own road to reach Y from X, you have to grow your own food etc.!!

(Continued in next part...)