/*
Description:
  C routines and functions which are meant to either be called
  from FORTRAN or are used to help C routines interface to FORTRAN.

Author:
  DTJ	 5/ 1/92

  $Revision: 1.4 $
  $Modtime:   07/12/94 12:50:38  $

Version: $Id: fcinterface.c,v 1.4 2010/11/12 20:47:44 ntn Exp $
  2010-11-11 NTN: added addnullterminator() to fix BUG 2287

*/

/* Include files which are somewhat global */

#include <stdio.h>
#include <string.h>
#include <ctype.h>		/* toupper, tolower */
#include "cdefs.h"		/* MIN */
#include "fcinterface.h"


/****************************** CODE *****************************/

/* strf2c

Description:
  Converts FORTRAN strings to C strings.  When a FORTRAN program calls
  a C function with a string argument, the function gets a char pointer
  to an array that is NOT null-terminated, and the allocated bytes
  for the string.

  Therefore this routine does the following:
    1) copies as many bytes as possible from the FORTRAN to the C string;
    2) makes sure the C string terminates with a null;

  If the type of conversion is F2C_UNIXFILE or F2C_TRIM, it also:
    3) effectively trims off any trailing white space that may have come
       in with the FORTRAN string.

  If the type of conversion is F2C_UNIXFILE, it also:
    4) converts every character in the C string to lowercase.

  If the type of conversion is F2C_SUBROUTINE, it also:
    5) appends an underscore.

Author:  DTJ 2/26/92

Arguments:
  fchars (IN)		-- pointer to the FORTRAN character array.
  flen (IN)		-- allocated bytes for fchars
  cstr (OUT)		-- pointer to C string
  cmax (IN)		-- allocated bytes for cstr
  convtype (IN)		-- type of conversion

Returns:
  a pointer to the C string.
*/
char *strf2c(const char *fchars, int flen, char *cstr, int cmax, int convtype)
{
  int i, copied;

/* Save one character for the null, for the C string */

  strncpy(cstr, fchars,
	  copied = MIN(cmax - 1, flen));
  cstr[copied] = '\0';

  if (convtype & F2C_FLAG_TRIM)
    while (copied >= 0 && cstr[copied]<=' ')
      cstr[copied--] = '\0';

  if (convtype & F2C_FLAG_LOWERCASE)
    for (i = 0; cstr[i] != '\0'; i++)
      cstr[i] = tolower(cstr[i]);

  if (convtype & F2C_FLAG_APPEND_) {
    cstr[i++] = '_';
    cstr[i] = '\0';
  }

  return(cstr);

}



/* strc2f

Description:
  Converts C strings to FORTRAN strings.  When a C program needs to fill
  in the contents of a string that will be used in FORTRAN programs the
  null-terminator must be removed.

  Therefore this routine does the following:
    1) copies as many bytes as possible from the C to the FORTRAN string;
    2) makes sure the FORTRAN string does not terminate with a null;

  If the type of conversion is C2F_FLAG_FILL:
    3) appends trailing spaces to the FORTRAN string if necessary.

  If the type of conversion is C2F_FLAG_UPPERCASE, it also:
    4) converts all characters copied from the C string to uppercase.

Author:  SES 2/26/92

Arguments:
  cstr (IN)		-- pointer to C string
  cmax (IN)		-- number of chars to copy, if <0 until '\0' encountered
  fchars (OUT)		-- pointer to the FORTRAN character array (string).
  flen (IN)		-- allocated bytes for fchars
  convtype (IN)		-- type of conversion

Returns:
  a pointer to the Fortran character array (string).
*/
char *strc2f(const char *cstr, int cmax, char *fchars, int flen, int convtype)
{
  int i, copied;

  if (cmax >= 0)
    for (i = 0; i < cmax && i < flen; i++) fchars[i] = cstr[i];
  else
    for (i = 0; cstr[i] != '\0' && i < flen; i++) fchars[i] = cstr[i];
  copied = i;

  if (convtype & C2F_FLAG_FILL)
    while (i < flen) fchars[i++] = ' ';

  if (convtype & C2F_FLAG_UPPERCASE)
    for (i = 0; i < copied; i++)
      fchars[i] = toupper(fchars[i]);

  return (fchars);
}

/*******************************************************************************
Description: adds a C string null-terminator character ('\0') at the specified
             position. This is a quick and efficient way to convert a Fortran
             string to C string when the output length is known. This WILL
             replace the last character with the null char when (pos == maxlen).

Author: Neon Ngo  2010-11-11 (original version on Veterans Day)

Arguments:
  str    (I/O) -- pointer to Fortan/C string (char*) to add null-terminator
  maxlen (IN)  -- max length of str (if <= 0 then cstr is NOT changed)
  pos    (IN)  -- position in str to insert null-terminator character (when >= 0),
                  if this is greater than maxlen
  flags  (IN)  -- flags to modify default behavior:
                  FLAG_NONE (0x0)      - default behavior
                  FLAG_IGNORE_ZERO_POS - no change to str when (pos == 0).

Returns:
  a pointer to the str (char *)
*******************************************************************************/
char * addnullterminator (char* str, int maxlen, int pos, int flags)
{
  if (maxlen <= 0) {       // negative len or empty str
    return str;            // return str unchanged
  }

  // flag to ignore zero pos (to support APIs like m_get_uswitch())
  if ((pos == 0) && (flags & FLAG_IGNORE_ZERO_POS)) {
    return str;            // return str unchanged
  }

  if ((pos >= 0) && str) { // make sure pos (positive) and str (not null) are valid
    if (pos >= maxlen) {
      pos = (maxlen - 1);  // truncate last character (no space left) in str
                           // TODO: print warning message?
    }
    str[pos] = '\0';       // insert null terminator
  }

  return str;
} // end addnullterminator()
