/* $Id: libdeps.c,v 1.9 2009/01/04 15:49:31 kiesling Exp $ */

/*
  This file is part of Ctalk.
  Copyright  2005-2009 Robert Kiesling, ctalk@ctalklang.org.
  Permission is granted to copy this software provided that this copyright 
  notice is included in all source code modules.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, 
  Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "object.h"
#include "message.h"
#include "ctalk.h"
#include "classlib.h"

extern char *classlibdir;      /* Declared in main.c */
extern char libcachedir[FILENAME_MAX];
char ctalkuserhomedir[FILENAME_MAX];
extern int args_changed; 

/*
 *  The format of ctpp_ofn_path is generally something like
 *  /tmp/Object.ctpp.<id>
 */
int cache_ctpp_output_file (char *ctpp_ofn_path) {
  char lib_cache_path[FILENAME_MAX];
  char buf[FILENAME_MAX], fn[FILENAME_MAX];
  char *ctpp_ofn_lastdot, *ctpp_ofn_lastslash;

  strcpy (buf, ctpp_ofn_path);
  
  if ((ctpp_ofn_lastdot = rindex (buf, '.')) != NULL)
    *ctpp_ofn_lastdot = '\0';

  if ((ctpp_ofn_lastslash = rindex (buf, '/')) != NULL) {
    strcpy (fn, ctpp_ofn_lastslash + 1);
  }  else {
    strcpy (fn, buf);
  }
    
  sprintf (lib_cache_path, "%s/%s", libcachedir, fn);
  copy_file (ctpp_ofn_path, lib_cache_path);

  return SUCCESS;
}

int ctpp_deps_updated (char *class_path) {
  char fn[FILENAME_MAX];
  char lib_cache_path[FILENAME_MAX];
  char *lastslash;
  int lib_mtime, cache_mtime;

  if (args_changed)
    return TRUE;

  if ((lastslash = rindex (class_path, '/')) != NULL) {
    strcpy (fn, lastslash + 1);
  } else {
    strcpy (fn, class_path);
  }

  sprintf (lib_cache_path, "%s/%s.ctpp", libcachedir, fn);

  if (!file_exists (lib_cache_path))
    return TRUE;

  lib_mtime = file_mtime (class_path);
  cache_mtime = file_mtime (lib_cache_path);
  if ((lib_mtime != ERROR) && 
      (cache_mtime != ERROR) && 
      (lib_mtime > cache_mtime))
    return TRUE;
      
  return FALSE;
}

char *ctpp_cache_path (char *classname) {
  static char buf[FILENAME_MAX];
  sprintf (buf, "%s/%s.ctpp", libcachedir, classname);
  return buf;
}

static char *cmd_opts[512];
static int n_saved_opts;

/*
 *  Record the ctalk executable and all opts that begin 
 *  with '-', and "-o" and its argument.
 *
 *  The only options that take an argument that 
 *  we need for dependency checking are "-I" and "-s".
 *
 *  The program exits before reaching here when
 *  the options are, "-V," "-h," and, "--printlibdirs."
 */
static char *opts_w_args = "Is";

void save_opts (char **a, int n) {
  int i;
  n_saved_opts = 0;
  cmd_opts[0] = strdup (a[0]);
  n_saved_opts++;

  for (i = 1; i < n; i++) {
    if (a[i][0] == '-') {
      if (a[i][1] == 'o') {
	continue;
      } else {
	if (strpbrk (a[i], opts_w_args)) {
	  cmd_opts[i] = strdup (a[i]); ++i;
	  cmd_opts[i] = strdup (a[i]);
	  n_saved_opts += 2;
	  continue;
	} else {
	  cmd_opts[i] = strdup (a[i]);
	  n_saved_opts++;
	  continue;
	}
      }
    }
  }
}

#define ARGSFILE "args"

void check_user_args (void) {
  char path[FILENAME_MAX];
  char new_args[MAXMSG];
  char old_args[MAXMSG];
  char *p;
  int i;
  FILE *f;
  *new_args = '\0';
  for (i = 0; i < n_saved_opts; i++) {
    strcat (new_args, cmd_opts[i]);
    strcat (new_args, " ");
  }
  sprintf (path, "%s/%s", ctalkuserhomedir, ARGSFILE);
  /*
   *  Don't issue error if args file does not exist.
   */
  if ((f = fopen (path, "r")) != NULL) {
    if (!fgets (old_args, MAXMSG, f))
      _error ("%s: %s.\n", ctalkuserhomedir, strerror(errno));
    /*
     *  In case fgets grabs the newline (and there is a trailing
     *  space.
     */
    for (p = &old_args[strlen(old_args) - 1]; 
	 (*p == ' ') || (*p == '\n'); 
	 p--)
      *p = '\0';
    for (p = &new_args[strlen(new_args) - 1]; 
	 (*p == ' ') || (*p == '\n'); 
	 p--)
      *p = '\0';
    if (strcmp (new_args, old_args))
      args_changed = TRUE;
    else
      args_changed = FALSE;
    fclose (f);
  } else {
    args_changed = TRUE;
  }
}

void record_opts (void) {
  char path[FILENAME_MAX];
  int i;
  FILE *f;
  if (args_changed) {
    sprintf (path, "%s/%s", ctalkuserhomedir, ARGSFILE);
    if ((f = fopen (path, "w")) == NULL)
      _error ("%s: %s.\n", path, strerror(errno));
    for (i = 0; i < n_saved_opts; i++) {
      fprintf (f, "%s ", cmd_opts[i]);
    }
    fprintf (f, "\n");
    fclose (f);
  }
}
