Le 4 janvier 2011 07:57, Frédéric Benninger <[email protected]> a écrit :
> Car il s’agit bien de garder une certaine quantité de données (ko ou
> nb lignes)  à partir de la fin d’un fichier en s’arrêtant à un saut de
> ligne.

Oui bien sûr, j'étais à coté de la plaque.
Du coup le programme en C devient plus compliqué...
J'ai fait ça:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void usage(const char *argv0)
{
        fprintf(stderr, "%s lines files...\n", argv0);
        exit(1);
}

int get_prev_char(int fd, char *pc)
{
        if (lseek(fd, -1, SEEK_CUR) == -1) return -1;
        if (read(fd, pc, 1) == -1) return -1;
        if (lseek(fd, -1, SEEK_CUR) == -1) return -1;
        return 0;
}

int copy_end_to_start(int fd, off_t read_pos)
{
        off_t write_pos = 0;
        char c;
        ssize_t read_ret;
        while ((read_ret = read(fd, &c, 1)) == 1) {
                ++read_pos;
                if (lseek(fd, write_pos, SEEK_SET) == -1) return -1;
                if (write(fd, &c, 1) != 1) return -1;
                ++write_pos;
                if (lseek(fd, read_pos, SEEK_SET) == -1) return -1;
        }
        if (read_ret != 0) return -1;
        return 0;
}

void shrink(const char *fn, long lines)
{
        const int fd = open(fn, O_RDWR);
        if (fd == -1) goto error;
        const off_t fsize = lseek(fd, 0, SEEK_END);
        if (fsize == -1) goto error;
        off_t fpos = fsize;
        long count_lines = 0;
        while (fpos > 0 && count_lines <= lines) {
                char c;
                if (get_prev_char(fd, &c) == -1) goto error;
                --fpos;
                if (c == '\n' || count_lines == 0) ++count_lines;
        }
        if (fpos > 0) {
                if (lseek(fd, 1, SEEK_CUR) == -1) goto error;
                if (copy_end_to_start(fd, fpos + 1) == -1) goto error;
                if (ftruncate(fd, fsize - fpos - 1) == -1) goto error;
        }
        close(fd);
        return;
error:
        perror(fn);
        if (fd != -1) close(fd);
}

int main(int argc, char **argv)
{
        if (argc < 3) usage(argv[0]);
        
        char *endptr;
        const long lines = strtol(argv[1], &endptr, 10);
        if (*argv[1] == '\0' || *endptr != '\0' || lines < 0)
                usage(argv[0]);

        for (int i = 2; i < argc; ++i)
                shrink(argv[i], lines);

        return 0;
}
_______________________________________________
gull mailing list
[email protected]
http://forum.linux-gull.ch/mailman/listinfo/gull

Répondre à