 /*
  * Khoros: $Id: utils.c,v 1.2 1992/03/20 22:50:02 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: utils.c,v 1.2 1992/03/20 22:50:02 dkhoros Exp $";
#endif

 /*
  * $Log: utils.c,v $
 * Revision 1.2  1992/03/20  22:50:02  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "utils.h"	


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    	    file name: utils.c                        <<<<
   >>>>                                                       <<<<
   >>>>		Various Internal Utility Routines	      <<<<
   >>>>		For the List Widget, Browser Widget, etc      <<<<
   >>>>                                                       <<<<
   >>>>             Used by the List Widget:		      <<<<
   >>>>             xvf_get_path_info()                       <<<<
   >>>>             xvf_compose_whole_list()                  <<<<
   >>>>             xvf_compose_single_list()                 <<<<
   >>>>                                                       <<<<
   >>>>             Used by the Keyword Browser:              <<<<
   >>>>             xvf_compose_keyword_list()                <<<<
   >>>>             xvf_get_keywd_part()                      <<<<
   >>>>             xvf_delete_startkey()                     <<<<
   >>>>                                                       <<<<
   >>>>             Used by the Directory Browser:            <<<<
   >>>>             xvf_strip_path()                          <<<<
   >>>>             xvf_check_slash()                         <<<<
   >>>>             xvf_good_dir()                            <<<<
   >>>>             xvf_get_directory()                       <<<<
   >>>>             xvf_delete_browser()                      <<<<
   >>>>             xvf_create_browser_list()                 <<<<
   >>>>                                                       <<<<
   >>>>             Used by Various Routines:                 <<<<
   >>>>             xvf_figure_height()                       <<<<
   >>>>             xvf_add_toplevel()                        <<<<
   >>>>             xvf_delete_toplevel()                     <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


/************************************************************
*
*  Routine Name: xvf_get_path_info()
*
*       Purpose: Goes out to the path provided, and first determines if:
*		    1) the path is to a file
*		    2) the path is to a directory
*		    3) the path is bogus
*	
*		 In case (1), it simply returns the filename, and file_num = 1; 
*		 In case (2), it goes out to the specified directory, 
*		 does a listing, and returns an array of strings that 
*		 are the names of the files in that directory.  
*		 Also returns the number of files in the directory. 
*		 In case (3), it returns NULL for the filename and file_num = 0.
*
*        Input:  path - the directory path in which we are interested
*
*       Output:  Returns an array of strings with the names of the files in
*		 the directory (if the path is to a directory), the name of
*		 the file (if the path is to a file), or NULL (if the path
*		 is bogus).
*		 dir_type  - one of DIRECTORY_PATH, FILE_PATH, BOGUS_PATH
*		 file_num  - (see above)
*		 
*
*    Called By:  xvf_create_help_widget(),
*		 xvf_create_multlist_multsel_wait()
*
*   Written By:  Danielle Argiro & Mark Young
*
*************************************************************/

char **xvf_get_path_info(path, dir_type, filenum)
char *path;
int  *dir_type;
int  *filenum;
{
	int	mode;
	char	**filenames, **vlistdir();
	struct  stat stat_buffer;


	if (stat(path, &stat_buffer) != -1)  
	{
	   /* path specified is a directory */
	   if ((stat_buffer.st_mode & S_IFMT) == S_IFDIR)
	   {
	      *dir_type = DIRECTORY_PATH;

	      /*
	       *  set the list mode to look for files and directories.
	       */
	      mode = XV_FILE;
	      filenames = vlistdir(path, NULL, mode, False, filenum);
	      if (filenames == NULL)
	      {
		 *dir_type = BOGUS_PATH;
		 *filenum  = 0;
		 return(NULL);
	      }
	      return(filenames);
	   }
	   /* path specified is a single file */
	   else
	   {
	      filenames = (char **) calloc(1,sizeof(char *));
	      filenames[0] = vbasename(path);
	      *dir_type = FILE_PATH;
	      *filenum = 1;
	      return(filenames);
	   }
	}
        else  
	{
	   /*
	    *  set the list mode to look for files and directories.
	    */
	   mode = XV_FILE;
	   filenames = vlistdir(path, NULL, mode, False, filenum);
	   if (filenames == NULL)
	   {
	      *dir_type = BOGUS_PATH;
	      *filenum  = 0;
	      return(NULL);
	   }
	   return(filenames);
	}
}


/************************************************************
*
*  Routine Name: xvf_compose_whole_list()
*
*       Purpose: This routine is used to go out to the files indictated,
*		 and create a list out of their contents (which should be
*		 a list of strings).  This routine is used only by 
*		 xvf_create_multlist_widget().
*
*        Input:  path - the directory path to files which contain the
*			contents for our list
*		 filenames - names of files containing our list entries
*		 filenum - number of files
*
*       Output:  Returns a list of strings with the contents of the files in
*		 the directory specified
*
*    Called By:  xvf_create_multlist_widget()
*
*   Written By:  Danielle Argiro & Mark Young
*
*************************************************************/



int xvf_compose_whole_list(path, filenames, filenum, 
		       list_entries, num_entries, duplicate_entries)
char *path;
char **filenames;
int  filenum;
char **list_entries;
int  *num_entries;
int   duplicate_entries;
{
	int  i, j, k, offset;
	char *filename, temp[MaxLength];
	FILE *file;

	j = 0;
	for (i = 0; i < filenum; i++)
	{
	    filename = vfullpath(filenames[i], path, NULL);
	    if (!(file = fopen(filename, "r")))
            {
                fprintf(stderr, "\nxvf_compose_list: \n");
                fprintf(stderr, "Error: unable to open file %s\n", filename);
                return(false);
            }
	    /*
             * read the contents of the file,
             * into the array of strings which will be our list
             */
            while (!(feof(file)))
            {
                list_entries[j] = (char *) calloc(1,sizeof(char)*MaxLength);
                fgets(temp, MaxLength, file);
		k = 0;
		list_entries[j][0] = list_entries[j][1] = 
		list_entries[j][2] = ' '; offset = 3;
		if (duplicate_entries) 
		{
		    list_entries[j][3] = list_entries[j][4] = ' '; offset = 5;
		}
		while (temp[k] != '\n')
		{
		   if (temp[k] != '_') list_entries[j][k+offset] = temp[k];
		   k++;
		}
                j++;
            }
	}
	*num_entries = j-1;
	return(true);
}

/************************************************************
*
*  Routine Name: xvf_compose_single_list()
*
*       Purpose: This routine is used to go out to the file indictated,
*		 and create a list out of its contents (which should be
*		 a list of strings). 
*
*        Input:  path - the directory path to files which contain the
*			contents for our list
*		 filename - names of file containing our list entries
*
*       Output:  Returns a list of strings with the contents of the files in
*		 the directory specified
*
*    Called By:  xvf_create_multlist_widget()
*
*   Written By:  Danielle Argiro & Mark Young
*
*************************************************************/


#define ListSize 100

char **xvf_compose_single_list(path, filename, num_entries, duplicate_entries)
char *path;
char *filename;
int  *num_entries;
int   duplicate_entries;
{
	int  j, k, offset;
	char temp[MaxLength], *fullpath;
	FILE *file;
	char **list_entries;

	list_entries = (char **) calloc(1,sizeof(char *) * ListSize);

	j = 0;
	fullpath = vfullpath(filename, path, NULL);
	if (!(file = fopen(fullpath, "r")))
        {
            fprintf(stderr, "\nxvf_compose_single_list: \n");
            fprintf(stderr, "Error: unable to open file %s\n", fullpath);
            return(NULL);
        }
	/*
         * read the contents of the file,
         * into the array of strings which will be our list
         */
        while (!(feof(file)))
        {
            list_entries[j] = (char *) calloc(1,sizeof(char)*MaxLength);
            fgets(temp, MaxLength, file);
	    k = 0;
	    list_entries[j][0] = list_entries[j][1] = 
	    list_entries[j][2] = ' '; offset = 3;
	    if (duplicate_entries)
	    {
		list_entries[j][3] = list_entries[j][4] = ' '; offset = 5;
	    }
	    while (temp[k] != '\n')
	    {
	        if (temp[k] != '_') list_entries[j][k+offset] = temp[k];
	        k++;
	    }
            j++;
	}
	*num_entries = j-1;
	return(list_entries);
}


/************************************************************
*
*  Routine Name: xvf_compose_keyword_list()
*
*       Purpose: This routine is used to go out to the (global to all
*		 of Khoros) keyword list, and create a list its contents 
*		 depending on the Level passed in.
*
*        Input:  start_key: the outermost key part 
*		 level:	    level corresponding to start key
*
*       Output:  Returns a list of strings with the keywords
*		 num - the size of list returned
*
*    Called By:  xvf_browser_cb()
*
*   Written By:  Danielle Argiro 
*
*************************************************************/



char **xvf_compose_keyword_list(start_keypart, num)
char *start_keypart;
int  *num; 
{
	int  i;
	char *xvf_get_keywd_part(), *temp, *save;
        char **keyword_list;
        Khoros_keywords *keywd_ptr;

	keyword_list = (caddr_t *) calloc(1,sizeof(char *)*MaxDBSize);

	if (khoros_keyword_list == NULL)
	    vinitialize_keywords();

	keyword_list[0] = xvf_strcpy("<==");
	i = 1;
	keywd_ptr = khoros_keyword_list;
	save = xvf_strcpy("@");
	while(keywd_ptr != NULL)
	{
	    temp = xvf_get_keywd_part(start_keypart, keywd_ptr->keyword);
	    if (temp != NULL)
	    {
	       if (strcmp(temp, save)!= 0)
	           keyword_list[i++] = temp;
	       save = xvf_strcpy(temp);
	    }
	    keywd_ptr = keywd_ptr->next;
	}
	*num = i;
	return(keyword_list);
}

/************************************************************
*
*  Routine Name: xvf_get_keywd_part()
*
*       Purpose: This routine returns the part of a keyword 
*	 	 (one of those defined in KHOROS_HOME/repos/Keywords)
*		 that follows the string passed in start_keypart.
*
*		 For example, if keyword = "images:medical:spine"
*		       and start_keypart = "images:", 
*	   	      then it will return, "medical".
*
*        Input:  start_keypart: the leading key part of keyword 
*		 keyword: the entire keyword 
*
*       Output:  returns the segment of the keyword directly following
*		 the start_keypart.
*
*    Called By:  xvf_browser_cb()
*
*   Written By:  Danielle Argiro 
*
*************************************************************/

char *xvf_get_keywd_part(start_keypart, keyword)
char *start_keypart;
char *keyword;
{
	int  i;
	char buffer[MaxLength];

	/* doing the top level keyword list */
	if ((start_keypart == NULL) || (start_keypart[0] == '\0'))
	{
	    if (keyword[0] == ':')
	    {
		sprintf(buffer, "%s", &keyword[1]);
		return(xvf_strcpy(buffer));
	    }
	    else
	    {
		i = 0;
		while (keyword[i] != ':') i++; 
		i++; strncpy(&buffer[0], keyword, i);
		buffer[i] = '\0';
		return(xvf_strcpy(buffer));
	    }
	}
	else
	{
	    i = 0;
	    while ((strncmp(start_keypart, &keyword[i], 
		    xvf_strlen(start_keypart)) != 0) &&
		    (i < xvf_strlen(keyword))) i++;

	    if (i == xvf_strlen(keyword)) return(NULL);

	    else 
	    {
		sprintf(buffer, "%s", &keyword[i+xvf_strlen(start_keypart)]);
	        i = 0;
	        while ((buffer[i] != ':') && (buffer[i] != '\0')) i++;
		if (buffer[i] == ':') buffer[i+1] = '\0';
		return(xvf_strcpy(buffer));
	    }
	}
}


/************************************************************
*
*  Routine Name: xvf_delete_endkey()
*
*       Purpose: Takes a keyword path and deletes the last
*		 part of it.  For example,
*			 if keyword = "images:medical:unm
*		         it returns,  "images:medical:"
*
*        Input:  keypath - the key path to have the last part deleted
*
*       Output:  returns the keypath without the last entry
*
*    Called By:  xvf_keyord_cb()
*
*   Written By:  Danielle Argiro
*
************************************************************/
xvf_delete_endkey(keypath)
char *keypath;
{
     int i;
     if (xvf_strlen(keypath) == 0) 
     {
	keypath[0] = '\0'; 
     }
     else
     {
        i = xvf_strlen(keypath) - 1;
        if (keypath[i] == ':') i--;
        while ((keypath[i] != ':') && (i != 0)) i--;
        if (keypath[i] == ':') keypath[i+1] = '\0';
        if (i == 0) keypath[0] = '\0';
     }
}



/************************************************************
*
*  Routine Name: xvf_strip_path()
*
*       Purpose: Takes a path that may have a filename at the 
*		 end and strips off the filename
*
*        Input:  path - the path to be stripped
*
*       Output:  returns the path without a filename at the end
*
*    Called By:  check_good_dir()
*
*   Written By:  Stephanie Hallett
*
*************************************************************/

char *xvf_strip_path(path)
char *path;
{
   char *tmp_file;
   char *char_ptr;
   char *last_slash;

   if (path == NULL)
      return(NULL);

   last_slash = NULL;

   tmp_file = xvf_strcpy(path);

   char_ptr = tmp_file;
   while (*char_ptr != '\0')
   {
      if (*char_ptr == '/')
	 last_slash = char_ptr;
      char_ptr++;
   }

   if (last_slash != NULL)
   {
      last_slash++;
      *last_slash = '\0';
   }
   else
   { 
      return(NULL);
   }

   return(tmp_file);
}


/************************************************************
*
*  Routine Name: xvf_check_slash()
*
*       Purpose: Makes sure that directory path has a slash "/" at the end
*
*        Input:  path - the path to be checked
*
*       Output:  returns the path with a slash at the end, if it doesn't
*		 have one already 
*
*   Written By:  Stephanie Hallett
*
************************************************************/

char *xvf_check_slash(path)
char *path;
{
   char *cur_char;
   char tmp_dir[512];

   if (path == NULL)
      return(NULL);

   cur_char = path;

   if (*cur_char == '\0')
      return(xvf_strcpy("/"));

   while(*cur_char != '\0')
      cur_char++;

   cur_char--;

   if (*cur_char != '/')
   {
      sprintf(tmp_dir,"%s/",path);
      return(xvf_strcpy(tmp_dir));
   }
   else
      return(xvf_strcpy(path));
}

/************************************************************
*
*  Routine Name: xvf_good_dir()
*
*       Purpose: Makes sure that directory path passed in is really
*		 a valid directory
*
*        Input:  path - the directory path to be checked
*
*       Output:  true if directory path is valid
*		 false otherwise
*
*   Written By:  Stephanie Hallett
*
************************************************************/

int check_good_dir(path)
char *path;
{
   int len;
   char wd[MAXPATHLEN];
   char *dir;
   char *wdir;

   dir = xvf_strip_path(path);
   len = strlen(dir)-1;
   if (XVF_FILE_DIR != NULL)
   {
      wdir = vfullpath(XVF_FILE_DIR, NULL, NULL);

      if ((strncmp(dir,wdir,len) == 0)&&(wdir[len]=='\0'))
	 return(1);
      else
	 return(0);
   }
   else
   {
      /* use the current working directory */
      getwd(wd);

      if ((strncmp(dir,wd,len) == 0)&&(wd[len]=='\0'))
         return(1);
      else
         return(0);
   }
}


/************************************************************
*
*  Routine Name: xvf_get_directory()
*
*       Purpose: Expands directory path to full representation
*
*        Input:  path - the directory path to be checked
*
*       Output:  full path of directory
*
*   Written By:  Mark Young
*
************************************************************/

char *xvf_get_directory(path)

char *path;
{
	char	dir[MAXPATHLEN], save[MAXPATHLEN];

	(void) getwd(save);

	(void) sprintf(dir, "%s", vfullpath(path, NULL, NULL));
	if (dir != NULL)
	   chdir(dir);

	getwd(dir);
	chdir(save);

	if (xvf_strlen(dir) < MAXPATHLEN)
	   (void) strcat(dir,"/");
	else
	   return(xvf_strcpy(save));

	return(xvf_strcpy(dir));
}

/************************************************************
*
*  Routine Name: xvf_delete_browser()
*
*       Purpose: Frees browser structure
*
*        Input:  browser - pointer to browser struct to be freed
*
*       Output:  none
*
*   Written By:  Mark Young
*
************************************************************/

xvf_delete_browser(browser)

xvf_browser_list *browser;
{
	vfreelist(browser->list, browser->num);
	XtFree(browser);
}

/************************************************************
*
*  Routine Name: xvf_create_browser_list()
*
*       Purpose: creates a list of the filenames and directories that
*		 exist in the specified directory, for display in the
*		 browser
*
*        Input:  directory - the directory which will supply contents
*			     for the browser list
*
*       Output:  xvf_browser_list - list for the browser
*
*   Written By:  Mark Young
*
*
************************************************************/

xvf_browser_list *xvf_create_browser_list(directory)

char	*directory;
{
	int		    mode;
	xvf_browser_list    *browser;
	char		    entry[MaxLength], **list, **vlistdir();

	/*
	 *  Malloc space for the browser structure.
	 */
	browser = (xvf_browser_list *) XtMalloc(sizeof(xvf_browser_list));

	/*
	 *  set the list mode to look for files and directories.
	 */
	mode = XV_DIR | XV_FILE;
	list = vlistdir(NULL, directory, mode, True, &browser->num);
	if (list == NULL)
	{
	   (void) sprintf(entry, "Error! Cannot open directory %s", directory);
	   xvf_error_wait(entry, "xvf_create_browser_list", NULL);
	   return(NULL);
	}

	/*
	 *  The following is a kludge necessary to to put the keyword
	 *  identifier at the head of the list of filenames.
	 */
	browser->list = (char **) XtMalloc(sizeof(char *) * (browser->num+1));
	browser->list[0] = xvf_strcpy("-- keywords --");
	bcopy(list, &browser->list[1], browser->num*sizeof(char *));
	free(list); browser->num++;
	return(browser);
}


/************************************************************
*
*  Routine Name: xvf_figure_height()
*
*       Purpose: figures the minimum height (in characters)
*		 of a text widget needed to display the given 
*		 string, based on the width passed in (in characters).
*
*        Input:  message - the string to be displayed in the text widget
*		 width   - width of the text widget to be used (in characters)
*
*       Output:  necessary height (in characters) for the text widget.
*
*   Written By:  Danielle Argiro
*
*
************************************************************/

xvf_figure_height(message, width)
char *message;
int  width;
{
	int i, length, row_size, height = 1;

	if (message == NULL) return (0);

	row_size = 0;
	length = xvf_strlen(message);
	if (length == 0) return (0);

	for (i = 0; i < length; i++)
	{
	     if (message[i] != '\n') row_size++;
	     else row_size = width;

	     if (row_size >= width)
	     {
		row_size = 0;
	        height++;
	     }
	}
	return(height);
}


/************************************************************
*
*  Routine Name: xvf_add_toplevel()
*
*       Purpose: Every time a new toplevel widget is created by one
*		 of the routines in xvutils, we must add it to the
*	         xvf_toplevels list so that when we do journal playback,
*	         we will look through this list first.  this makes
*	         journal playback more reliable and efficient.
*
*        Input:  toplevel - the toplevel widget created by 
*		            xvf_create_error(), xvf_create_browser(), etc.
*
*       Output:  new node in the xvf_toplevels list 
*
*   Written By:  Danielle Argiro
*
************************************************************/

xvf_add_toplevel(toplevel)
Widget toplevel;
{
      xvf_toplevel_list *new;

      if (toplevel == NULL) return;

      /*
       *  start the global xvf_toplevels list
       */
      if (xvf_toplevels == NULL)
      {
          xvf_toplevels = (xvf_toplevel_list *) 
			  malloc (sizeof(xvf_toplevel_list));
          xvf_toplevels->toplevel = toplevel;
          xvf_toplevels->next = NULL;
      }

      /*
       *  put a new node at the top of the list
       */
      else
      {
          new = (xvf_toplevel_list *) 
			  malloc (sizeof(xvf_toplevel_list));
	  new->toplevel = toplevel;
          new->next = xvf_toplevels;
          xvf_toplevels = new;
      }
}



/************************************************************
*
*  Routine Name: xvf_delete_toplevel()
*
*       Purpose: Every time a toplevel widget is destroyed by one
*		 of the exiting callbacks in xvutils, we must delete it 
*		 from the xvf_toplevels list.
*
*        Input:  toplevel - the toplevel widget created by 
*		            xvf_create_error(), xvf_create_browser(), etc.
*			    that is now being destroyed by the callback
*			    that exits the error or the browser, etc.
*
*       Output:  one less node in the xvf_toplevels list 
*
*   Written By:  Danielle Argiro
*
************************************************************/

xvf_delete_toplevel(toplevel)
Widget toplevel;
{
      xvf_toplevel_list *ptr, *last;

      if (xvf_toplevels == NULL) return;

      ptr = xvf_toplevels;

      /* 
       *  the node to destroy is first in the list
       */
      if (ptr->toplevel == toplevel)
      {
           xvf_toplevels = xvf_toplevels->next;
           free(ptr);
      }
      else
      {
	 last = xvf_toplevels;
	 while (ptr->toplevel != toplevel)
         {
	       last = ptr;
               ptr = ptr->next;
         }
	 last->next = ptr->next;
         free(ptr);
      }

}
