/* @(#)osfparse.c	19.1 (ES0-DMD) 02/25/03 13:56:12 */
/*===========================================================================
  Copyright (C) 1995 European Southern Observatory (ESO)
 
  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., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE        Module
.NAME        osfparse.c
.LANGUAGE    C
.AUTHOR      IPG-ESO Garching
.ENVIRONMENT	VAX / VMS Version
.CATEGORY    Host operating system interfaces. File management.
.COMMENTS    
	 File name Parsing.
	 A file name can be decomposed into path, filename,
	 extension and version.

.VERSION 1.0 	05-Feb-1988   F. Ochsenbein. 
.VERSION 1.1 	19-Jun-1989   Convention of Logical Names followed by :
				(to convert names from Unix)
.VERSION 1.2 	05-Dec-1989   Take care of .. = up subdirectory in Unix.
			Several paths are available with logicals, e,g,
			LOG:file.vers with ASSIGN p1,p2 LOG
.VERSION 1.3 	31-Jan-1990   Cosmetic
.VERSION 1.4 	23-Nov-1990   Don't crash if NULL filename
-----------------------------------------------*/

#include <osfile.h>
#include <atype.h>
#include <macrogen.h>

#define COMPONENTS 	(__PATH_+1)
static short int comp1[COMPONENTS][2] = { {0,0}}; 
static short int comp2[COMPONENTS][2] = { {0,0}}; 
					/* Index + length of components */

static char *buffer = NULL_PTR(char);
static int  lbuffer = 0;
char *osmmget(), *osmmexp();

/*===========================================================================*/
static void strupper ( str )
/*+++++++++
.PURPOSE  Converts (in place) a string to upper case
.RETURNS  Nothing
--------*/
     char *str;	/* MOD: starting address        */
{
	register char *p;

  for (p = str; *p; p++)
	*p = toupper(*p); 

}

/*==========================================================================*/
static int split(name, comp)
/*+++
.PURPOSE Split a file name into components, returned in `comp'.
.RETURNS The character that ends up the path (] or : or / or EOS)
.REMARKS Only written for VMS...
---*/
        char 	*name;	/* IN: EOS-terminated File Name	*/
	short int comp[COMPONENTS][2]; /* OUT: Index + length of components*/
{ 
  	register int i, len, status;

  oscfill((char *)comp, sizeof(comp1), 0);	/* initialize length and indexes */

  len = strlen(name);

	/* The structure of VMS file names is:
	   NODE::DEVICE:[DIRECTORY]FILE.EXTENSION;VERSION	*/

	/* Look for path name (terminated by / )	*/

  i = oscbloc(name, len, ']');		/* VMS--like	*/
  if (i < 0)	i = oscbloc(name, len, '/') ; /* Look Unix  */
  if (i < 0)	i = oscbloc(name, len, '\\'); /* Look MSDOS */
  if (i < 0)	i = oscbloc(name, len, ':') ; /* Look VMS */

  status = 0;

  if (i >= 0)		/* A Path was found, reset name to remaining chars */
  {	status = *(name + i);
  	comp[__PATH_][1] = ++i;
  	name += i, len -= i;
	for (i = __PATH_; --i >= 0; )	/* Set Indexes	*/
			comp[i][0] = comp[__PATH_][1];
  }

	/* Look for version	*/

  i = oscbloc(name, len, ';');
  if (i >= 0)	/* Version Found */
  {	comp[__VERSION_][0] += i;	/* Offset */
	comp[__VERSION_][1] = len - i;
	len = i;
  }

	/* Look for extension	*/

  i = oscbloc(name, len, '.');
  if (i >= 0)	/* Extension Found */
  {	comp[__EXTENSION_][0] += i;
	comp[__EXTENSION_][1] = len - i;
	len = i;
  }

	/* Look for file name	(remaining bytes)	*/

  comp[__FILE_][1] = len;

  return(status);
}	

/*==========================================================================*/
static char *path(name, len)
/*+++
.PURPOSE Convert a non-VMS (i.e. Unix or MSDOS) pathname
.RETURNS Pointer to EOS-terminated pathname if transformation needed
.REMARKS 
---*/
        char *name;		/* IN: Path Name	*/
        int  len;		/* IN: Length of Path Name	*/
{ 
	char	*p, *pe, *q, *start, savec, dir_sep;
	char	*oshenv();
	int	leq, l;
	static	char zero = EOS;
	static	char *pathname = NULL_PTR(char);	/* Returned path */
	static	int  lpathname = 0;

  if (len <= 0)		return(&zero);
  
  pe = name + len - 1;	/* Last character */
  dir_sep = *pe;	/* Is / for Unix, \ for MSDOS	*/
  
  if ((dir_sep == ']') || (dir_sep == ':'))	return(name);	/* VMS Notation */
  
	/* The path uses, either Unix, or MSDOS notation.
	 dir_sep is '/' (Unix notation) or '\' (MSDOS notation)	*/

  l = len + 4;		/* Minimal Size for Translated Path Name */
  
  if (*name == '$')	q = name + oscloc(name, len, dir_sep);
  else			q = name + len;
  
  if (q <= pe) 				/* Requires Logical Translation */
  {	savec = *q;
  	*q  = EOS;
  	p   = oshenv(name+1, NULL_PTR(char));
  	*q  = savec;
  	leq = (p ? strlen(p) : 0);
  	l   = leq + 4 + (pe-q);
  }
  else	leq = 0, l = len+1;
  l += 3;
  
  if (l > lpathname)		/* Expand Buffer */
  	lpathname = (l+63)& ~63, pathname = osmmexp(pathname, lpathname);

	/* Copy with modificataions */

  if(leq)	/* Name comes from a $path (logical translation) */
  {
  	oscopy(pathname, p, leq);
  	p = q;
  	start = pathname + leq - 1;	/* Last byte of translation */
  	if (*start != ']')	*++start = '[', start++;
  }
  else
  {
  	p = name;
  	start = pathname, *(start++) = '[';
  	if ( *p == dir_sep ) 	p++;		/* It's Root directory	*/
  	else	*(start++) = '.';		/* It's a subdirectory 	*/
  }
  
  for (q = start; p <= pe; p++, q++)
  {  	if (*p == '.')				/* Special Files 	*/
  	{ 	if (*++p == dir_sep)	  	/* ./ = current direct.	*/
  			{ --q; continue;}	
  		if (*p == '.')			/* ../ = up directory	*/
  			{ *q = '-'; continue; }
		--p;
  	}
  	*q = ( *p == dir_sep ? '.' : *p) ;
  }

  if (*(q-1) == '[')	*(q++) = ']';
  if (*(q-1) == '.')	*(q-1) = ']';
  *q = EOS;

  return(pathname);
}	

/*======================================================================*/
char *osfparse(name, option)
/*+++
.PURPOSE Extract from a file name the specified items, copy them
	to an internal buffer.
.RETURNS Address of the item(s) to extract
.REMARKS Options are _PATH_, _FILE_, _EXTENSION_, _VERSION_.
	VMS filenames are converted.
---*/
	char     *name;		/* IN: File name			*/
	unsigned int option;	/* IN: what to extract, as a \
				combination of options			*/
{ 
	char 	*p, *pname;		/* Pathname */
	int 	i, l, lpath;
	char	local_copy[256];
  
  if (!name)	name = "";	/* Take default name...	*/

  if (name == buffer)  {	/* Copy first... */
	l = strlen(name) + 1;
	l = MIN(l, sizeof(local_copy));
	oscopy(local_copy, name, l);
	name = local_copy;
  }
	
  split(name, comp1);	/* Split the filename into its components */

  if (option & _PATH_)
  {
  	p     = name + comp1[__PATH_][0];
  	pname = path(p, comp1[__PATH_][1]);
  	if (p == pname)	pname = NULL_PTR(char);	/* Was not modified */
	else		comp1[__PATH_][1] = 0;
  }
  else	pname = NULL_PTR(char);

	/* Compute the required length	*/

  lpath = 0;
  l = 1;				/* Take into account the EOS!	*/
  if (pname) 	lpath = strlen(pname), l += lpath;

  for (i = __PATH_; --i>=0; )
	if (option & (1<<i))		l += comp1[i][1];

  if (l > lbuffer)
  	lbuffer = (l+63)& ~63, buffer = osmmexp(buffer, lbuffer);


	/* Now, copy the required items	*/

  p = buffer;
  if (pname)	p += oscopy(p, pname, lpath);

  for (i=COMPONENTS; --i>=0; )
	if (option & (1<<i))
		p += oscopy(p, name + comp1[i][0], comp1[i][1]);
  *p = EOS;				/* Terminate with EOS	*/


  strupper(buffer);		/* Convert to UpperCase */

  return(buffer);
}

/*======================================================================*/
char *osfsupply(name, template)
/*+++
.PURPOSE Convert a file name according to a specified template:
	missing parts in name are replaced by the corresponding parts 
	provided in template.
	The resulting name is copied (in uppercase on VMS)
	to an internal buffer.
.RETURNS The address of the internal buffer
---*/
	char     *name;		/* IN: File name			*/
	char 	 *template;	/* IN: Template name			*/
{ 
	char 	*p, *pname;
	int 	i, l, lpath;
	char	local_copy[256];

	/* First, split the filenames into its components */

  if (!name)	name = "";	/* Take default name...	*/

  if (name == buffer)  {	/* Copy first... */
	l = strlen(name) + 1;
	l = MIN(l, sizeof(local_copy));
	oscopy(local_copy, name, l);
	name = local_copy;
  }
	
  split(name, comp1);
  split(template, comp2);

  if (comp1[__PATH_][1])	pname = name +     comp1[__PATH_][0],
					   lpath = comp1[__PATH_][1];
  else if (comp2[__PATH_][1])	pname = template + comp2[__PATH_][0],
					   lpath = comp2[__PATH_][1];
  else pname = NULL_PTR(char),	lpath = 0;
  
  if (pname) 	{
  	p = pname, pname = path(p, lpath);
  	if (pname != p)	lpath = strlen(pname);
  }

	/* Compute the required length			*/

  l = 1 + lpath;		/* Take into account the EOS!	*/
  for (i = __PATH_; --i>=0; ) 	{
  	if (comp1[i][1])	l += comp1[i][1];
	else			l += comp2[i][1];
  }

  if (l > lbuffer)
  	lbuffer = (l+63)& ~63, buffer = osmmexp(buffer, lbuffer);

	/* Now, copy the required items	*/

  p = buffer;
  if (pname)	p += oscopy(p, pname, lpath);

  for (i = __PATH_; --i>=0; )	{
  	if (comp1[i][1]) p += oscopy(p, name     + comp1[i][0], comp1[i][1]);
	else		 p += oscopy(p, template + comp2[i][0], comp2[i][1]);
  }
  *p = EOS;				/* Terminate with EOS	*/

  strupper(buffer);		/* Convert to UpperCase */

  return(buffer);
}

/*======================================================================*/
char *osftr(name)
/*+++
.PURPOSE Convert filename.
.RETURNS The address of the converted filename.
---*/
	char     *name;		/* IN: File name			*/
{ 

  if (name != buffer)	osfsupply(name, "");

  return(buffer);
}

