/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *
 *	$Id: show_help.c,v 6.15 1999/10/26 21:10:22 jsquyres Exp $
 * 
 *	Function:	- Read the LAM help file for the given program & topic
 *			- output the help message
 *			- substitute for variables and parameters
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#include <lam_config.h>
#include <patchlevel.h>
#include <portable.h>
#include <terror.h>
#include <args.h>


static char *nonver_name = "lam-helpfile";
static char *ver_name = NULL;
static char *helpfile_name = NULL;
static char *line = "-----------------------------------------------------------------------------\n";


#define TRY_FILE(dir, filename) \
  snprintf(buffer, LAM_PATH_MAX, "%s/%s", (dir), (filename)); \
  fp = fopen(buffer, "r"); \
  if (fp != NULL) { \
    helpfile_name = strdup(buffer); \
    return fp; \
  }


static FILE *
try_dir(char *dirname)
{
  /* Allocate out the version filename, if it hasn't been done yet */

  if (ver_name == NULL) {
    ver_name = malloc(64);
    snprintf(ver_name, 64, "lam-%s-helpfile", LAM_VERSION);
  }

  /* Now try the requested dirname */

  if (dirname != NULL) {
    FILE *fp;
    char buffer[LAM_PATH_MAX];

    TRY_FILE(dirname, nonver_name);
    TRY_FILE(dirname, ver_name);
  }

  return NULL;
}


static FILE *
open_helpfile()
{
  FILE *fp = NULL;
  char extra[LAM_PATH_MAX];
  char *env;

  /* Try a variery of places */
  /* First try for an absolute pathname */

  env = getenv("LAMHELPFILE");
  if (env != NULL) {
    fp = fopen(env, "r");
    if (fp != NULL) {
      helpfile_name = env;
      return fp;
    }
  }

  /* Now try several directories */

  env = getenv("HOME");
  if (env != NULL) {
    fp = try_dir(env);
    if (fp == NULL) {
      snprintf(extra, LAM_PATH_MAX, "%s/share/lam", env);
      fp = try_dir(extra);
    }
  }

  if (fp == NULL) {
    env = getenv("LAMHELPDIR");
    if (env != NULL)
      fp = try_dir(env);
  }

  if (fp == NULL) {
    env = getenv("LAMHOME");
    if (env != NULL) {
      snprintf(extra, LAM_PATH_MAX, "%s/share/lam", env);
      fp = try_dir(extra);
    }
  }

  if (fp == NULL) {
    env = getenv("TROLLIUSHOME");
    if (env != NULL) {
      snprintf(extra, LAM_PATH_MAX, "%s/share/lam", env);
      fp = try_dir(extra);
    }
  }

  if (fp == NULL) {
    if (DEFP != NULL) {
      snprintf(extra, LAM_PATH_MAX, "%s/share/lam", DEFP);
      fp = try_dir(extra);
    }
  }

  return fp;
}



/*
 * Open up the help file, find the help lines for a given
 * program/topic, and return it in an array of char*'s, or NULL if an
 * error occurs.  
 */
static char**
read_help(char *program, char *topic)
{
  FILE *fp;
  char *str;
  char **ret;
  int len, i, j, k, found = 0, count = 0;
  long pos;
  char buffer[BUFSIZ];

  /* Try to open the help file */

  fp = open_helpfile();
  if (fp == NULL) {
    fprintf(stderr, line);
    fprintf(stderr, "*** Oops -- I cannot open LAM help file.\n");
    fprintf(stderr, "*** I tried looking for it in the following places:\n");
    fprintf(stderr, "***\n");

    fprintf(stderr, "***   $LAMHELPFILE\n");
    fprintf(stderr, "***   $HOME/%s\n", nonver_name);
    fprintf(stderr, "***   $HOME/%s\n", ver_name);
    fprintf(stderr, "***   $HOME/share/lam/%s\n", nonver_name);
    fprintf(stderr, "***   $HOME/share/lam/%s\n", ver_name);
    fprintf(stderr, "***   $LAMHELPDIR/%s\n", nonver_name);
    fprintf(stderr, "***   $LAMHELPDIR/%s\n", ver_name);
    fprintf(stderr, "***   $LAMHOME/share/lam/%s\n", nonver_name);
    fprintf(stderr, "***   $LAMHOME/share/lam/%s\n", ver_name);
    fprintf(stderr, "***   $TROLLIUSHOME/share/lam/%s\n", nonver_name);
    fprintf(stderr, "***   $TROLLIUSHOME/share/lam/%s\n", ver_name);
    fprintf(stderr, "***   %s/share/lam/%s\n", DEFP, nonver_name);
    fprintf(stderr, "***   %s/share/lam/%s\n", DEFP, ver_name);
    fprintf(stderr, "***\n");

    fprintf(stderr, 
	    "*** You were supposed to get help on the program \"%s\"\n",
	    program);
    fprintf(stderr, "*** about the topic \"%s\"\n", topic);
    fprintf(stderr, "***\n");
    fprintf(stderr, "*** Sorry!\n");
    fprintf(stderr, line);

    return NULL;
  }

  /* Try to find the program/topic */

  if (program == NULL)
    program = "ALL";
  if (topic == NULL)
    topic = "ALL";
  str = malloc(strlen(program) + strlen(topic) + 16);
  sprintf(str, "-*-%s:%s-*-", program, topic);
  len = strlen(str);
  while (fgets(buffer, BUFSIZ, fp) != NULL) {
    if (strncmp(str, buffer, len) == 0) {
      found = 1;
      break;
    }
  }
  free(str);

  /* Did we find it? */

  if (!found) {
    fprintf(stderr, line);
    fprintf(stderr, "*** Oops -- cannot find the help that you're supposed to get.\n");
    fprintf(stderr, "*** Using the following help file:\n");
    fprintf(stderr, "***\n");
    fprintf(stderr, "***    %s\n", helpfile_name);
    fprintf(stderr, "***\n");
    fprintf(stderr, 
	    "*** You were supposed to get help on the program \"%s\"\n",
	    program);
    fprintf(stderr, "*** about the topic \"%s\"\n", topic);
    fprintf(stderr, "*** But it doesn't seem to be in that file.\n");
    fprintf(stderr, "***\n");
    fprintf(stderr, "*** Sorry!\n");
    fprintf(stderr, line);

    return NULL;
  }

  /* Read in the lines of help */
  /* First count the max of how many there are */

  pos = ftell(fp);
  while (fgets(buffer, BUFSIZ, fp) != NULL) {
    if (strncmp(buffer, "-*-", 3) == 0)
      break;
    count++;
  }

  /* Now alloc space and read in all the lines */
  /* Ignore lines that begin with # or [whitespace]+# */

  fseek(fp, pos, SEEK_SET);
  ret = malloc(sizeof(char*) * (count + 1));
  for (k = i = 0; i < count; i++) {
    fgets(buffer, BUFSIZ - 1, fp);
    buffer[BUFSIZ - 1] = '\0';
    for (j = 0; j < strlen(buffer); j++)
      if (!isspace((int) buffer[j]))
	break;
    if (buffer[j] == '#')
      continue;
    ret[k++] = strdup(buffer);
  }
  ret[k] = NULL;

  /* We're all done */

  fclose(fp);

  return ret;
}


/*
 * Perform substitutions; print out the resulting line.
 *
 * Substitute args[x - 1] for %x in the line (i.e., indexed from 1)
 * Print the output of perror() for %perror
 * Print the output of terror() for %terror
 * Substitute % for %%
 * Leave all other %'s alone
 */
static void
print_subst(char *line, char **args, int nargs)
{
  int num, i, last = 0, len = strlen(line);
  
  for (i = 0; i < len; i++)
    if (line[i] != '%')
      continue;
    else {
      if (i + 1 >= len)
	continue;
      else {
	if (strncmp(line + i + 1, "perror", 6) == 0) {
	  line[i] = '\0';
	  printf("%s", line + last);
	  fflush(stdout);
	  perror("");
	  last = i + 7;
	  i = last - 1;
	  continue;
	} else if (strncmp(line + i + 1, "terror", 6) == 0) {
	  line[i] = '\0';
	  printf("%s", line + last);
	  fflush(stdout);
	  terror("");
	  last = i + 7;
	  i = last - 1;
	  continue;
	}
	num = atoi(line + i + 1);
	if (num > 0) {
	  line[i] = '\0';

	  /* If we have a valid arg, print it */

	  if (num <= nargs && args[num - 1] != NULL)
	    printf("%s%s", line + last, args[num - 1]);
	  else
	    printf("%s", line + last);

	  /* Advance last past the number */

	  last = i + 1;
	  while (isdigit((int) line[last]) && last < len)
	    last++;
	  i = last - 1;
	}
      }
    }
  if (last < len)
    printf("%s", line + last);
}

/*
 * Show help for a particular program and topic.  Accept a variable
 * length list of args to be substituted in the output when the output
 * contains %x, where x is the number of the arugment from the
 * variable length argument list.
 */
void
#if LAM_WANT_PROTOS
show_help(char *program, char *topic, ...)
#else
show_help(program, topic, va_alist)

char *program;
char *topic;
va_dcl
#endif
{
  va_list arglist;
  char **lines;
  char **args, *arg;
  int i, count = 0, max_args = 0;

#if __STDC__
  va_start(arglist, topic);
#else
  va_start(arglist);
#endif

  /* Get the help strings */

  if ((lines = read_help(program, topic)) == NULL)
    return;

  /* We got the strings -- do the variable replacement */
  /* Read in all the var args to an array of char*'s */

  args = malloc(sizeof(char*) * 10);
  max_args = 10;
  count = 0;
  while ((arg = va_arg(arglist, char*)) != NULL) {
    if (count > max_args) {
      max_args += 10;
      args = realloc(args, sizeof(char*) * max_args);
    }
    args[count] = arg;
    count++;

    /* Make the array larger if necessary */

    if (count > max_args) {
      args = realloc(args, sizeof(char*) * count);
      max_args = count;
    }
  }
  args[count] = NULL;
  va_end(arglist);

  /* Now do the substititions */

  fprintf(stderr, "-----------------------------------------------------------------------------\n");
  for (i = 0; lines[i] != NULL; i++)
    print_subst(lines[i], args, count);
  fprintf(stderr, "-----------------------------------------------------------------------------\n");

  /* We're all done -- free up everything */

  for (i = 0; lines[i] != NULL; i++)
    free(lines[i]);
  free(lines);
  free(args);
}
