/* $Id: atomu-1.2.c,v 1.1 2011/04/27 01:22:30 homer Exp $ */
/* Like `>' in sh, but atomic. Also, will not write an empty file. */
/* Unix C */

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    char *fout;
    char ftmp[] = "atomu-XXXXXX";
    int fd = mkstemp(ftmp);
    FILE *f;
    int c;
    int empty = 1;

    if (argc != 2) {
        fprintf(stderr, "Args: FILENAME\n");
        return EXIT_FAILURE;
    }

    fout = argv[1];

    if (fd == -1) {
        perror("mkstemp");
        return EXIT_FAILURE;
    }

    f = fdopen(fd, "w");
    if (f == NULL) {
        perror("fdopen");
        unlink(ftmp);
        return EXIT_FAILURE;
    }

    while ((c = getchar()) != EOF) {
        fputc(c, f); /* Not checking for errors (any way to recover?) */
        empty = 0;
    }

    if (fclose(f) == EOF) {
        perror("fclose");
    }

    if (empty) {
        /* Not writing an empty file */
        unlink(ftmp);
        return 0;
    }

    if (rename(ftmp, fout) != 0) {
        /* keeping the tmp file on error */
        #define len 512
        char s[len];
        snprintf(s, len, "rename(\"%s\", \"%s\")", ftmp, fout);
        s[len - 1] = '\0';
        perror(s);
    }

    return 0;
}
