/* Copyright (C) 1993,1994 by the author(s).
 
 This software is published in the hope that it will be useful, but
 WITHOUT ANY WARRANTY for any part of this software to work correctly
 or as described in the manuals. See the ShapeTools Public License
 for details.

 Permission is granted to use, copy, modify, or distribute any part of
 this software but only under the conditions described in the ShapeTools 
 Public License. A copy of this license is supposed to have been given
 to you along with ShapeTools in a file named LICENSE. Among other
 things, this copyright notice and the Public License must be
 preserved on all copies.
*/
/*
 * main module of rcs2atfs
 *
 * Author: Juergen Nickelsen (Juergen.Nickelsen@cs.tu-berlin.de)
 *
 * $Header: main.c[3.0] Tue Jun 29 16:38:02 1993 andy@cs.tu-berlin.de frozen $
 */

#include "atfs.h"
#include "sttk.h"
#include "rcs2atfs.h"
#include "functions.h"

char *progname ;		/* for usage message etc. */
int warnings = 0 ;		/* no. of warnings occurred (not used) */
int errors = 0 ;		/* no. of errors occured */

bool use_pipe = true ;		/* use pipe to shell */
bool recursive = false ;	/* recursively descend dir.-tree */
bool keep_quiet = false ;	/* don't issue warnings */


/* description of options for ParseArgs:
 *    option string, whattodo, opt.function, var. to set, ???
 */
static StOptDesc optDesc[] = {
  { "o", PCALL|PARG, read_out_name, NULL, NULL},
  { "R", PSET, NULL, &recursive, NULL },
  { "q", PSET, NULL, &keep_quiet, NULL },
  { "version", PCALL, (int (*)()) echo_version, NULL,NULL},
  { NULL, 0, NULL, NULL, NULL }
} ;

char *shellscript ;		/* name of generated shell script */

/*ARGSUSED*/
int read_out_name(o, arg)
char *o, *arg ;
{
    shellscript = arg ;
    use_pipe = false ;
    return 0 ;
}

void usage()
{
    (void) fprintf(stderr, "Usage: %s [-o outputfile] [-q] history ...\n",
		   progname) ;
    (void) fprintf(stderr, "       %s [-o outputfile] [-q] -R directory ...\n",
		   progname) ;
}


/* main function (this should be obvious) */

int main(argc, argv)
int argc ;
char **argv ;
{
    char *rcs_history ;		/* name of RCS history to convert */
    int nargc ;			/* argc changed by ParseArgs */
    char **nargv ;		/* argv changed by ParseArgs() */
    FILE *out ;			/* shell commands are written here */
    extern int pclose() ;
    extern int fclose() ;
    
    /* extract name of this program */
    progname = strrchr(argv[0], '/') ;
    progname = (progname == NULL) ? argv[0] : progname + 1 ;
    
#if defined(sun) && defined(DEBUG)
    /* call life saver */
    malloc_debug(2) ;
#endif /* sun, DEBUG */
    
    
    /* parse argument list for option settings */
    if (stParseArgs(argc, argv, &nargc, &nargv, optDesc) || nargc < 2) {
	usage() ;
	(void) exit(1);
    }

    /* determine command output */
    if (use_pipe) {
	/* open pipe to Bourne Shell */
	if ((out = popen(BOURNE_SHELL, "w")) == NULL) {
	    fatal(POPEN_SHELL, sys_errlist[errno]) ;
	}
    } else {
	/* open output file for script */
	if ((out = fopen(shellscript, "w")) == NULL) {
	    fatal(sys_errlist[errno], shellscript) ;
	}
	/* insert some header into shell script (#!/bin/sh etc.) */
	fprintf(out, SCRIPT_HEADER, "rcs2atfs-1.9") ;
    }
    
    
    /* repeat for all arguments */
    *nargv++; /* skip command name */
    while ((rcs_history = *nargv++) != NULL) {
	convert(rcs_history, out) ;
    }
    
    if (!keep_quiet) fprintf(out, "\necho Done.\n") ;

    fprintf(out, "exit\n") ;
    (use_pipe ? pclose : fclose) (out) ;

    return errors ;
}


/* convert fname, if recursive, maybe directory */
void convert(fname, out)
char *fname ;
FILE *out ;
{
    struct RCSFILE *rcsfile ;	/* to be returned by readin_rcsfile() */
    char *newfname ;		/* to construct a new filename */
    char *dirname ;		/* dir file resides in */
    struct AFIND_STATE astate;	/* state information for afind */
    char *found_file ;		/* file found by afind */

    switch (file_type(fname)) {
      case f_plain:		/* is a plain file */
	if (recursive) {
	    return ;		/* comes from readdir if RCS archive
				 * exists; we will get at it later */
	} else {
				/* if not recursive: does a history exist? */
	    rcsfile = readin_rcsfile(fname) ;
	    if (rcsfile != NULL) {
		if (atfs_exists(fname)) {
		    error(AtFS_EXISTS, fname) ;
		} else {
		    dirname = strip_last(fname) ;
		    make_shell_script(dirname, rcsfile, out) ;
		    (void) free(dirname) ;
		}
		free_rcsfile(rcsfile) ;
	    }
	}
	break ;
      case f_dir:		/* is a directory */
	if (! recursive) {	/* we ignore dirs if not recursive */
	    warning(NOT_RECURSIVE, fname) ;
	    return ;
	}
				/* if recursive, we look into them */
	if (afind_init(fname, &astate) == -1) {
	    warning("", fname) ;
	    af_perror(fname) ;
	    return ;
	}
	while ((found_file = afind_read(&astate)) != NULL) {
				/* don't look at itself, parent,
				 * and AtFS directories */
	    if (!strcmp(found_file, "..") || !strcmp(found_file, ".") ||
		!strcmp(found_file, AF_SUBDIR) ||
		!strcmp(found_file, "AFS")) {
		continue ;
	    }
	    newfname = addstr3(fname, "/", found_file) ;
	    free(found_file) ;
	    convert(newfname, out) ;
	    free(newfname) ;
	}
	afind_close(&astate) ;
	break ;
      case f_rcs:		/* is RCS archive file */
	rcsfile = readin_rcsfile(fname) ;
	if (rcsfile != NULL) {
	    dirname = strip_last(fname) ;
	    if (dirname != NULL && file_type(dirname) == f_rcsdir) {
				/* is RCS archive in RCS directory */
		char *tmp = dirname ;
		dirname = strip_last(dirname) ;
		free(tmp) ;
	    }
	    newfname = addstr3(dirname, "/", rcsfile->working_file) ;
	    if (atfs_exists(newfname)) {
		error(AtFS_EXISTS, newfname) ;
	    } else {
		make_shell_script(dirname, rcsfile, out) ;
	    }
	    free(dirname) ;
	    free(newfname) ;
	    free_rcsfile(rcsfile) ;
	}
	break ;
      case f_rcsdir:		/* is RCS directory */
	convert_rcsdir(fname, out) ;
	break ;
      default: ;		/* can only be f_error, but that doesn't
				 * matter anymore */
    }	
}


/* convert a directory named RCS */

void convert_rcsdir(rdir, out)
char *rdir ;
FILE *out ;
{
    DIR *dirp ;			/* for reading... */
    struct dirent *dep ;	/* ... directory entries */
    struct RCSFILE *rcsfile ;	/* to be returned by readin_rcsfile() */
    char *basedir ;		/* name of dir. RCS directory lies in */
    char *rcs_archive ;		/* name of RCS archive in rdir */

    /* where is the working dir. of this RCS archive? */
    basedir = strip_last(rdir) ; /* may be NULL */
    
    if ((dirp = opendir(rdir)) == NULL) {
	warning(sys_errlist[errno], rdir) ;
	free(rdir) ;
	return ;
    }
    while ((dep = (struct dirent *)readdir(dirp))) {
	rcs_archive = addstr3(rdir, "/", dep->d_name) ;
	if (file_type(rcs_archive) == f_rcs) {
				/* convert only RCS archives */
	    rcsfile = readin_rcsfile(rcs_archive) ;
	    if (rcsfile != NULL) {
		char *tmp = addstr3(basedir, "/", rcsfile->working_file) ;
		if (atfs_exists(tmp)) {
		    error(AtFS_EXISTS, tmp) ;
		} else {
		    make_shell_script(basedir, rcsfile, out) ;
		}
		free(tmp) ;
		free_rcsfile(rcsfile) ;
	    }
	}
	free(rcs_archive) ;
    }
    if (basedir != NULL) free(basedir) ;
    closedir(dirp) ;
}
	    
/*EOF*/
