#include <stdlib.h>
#include <string.h>
#include "flx.h"
#include "output_file.h"
#include "input_file.h"
#include "check.h"
#include "output.h"
#define STAT_WRITESUBDIR (1<<0)
#define STAT_DOINIT (1<<1)
#define STAT_VIEWSORTED (1<<2)
#define OPT_SORTED 0x01
#define OPT_WRITE 0x02
#define OPT_LS 0x04
/* affiche le contenu d'un répertoire à partir de l'emplacement spécifié en
* reprenant son nom
*/
int output_file_write_(t_file_status *desc, t_ft *tree,
int number, char *(*desc_to_str)()) {
char *pcpath, *pbpath;
int count = 0;
/* output initialization */
if (IS(desc->status, STAT_DOINIT)) {
UNSET(desc->status, STAT_DOINIT);
}
/* nothing have change, do not free */
if (number > 0 &&
IS(Sorted, OUTPUT_SORTED) && !IS(Sorted, INPUT_SORTED)) return (0);
/* initialize path pointers */
pcpath = desc->cpath + strlen(desc->cpath);
pbpath = desc->bpath + strlen(desc->bpath);
tree = ft_get(tree, desc->cpath);
/* find a valid directory */
while (!IS(tree->status, CHANGED) && SIMPLE_LIST_NEXT(desc->fdstack)) {
pcpath = REMOVE_DIR(desc->cpath, pcpath); *pcpath = 0;
pbpath = REMOVE_DIR(desc->bpath, pbpath); *pbpath = 0;
desc->recursion--;
tree = tree->parent;
}
/* start from changed subdirectory */
if (!tree->subtree || !IS(tree->status, CHANGED) || IS(tree->status, SORTING)) {
return (0);
}
tree = tree->subtree->next;
while (desc->fdstack) {
/* write all in the subdirectory */
while (!IS(tree->status, BASE)) {
/* nothing to do, pass */
if (!IS(tree->status, CHANGED)) { tree = tree->next; continue; }
/* the status have change, something to do with it, update path */
ADD_PATH(desc->cpath, pcpath, tree->filename);
/* filename have been newly filled */
if (IS(tree->status, FILLED)) {
char *str = desc_to_str(desc->cpath, pcpath, tree->desc);
if (str) {
fprintf(desc->fd, "%s\n", str);
count++;
}
}
/* stop recursion when an output is sorted and
* and this directory isn't finished to fill */
if (number > 0 &&
IS(desc->status, STAT_VIEWSORTED) && IS(tree->status, SORTING)) {
*pcpath = 0;
return (count);
}
/* treat sub directory, not for back pointers (. and ..) */
if (tree->subtree && !IS_DOTF(tree->filename)) {
/* add backup file descriptor for this level */
SIMPLE_LIST_PUSH(desc->fdstack, desc->fd);
/* backup directory filename and new position */
pcpath += strlen(pcpath);
if (desc->recursion > 0) {
FILE *newfd;
/* build new path, and new fd and so continue */
pbpath = ADD_PATH(desc->bpath, pbpath, tree->filename);
if (mkdir_with_parent(desc->bpath, ~GET_UMASK() & 0777)) {
/* open new fd for this directory */
ADD_PATH(desc->bpath, pbpath, DUMPBASENAME);
if (!(newfd = fopen(desc->bpath, "w")))
PFERROR("fopen(%s)", desc->bpath);
else
desc->fd = newfd;
}
/* remove filename from bpath */
*pbpath = 0;
}
/* recursion level (can be negative) */
desc->recursion--;
/* go subtree */
tree = tree->subtree->next;
continue;
}
/* look for next */
tree = tree->next;
}
/* remove added filenames */
*pcpath = 0;
/* verify that all files are readed */
if (number > 0 &&
IS(tree->parent->status, READING)) return (count);
/* search old path */
pcpath = REMOVE_DIR(desc->cpath, pcpath); *pcpath = 0;
/* recursion level : up */
desc->recursion++;
/* if recursion level, can close old fd */
if (desc->recursion > 0) {
pbpath = REMOVE_DIR(desc->bpath, pbpath); *pbpath = 0;
fclose(desc->fd);
}
/* get last fd */
desc->fd = SIMPLE_LIST_POP(desc->fdstack);
/* restore backuped position */
tree = tree->parent->next;
}
return (count);
}
int output_file_write(t_file_status *desc, t_ft *tree, int number) {
if ((desc->options & OPT_LS) == OPT_LS)
return (output_file_write_(desc, tree, number, show_filename));
else
return (output_file_write_(desc, tree, number, build_line));
}
/* traduct a string options descriptions to flags
*/
int output_file_fcntl(t_file_status *env, int cmd) {
return (0);
}
t_file_status *output_file_open(char *pathname, char *opts) {
t_file_status *new;
char *filename;
int status, ret;
char tmp[BUFFER_LENGTH];
char *ppath, *popts, *pvalue;
int options = (OPT_SORTED|OPT_WRITE);
popts = opts ? strcpy(tmp, opts) : NULL;
ppath = pathname ? strcpy(tmp + strlen(tmp) + 1, pathname) : NULL;
/* memory allocation for new element */
new = MALLOC(sizeof(*new));
bzero(new, sizeof(*new));
new->recursion = 0;
/* part to get source specific options */
while (popts) {
int sign = 1;
char *t;
/* select an option and its value */
if ((t = strchr(popts, '+'))) *t++ = 0;
if ((pvalue = strchr(popts, '='))) *pvalue++ = 0;
/* remove negative */
while (*popts == '!') { sign = -sign ; popts++; }
/* treat option */
if (!*popts) continue;
else if (!strcmp(popts, "sort")) /* sorted flag */
options = (sign > 0 ? (options|OPT_SORTED) : (options&~OPT_SORTED));
else if (!strcmp(popts, "level") && pvalue) /* recurse level */
new->recursion = atoi(pvalue);
else if (!strcmp(popts, "ls")) /* just list flag */
options = options|OPT_LS;
else {
error("unknown option : %s", popts);
FREE(new);
return (0);
}
popts = t;
}
new->options = options;
filename = ppath;
if (ppath && (ppath = backslashed_strmchr(ppath, DELIM_LIST))) {
status = *ppath++;
}
SET(new->status, STAT_VIEWSORTED); /* default is sorted */
SET(new->status, STAT_DOINIT);
if (!filename || !filename[0] || !strcmp(filename, "-")) {
/* special case for stdout */
new->fd = stdout;
}
else {
struct stat st;
/* case for files, should stat them */
if (!(ret = stat(filename, &st)) && S_ISDIR(st.st_mode)) {
/* directory, directory treatment */
/* build base filename path */
strcpy(new->bpath, filename);
filename = new->bpath + strlen(new->bpath);
ADD_PATH(new->bpath, filename, DUMPBASENAME);
/* open the file */
if (!(new->fd = fopen(new->bpath, "w"))) {
PFERROR("fopen(%s)", new->bpath);
exit(3);
}
*filename = 0;
}
else {
/* can get confirmation */
/* can test and open */
if (!(new->fd = fopen(filename, "w"))) {
PFERROR("fopen(%s)", filename);
exit(3);
}
}
}
/* initialise file descriptor stack */
new->fdstack = NULL;
SIMPLE_LIST_PUSH(new->fdstack, new->fd);
return (new);
}
t_file_status *output_file_close(t_file_status *old) {
while (old->fdstack && old->recursion < 0) {
SIMPLE_LIST_POP(old->fdstack);
old->recursion--;
}
if (old->fd && old->fd != stdout) fclose(old->fd);
while (old->fdstack) {
old->fd = SIMPLE_LIST_POP(old->fdstack);
fclose(old->fd);
}
FREE(old);
return (NULL);
}
t_file_status *output_stdout_open(char *desc, char *opts) {
if ((desc = backslashed_strmchr(desc, DELIM_LIST)))
return (output_file_open(desc, opts));
return (output_file_open("", opts));
}