/*
 * shapeTools -- atfsit
 *
 * $Header: atfsit.c[4.0] Tue May 11 15:52:13 1993 andy@cs.tu-berlin.de frozen $
 *
 * derived from:
 * rcsit -- 	Prepare files for RCS.  rcsit puts the correct headings
 *		at the top of files to prepare them for RCS headings
 *		and log tracking.
 *
 * Michael Cooper	(mcooper@usc-oberon.arpa)
 * University Computing Services, USC
 *
 * 9-16-85
 *
 */

#include <ctype.h>
#include "config.h"

char    *atfsit_version();

#define LENGTH		512		/* length of line */
#define TRUE  1
#define FALSE 0

#ifdef DEBUG
 int debugon = TRUE;
#else
 int debugon = FALSE;
#endif

static char 	*progname;		/* program name */
static char 	*rcsdir;

/*
 * Messages to be printed for the user.
 */
static char	*msg_name;		
static char 	*m_stdc = "Standard C",
                *m_stdcflg = "Standard C with compile flags",
		*m_include = "C Include",
		*m_fortran = "Fortran",
                *m_elisp = "Emacs Lisp",
		*m_make	= "Makefile",
		*m_shape = "Shapefile",
		*m_shell = "Shell Script",
		*m_manual = "Manual";

/*
 * The headers to put at the beginning of the file(s).
 * Notice that the words Header and Log do not appear here
 * because RCS will put in the keyword substitutions when rcsit.c
 * is co'ed.
 */
static char	*header;
#ifdef RCSIT
static char	*h_stdc = 
	"#ifndef lint\nstatic char *RCSid = \"$%s$\";\n#endif\n/*\n * $%s$\n */\n\n";
static char	*h_stdcflg = 
	"#ifndef lint\nstatic char *RCSid = \"$%s$\";\n#ifdef CFFLGS\n\
static char *ConfFlg = CFFLGS;\n\t/* should be defined from within\
 Makefile */\n#endif\n#endif\n/*\n * $%s$\n */\n\n";
#else
static char	*h_stdc = 
	"#ifndef lint\nstatic char *AtFSid = \"$%s$\";\n#endif\n/*\n * $%s$\n */\n\n";
static char	*h_stdcflg = 
	"#ifndef lint\nstatic char *AtFSid = \"$%s$\";\n#ifdef CFFLGS\n\
static char *ConfFlg = CFFLGS;\n\t/* should be defined from within\
 Makefile */\n#endif\n#endif\n/*\n * $%s$\n */\n\n";
#endif
static char	*h_include = 
	"/*\n * $%s$\n *\n * $%s$\n */\n\n";
static char	*h_make =
	"#\n# $%s$\n#\n# $%s$\n#\n";
static char	*h_shape =
	"#\n# $%s$\n#\n# $%s$\n#\n";
static char     *h_elisp = 
        ";;\n;; $%s$\n;; $%s$\n;;\n";
static char 	*h_manual =
	"...\n... $%s$\n... \n... $%s$\n...\n";
static char 	*h_fortran =
	"c\nc $%s$\nc\nc $%s$\nc\n";

/*
 * Template file names
 */
static char	*template_c 	= ".template.c";	/* .c template */
static char 	*template_h 	= ".template.h";	/* .h template */
static char 	*template_f 	= ".template.f";	/* .f template */
static char 	*template_man 	= ".template.man";	/* man template */
static char	*template_make	= ".template.make";	/* make template */
static char	*template_shape	= ".template.shape";	/* shape template */
static char	*template_elisp	= ".template.el";	/* elisp template */
static char	*template_sh	= ".template.sh";	/* sh script template */
static char	*tpath;					/* path to template */
static char	tfile[BUFSIZ];				/* template file */
static char	tbuf[BUFSIZ];				/* current tfile */

/*
 * Command line flags
 */
int	Iflag	= FALSE;			/* run ci(1) or save(1) */
int	rcsflag = FALSE;			/* run rcs(1) or vadm(1) */
int	aflag	= TRUE;				/* do auto guess */
int	dflag	= TRUE;				/* creat RCS or AtFS dir. */
int	qflag	= FALSE;			/* be quiet! */
int 	cflag	= FALSE;			/* std c file */
int	fflag	= FALSE;			/* fortran file */
int     Fflag   = FALSE;                        /* insert C-Flags header */
int	pflag	= FALSE;			/* pascal file */
int	eflag	= FALSE;			/* elisp file */
int	Sflag	= FALSE;			/* Shapefile */
int	hflag	= FALSE;			/* include file */
int	sflag	= FALSE;			/* shell script */
int 	mflag	= FALSE;			/* Makefile */
int	Mflag	= FALSE;			/* manual */
int	tflag	= FALSE;			/* template flag */

int     atfsit   = FALSE;                        /* progam called as "atfsit" */


/*
 * debug - print (useless) debugging info.
 */
 
static void debug(msg)
char *msg;
{
#ifdef DEBUG
	fprintf(stderr, msg);
	fputc('\n', stdout);
#endif
}

/*
 * fatal - print error and then exit(1).
 */
static void fatal0(str)
char *str;
{
	fprintf(stderr, "%s: %s\n", progname, str);
	exit(1);
}
static void fatal1(format, str)
char *format, *str;
{
	char namefmt[100];

	sprintf(namefmt, "%s: %s\n", progname, format);
	fprintf(stderr, namefmt, str);
	exit(1);
}
static void fatal2(format, str1, str2)
char *format, *str1, *str2;
{
	char namefmt[100];

	sprintf(namefmt, "%s: %s\n", progname, format);
	fprintf(stderr, namefmt, str1, str2);
	exit(1);
}

/*
 * zap str with NULL's
 */

static void zap(str)
char str[];
{
	int i, x;

	i = strlen(str);
	for(x = 0; x <= i; )
		str[x++] = '\0';
}

/*
 * set_flags - set & check flags
 */
 
static void set_flags()
{
	if(cflag || eflag || hflag || mflag || Mflag || sflag || Sflag 
	   || fflag) {
		if(cflag) {
			msg_name = m_stdc;
			header = h_stdc;
		}
		if(eflag) {
			msg_name = m_elisp;
			header = h_elisp;
		}
		if (Fflag) { /* This is more than just cflag - axel@coma */
		        msg_name = m_stdcflg;
			header = h_stdcflg;
		}
		if(hflag) {
			msg_name = m_include;
			header = h_include;
		}
		if(mflag) {
			msg_name = m_make;
			header = h_make;
		}
		if(Mflag) {
			msg_name = m_manual;
			header = h_manual;
		}
		if(sflag) {
			msg_name = m_shell;
			header = h_make;
		}
		if(Sflag) {
			msg_name = m_shape;
			header = h_shape;
		}
		if(fflag) {
			msg_name = m_fortran;
			header = h_fortran;
		}
	} else {
		cflag = TRUE;
		set_flags();
	}
}

/*
 * auto_guess - try and be intelligent and guess type of file
 *		by looking at the suffix or the whole name
 *		in the case of a makefile.
 */

static void auto_guess(file)
char	*file;
{
	char *suffix;

	(suffix = strrchr(file, '.')) ? suffix++ : (suffix = "");
	/* fixed by jmp@inesc */
	if((strcmp(file, "makefile") == 0) || 
	   (strcmp(file, "Makefile") == 0) ||
	   (strcmp(file, "shapefile") == 0) ||
	   (strcmp(file, "Shapefile") == 0) ||
	    (strcmp(suffix, "mk") == 0)) {	/* sys V std suffix */
		mflag = TRUE;
		sflag = FALSE;
		Sflag = FALSE;
		cflag = FALSE;
		eflag = FALSE;
		hflag = FALSE;
		Mflag = FALSE;
		fflag = FALSE;
	}
	if((strcmp(suffix, "sh") == 0) || (strcmp(suffix, "csh") == 0)) {
		sflag = TRUE;
		Sflag = FALSE;
		cflag = FALSE;
		eflag = FALSE;
		hflag = FALSE;
		mflag = FALSE;
		Mflag = FALSE;
		fflag = FALSE;
	}
	if(strcmp(suffix, "c") == 0){
		cflag = TRUE;
		eflag = FALSE;
		hflag = FALSE;
		mflag = FALSE;
		Mflag = FALSE;
		sflag = FALSE;
		Sflag = FALSE;
		fflag = FALSE;
	}
	if(strcmp(suffix, "el") == 0){
		eflag = TRUE;
		cflag = FALSE;
		hflag = FALSE;
		mflag = FALSE;
		Mflag = FALSE;
		sflag = FALSE;
		Sflag = FALSE;
		fflag = FALSE;
	}
	if(strcmp(suffix, "h") == 0){
		hflag = TRUE;
		cflag = FALSE;
		eflag = FALSE;
		mflag = FALSE;
		Mflag = FALSE;
		sflag = FALSE;
		Sflag = FALSE;
		fflag = FALSE;
	}
	if(strcmp(suffix, "f") == 0){
		fflag = TRUE;
		hflag = FALSE;
		cflag = FALSE;
		eflag = FALSE;
		mflag = FALSE;
		Mflag = FALSE;
		sflag = FALSE;
		Sflag = FALSE;
	}
	if(strcmp(suffix, "S") == 0){
		Sflag = TRUE;
		fflag = FALSE;
		hflag = FALSE;
		cflag = FALSE;
		eflag = FALSE;
		mflag = FALSE;
		Mflag = FALSE;
		sflag = FALSE;
	}
	if(isdigit(*suffix) != 0) {
		Mflag = TRUE;
		hflag = FALSE;
		cflag = FALSE;
		eflag = FALSE;
		mflag = FALSE;
		sflag = FALSE;
		Sflag = FALSE;
		fflag = FALSE;
	}
	set_flags();
	if(!qflag || debugon)
		printf("Hmm.  This file looks like a %s file.\n", msg_name);
}

/*
 * copy from -> to
 */

static void copy(from, to, mode)
char *from;
char *to;
char *mode;
{
	FILE *fdfrom, *fdto;
	char s[LENGTH];

	if((fdfrom = fopen(from, "r")) == NULL) {
		fatal1("Cannot open %s for reading.",from);
	}
	if((fdto = fopen(to, mode)) == NULL) {
		fatal2("Cannot open %s for \"%s\".",to,mode);
	}
	while(fgets(s, sizeof(s), fdfrom) != NULL)
		fputs(s, fdto);
	fclose(fdfrom);
	fclose(fdto);
}

/*
 * checkfor(x, str) -- check for x in str.  Return 1 (TRUE) if exists.
 *			Otherwise 0 (FALSE).
 */

static int checkfor(x, str)
char 	*x;
char 	*str;
{
	while(*str) {
		if(strcmp(str, x) == 0)
			return(TRUE);
		str++;
	}
	return(FALSE);
}

/*
 * lineprint - print msg in a nice line
 */

static void lineprint(msg)
char *msg;
{
	int len, left, right, x;

	len = strlen(msg);
	right = (75-len)/2;
	left = right;
	for(x = 0; x < right; ++x)
		fputc('-', stdout);
	printf("[ %s ]", msg);
	for(x = 0; x < left; ++x)
		fputc('-', stdout);
	fputc('\n', stdout);
}

/*
 * Run RCS's rcsprog on file with flags.
 */

static void rcs(rcsprog, file, flags)
char *rcsprog;
char *file;
char *flags;
{
	char buf[LENGTH];
	char tmp[LENGTH];

	if(!checkfor("q", flags) && qflag)
		flags = "q";
	if(strcmp(flags, "") == 0)
		sprintf(buf, "%s %s", rcsprog, file);
	else
		sprintf(buf, "%s -%s %s", rcsprog, flags, file);
	sprintf(tmp,"Running ``%s''...\n", buf);
	debug(tmp);
	if(!qflag) {
	  sprintf(tmp, "Start of ``%s''", buf);
	  lineprint(tmp);
	}
	system(buf);
	if(!qflag) {
	  sprintf(tmp, "End of ``%s''", buf);
	  lineprint(tmp);
	}
}

/*
 * Run SHAPE/AtFS' vcprog on file with flags.
 */

static void atfs(vcprog, file, flags)
char *vcprog;
char *file;
char *flags;
{
	char buf[LENGTH];
	char tmp[LENGTH];

	if(strcmp(flags, "") == 0)
		sprintf(buf, "%s %s %s", vcprog, qflag ? "-q" : "", file);
	else
		sprintf(buf, "%s -%s %s %s", vcprog, flags, 
			qflag ? "-q" : "", file);
	sprintf(tmp,"Running ``%s''...\n", buf);
	debug(tmp);
	if(!qflag) {
	  sprintf(tmp, "Start of ``%s''", buf);
	  lineprint(tmp);
	}
	system(buf);
	if(!qflag) {
	  sprintf(tmp, "End of ``%s''", buf);
	  lineprint(tmp);
	}
}

/*
 * checkdir - make RCS or AtFS directory if not present.
 */

static void checkdir()
{
  if(access(atfsit ? "AtFS" : "RCS", 0) != 0){
    if(!qflag || debugon)
      printf("Cannot find \"%s\" directory.  Creating...\n", atfsit ? "AtFS" : "RCS");
    if(strcmp(rcsdir, atfsit ? "AtFS" : "RCS") != 0) { 
      if(symlink(rcsdir, atfsit ? "AtFS" : "RCS") != 0)
	fatal2("Symbolic link of %s to %s failed.", rcsdir, atfsit ? "AtFS" : "RCS");
    } else {
      if(mkdir(rcsdir, 0755) != 0)
	fatal1("Cannot create \"%s\" directory.", rcsdir);
    }
  }
}

/*
 * get template names
 */

static void get_temp()
{
	zap(tbuf);
	if(mflag)
		strcpy(tbuf, template_make);
	if(Mflag)
		strcpy(tbuf, template_man);
	if(hflag)
		strcpy(tbuf, template_h);
	if(cflag)
		strcpy(tbuf, template_c);
	if(eflag)
		strcpy(tbuf, template_elisp);
	if(sflag)
		strcpy(tbuf, template_sh);
	if(Sflag)
		strcpy(tbuf, template_shape);
	if(fflag)
		strcpy(tbuf, template_f);
}

int main(argc, argv)
int	argc;
char 	*argv[];
{
	int x;
	char	tmp[LENGTH];
	char	*file;
	char	*flags;
	char 	tmpfile[32];
	char    *cp;
	FILE 	*fdtmp;

	progname = (cp = strrchr (argv[0], '/')) ? ++cp : argv[0];

	if (strcmp ("rcsit", progname)) atfsit = TRUE;

	for (x = 1; x < argc; x++) {
		if (argv[x][0] != '-')
			break;
		switch (argv[x][1]) {
			case 'a':
				aflag = FALSE;
				break;
			case 'q':
				qflag = TRUE;
				break;
			case 'd':
				dflag = FALSE;
				break;
			case 'f':
				fflag = TRUE;
				break;
			case 'e':
				eflag = TRUE;
				break;
                        case 'F':
				Fflag = TRUE;
				cflag = TRUE; /* Only for C-files yet */
				break;
			case 'h':
				hflag = TRUE;
				break;
			case 's':
				sflag = TRUE;	
				break;
			case 'S':
				Sflag = TRUE;	
				break;
			case 'm':
				mflag = TRUE;
				break;
			case 'M':
				Mflag = TRUE;
				break;
			case 'i':
			case 'I':
				Iflag = TRUE;
				flags = &argv[x][2];
				break;
			case 'r':
			case 'R':
				rcsflag = TRUE;
				flags = &argv[x][2];
				break;
			case 't':
				tflag = TRUE;
				tpath = &argv[x][2];
				break;
			case 'v':
				printf ("This is %s version %s.\n", progname, atfsit_version());
				exit (0);
				break;
			case 'c':
				cflag = TRUE;
				break;
			default:
				fatal1("Unknown flag %s.",argv[x]);
		}
	}
	argc -= (x - 1);
	argv += (x - 1);

	if((hflag && (mflag || Mflag || cflag || eflag || Sflag)) ||
		(mflag && (hflag || cflag || Mflag || eflag || Sflag)) ||
		(Mflag && (cflag || hflag || mflag || eflag || Sflag)) ||
		(Sflag && (cflag || hflag || mflag || eflag || Mflag)) ||
		(eflag && (cflag || hflag || mflag || Mflag || Sflag)) ||
		(cflag && (hflag || Mflag || mflag || eflag || Sflag))) {
			fatal0("Only ONE of -c,-e,-f,-m,-M,-h,-s,-S may be specified.");
	}
	if(Iflag && rcsflag) {
			fatal0("Only ONE of ``-i'' and ``-r'' may be specified.");
	}

	if(cflag || eflag || hflag || mflag || Mflag || fflag || sflag || Sflag)
		aflag = FALSE;

	if((rcsdir = getenv(atfsit ? "AtFSDIR" : "RCSDIR")) == NULL)
		rcsdir = atfsit ? "AtFS" : "RCS";
	if(Iflag && dflag)
		checkdir();	/* Make RCS or AtFS directory for ci or save */
	if((!tflag) && ((tpath = getenv ("TEMPLATES")) != NULL))
	        tflag = TRUE;   /* fixed by axel@coma.uucp */
	if((tpath == NULL) &&   /* fixed by jmp@inesc */
	   ((tpath = getenv("TEMPLATES")) == NULL))
		if((tpath = getenv("HOME")) == NULL)
			fatal0("Cannot find environment variable HOME or TEMPLATE");

	/*
	 * make tmp file once.
	 */
	sprintf (tmpfile, "/tmp/%s%d", progname, getpid());

	while (--argc) {	/* Main loop */
		file = *++argv;
		sprintf(tmp, "...file (*++argv) = %s...", file);
		debug(tmp);

		if(access(file, 4) != 0)
			fatal1("Cannot access %s.  No read permission OR file does not exist.",
				file);
		if((fdtmp = fopen(tmpfile, "w")) == NULL) {
			fatal1("Cannot open tmpfile (%s).", tmpfile);
		}

		if(aflag)
			auto_guess(file); /* try and guess file type */
		else
			set_flags();	  /* check and set flags */

		if(tflag) {
			/*
			 * first get names of templates, then create
			 * path name to it.
			 */
			get_temp();
			sprintf(tfile, "%s/%s", tpath, tbuf);
		}
		if(access(tfile, 0) == 0 && tflag) {
			if(!qflag || debugon)
				printf("Adding %s header file to %s...",
					msg_name, file);
			copy(tfile, tmpfile, "w");
			copy(file, tmpfile, "a");
		} else {
			if(!qflag || debugon)
				printf(
				"Adding default header (%s format) to %s...",
					msg_name, file);
			/*
			 * put the Keywords into header string
			 */

			if (atfsit)
			  sprintf(tmp, header, "__Header", "__Log");
			else
			  sprintf(tmp, header, "Header", "Log");
			fputs(tmp, fdtmp);
			/*
			 * fclose'em, just in case.
			 */
			fclose(fdtmp);
			copy(file, tmpfile, "a");
		}
		unlink(file);
		copy(tmpfile, file, "w");
		unlink(tmpfile);

		if(!qflag || debugon)
			printf("done.\n");
		if (Fflag && (!qflag || debugon))
		  fputs ("-> Don't forget to define CFFLGS on compiler commandline <-\n", stdout);

		if(Iflag){
		  if (atfsit) {
			atfs("save", file, flags);
			if(Mflag)
			  atfs("vadm", file, "setc '... '");
			else if (cflag)
			  atfs("vadm", file, "setc ' * '");
			else if (eflag)
			  atfs("vadm", file, "setc ';; '");
			else if (fflag)
			  atfs("vadm", file, "setc 'c '");
			else if (pflag)
			  atfs("vadm", file, "setc ' * '");
			else if (sflag)
			  atfs("vadm", file, "setc '# '");
			else if (Sflag)
			  atfs("vadm", file, "setc '# '");
			else if (mflag)
			  atfs("vadm", file, "setc '# '");
			else if (hflag)
			  atfs("vadm", file, "setc ' * '");
		  }
		  else {
			rcs("ci", file, flags);
			if(Mflag){	/* kludge to tell rcs about manuals */
				rcs("rcs", file, "c'... '");
				/*
				 * kludge part 2 - if the user tried a ci
				 * with a -l option, then the header is
				 * messed up in the currently checked out
				 * man file.  So we have to co the file to 
				 * clean up the header.  Plus we use the
				 * -l option of co to insure file locking.
				 */
				if(checkfor("l", flags)){
					unlink(file);
					rcs("co", file, "l");
				}
			      }
		      }
		}
		if(rcsflag)
		  if (atfsit)
		    atfs("vadm", file, flags);
		  else
		    rcs("rcs", file, flags);
	}
	return (0);
}
