Questa funzione, formatta o ritorna la grandezza visualizzata di un file o di una directory. Prende come parametri la grandezza in bytes e il tipo da visualizzare, se non viene specificato nessun tipo, formatta la grandezza automaticamente.

I tipi supportati sono ‘b’ per bytes, ‘k’ per kilobytes, ‘m’ per megabytes, ‘g’ per gigabites oppure 0 per la formattazione automatica. Alloca memoria dinamica quindi bisogna liberarla quando si è finito di usarla.

Notare come questa funzione si prende cura di formattare graziosamente l’output e approssimarlo proporzionalmente alla grandezza evitando di ritornare risultati del tipo 1000 bytes (restituirà infatti 0,98kb), che non corrispondono ancora 1 kilobyte, ma sono brutti da vedere.

char *format_size(unsigned long bytes, char type) {
    unsigned long divfactor;
    char *retfmt = NULL;
#define RETSIZE 128
    switch (type) {
        case 'b':
            divfactor = 1;
            break;
        case 'k':
            divfactor = 1024;
            break;
        case 'm':
            divfactor = 1024 * 1024;
            break;
        case 'g':
            divfactor = 1024 * 1024 * 1024;
            break;
        default:
            divfactor = 0;
    }
    retfmt = (char *)malloc(RETSIZE+1);
    if (!retfmt) return NULL;
    if (divfactor) {
        snprintf(retfmt, RETSIZE, "%lu", (bytes / divfactor));
    } else {
        float kb = bytes / 1024.00;
        if (bytes < 1000) {
            snprintf(retfmt, RETSIZE, " %d", (int)bytes);
        } else if (bytes < 1024) {
            snprintf(retfmt, RETSIZE, "%0.2fk", kb);
        } else if (kb < 10) {
            snprintf(retfmt, RETSIZE, "%1.1fk", kb);
        } else {
            float mb = kb / 1024.00;
            if (kb < 1000) {
               snprintf(retfmt, RETSIZE, "%3.0fk", kb);
            } else if (kb < 1024) {
               snprintf(retfmt, RETSIZE, "%0.2fM", mb);
            } else if (mb < 10) {
               snprintf(retfmt, RETSIZE, "%1.1fM", mb);
            } else {
                float gb = mb / 1024.00;
                if (mb < 1000) {
                    snprintf(retfmt, RETSIZE, "%3.0fM", mb);
                } else if (mb < 1024) {
                    snprintf(retfmt, RETSIZE, "%0.2fG", gb);
                } else if (gb  < 10) {
                    snprintf(retfmt, RETSIZE, "%1.1fG", gb);
                } else {
                    snprintf(retfmt, RETSIZE, "%3.0fG", gb);
                }
            }
        }
    }
    return retfmt;
}