/* file.c - Functions to read the status file for deborphan.
   Copyright (C) 2000, 2001, 2002, 2003 Cris van Pelt
   Copyright (C) 2003, 2004 Peter Palfrader
   Copyright (C) 2008 Andrej Tatarenkow
   Copyright (C) 2008 Carsten Hey

   $Id: file.c 756 2009-02-19 08:10:54Z carsten-guest $

   Distributed under the terms of the Artistic License.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>

#include <config.h>
#include <deborphan.h>
#include <xalloc.h>

#ifdef HAVE_ERRNO_H
#  include <errno.h>
#endif

#ifdef LOW_MEM
/* Be nice. This uses a little more memory than the longest line in your
 * status file (which probably means some 100 bytes).
 *
 * This is more or less how everything was handled before version 0.1.20.
 */
FILE *
debopen(const char *file)
{
    FILE *f;

    f = fopen(file, "r");

    return f;
}

char *
nextline(FILE **fp)
{
    char t[32];
    static int i =  32;
    static char *s;
    if (!s)
	s = xmalloc (i);

    if (!fgets(s, i, *fp))
	return NULL;

    if (!strchr(s, '\n') && strlen(s) < (i - 1))
        s[strlen(s)] = '\n';

    while (!strchr(s, '\n')) {
	if (!fgets(t, 32, *fp))
	    return NULL;
	s = xrealloc(s, (i+=32));
	strcat(s, t);
    }
    *(strchr(s, '\n')) = '\0';

    return s;
}

#else
/* Don't be nice. This uses up as much memory as your status file (near a
 * megabyte). It is considerably faster, though.
 */
char *
debopen(const char *file)
{
    int fd;
    char *buf;
    struct stat statbuf;

    fd = open(file, O_RDONLY);
    if (fd < 0)
	return NULL;

    if (fstat(fd, &statbuf) < 0)
	return NULL;

    buf = (char *) xmalloc((size_t) (statbuf.st_size + 1));

    if (read(fd, buf, (size_t) statbuf.st_size) < statbuf.st_size) {
	close(fd);
	free(buf);
	return NULL;
    }

    buf[statbuf.st_size] = '\0';
    close(fd);

    return buf;
}

/* This function is similar to strsep(s, "\n"), but I have the feeling this
 * is faster, because it only checks for '\n'. Well, that, and I just like 
 * writing this *(s+1) stuff.
 */
char *
nextline(char **s)
{
    int i = 0;
    char *a = *s;
    char *n;
    
    if (!a)
	return NULL;

    for (n = *s; *n && *n != '\n'; n++, i = 1);

    if (*n == '\0' && i == 0)
	return NULL;

    *n = '\0';
    *s = n + 1;

    return a;
}
#endif /* ! LOW_MEM */

int
zerokeep(const char *file)
{
     int fd = open(file, O_WRONLY | O_TRUNC);
     if (fd < 0) {
        if (errno == ENOENT) /* It not existing at all is fine too */
	    return 0;
	else
	    return -1;
     }
     close(fd);
     return 0;
}
