1
1
Jeff Squyres 0ab6b201fe mpi/fortran: fix parsing arrays of Fortran strings
MPI defines the "argv" param to Fortran MPI_COMM_SPAWN as being
terminated by a blank string.  While not precisely defined (except
through a non-binding example, Example 10.2, MPI-3.1 p382:6-29), one
can infer that the "array_of_argv" param to Fortran
MPI_COMM_SPAWN_MULTIPLE is also a set of argv, each of which are
terminated by a blank line.

The "array_of_commands" argument to Fortran MPI_COMM_SPAWN_MULTIPLE is
a little less well-defined.  It is *assumed* to be of length "count"
(another parameter to MPI_COMM_SPAWN_MULTIPLE) -- and *not* be
terminated by a blank string.  This is also given credence by the same
example 10.2 in MPI-3.1.

The previous code assumed that "array_of_commands" should also be
terminated by a blank line -- but per the above, this is incorrect.
Instead, we should just parse our "count" number of strings from
"array_of_commands" and *not* look for a blank line termination.

This commit separates these two cases:

* ompi_fortran_argv_blank_f2c(): parse a Fortran array of strings out
  and stop when reaching a blank string.
* ompi_fortran_argv_count_f2c(): parse a Fortran array of strings out
  and stop when "count" number of strings have been parsed.

Signed-off-by: Jeff Squyres <jsquyres@cisco.com>
2018-04-04 18:56:44 -07:00

222 строки
6.0 KiB
C

/*
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2010-2018 Cisco Systems, Inc. All rights reserved
* Copyright (c) 2017 Research Organization for Information Science
* and Technology (RIST). All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "ompi_config.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "ompi/constants.h"
#include "opal/util/argv.h"
#include "ompi/mpi/fortran/base/fortran_base_strings.h"
/*
* creates a C string from an F77 string
*/
int ompi_fortran_string_f2c(char *fstr, int len, char **cstr)
{
char *end;
int i;
/* Leading and trailing blanks are discarded. */
end = fstr + len - 1;
for (i = 0; (i < len) && (' ' == *fstr); ++i, ++fstr) {
continue;
}
if (i >= len) {
len = 0;
} else {
for (; (end > fstr) && (' ' == *end); --end) {
continue;
}
len = end - fstr + 1;
}
/* Allocate space for the C string. */
if (NULL == (*cstr = (char *) malloc(len + 1))) {
return OMPI_ERR_OUT_OF_RESOURCE;
}
/* Copy F77 string into C string and NULL terminate it. */
if (len > 0) {
strncpy(*cstr, fstr, len);
}
(*cstr)[len] = '\0';
return OMPI_SUCCESS;
}
/*
* Copy a C string into a Fortran string. Note that when Fortran
* copies strings, even if it operates on subsets of the strings, it
* is expected to zero out the rest of the string with spaces. Hence,
* when calling this function, the "len" parameter should be the
* compiler-passed length of the entire string, even if you're copying
* over less than the full string. Specifically:
*
* http://www.ibiblio.org/pub/languages/fortran/ch2-13.html
*
* "Whole operations 'using' only 'part' of it, e.g. assignment of a
* shorter string, or reading a shorter record, automatically pads the
* rest of the string with blanks."
*/
int ompi_fortran_string_c2f(char *cstr, char *fstr, int len)
{
int i;
strncpy(fstr, cstr, len);
for (i = strlen(cstr); i < len; ++i) {
fstr[i] = ' ';
}
return OMPI_SUCCESS;
}
/*
* Creates a C argument vector from an F77 array of strings. The
* array is terminated by a blank string.
*
* This function is quite similar to ompi_fortran_argv_count_f2c(),
* that it looks for a blank string to know when it has finished
* traversing the entire array (vs. having the length of the array
* passed in as a parameter).
*
* This function is used to convert "argv" in MPI_COMM_SPAWN (which is
* defined to be terminated by a blank string).
*/
int ompi_fortran_argv_blank_f2c(char *array, int string_len, int advance,
char ***argv)
{
int err, argc = 0;
char *cstr;
/* Fortran lines up strings in memory, each delimited by \0. So
just convert them until we hit an extra \0. */
*argv = NULL;
while (1) {
if (OMPI_SUCCESS != (err = ompi_fortran_string_f2c(array, string_len,
&cstr))) {
opal_argv_free(*argv);
return err;
}
if ('\0' == *cstr) {
break;
}
if (OMPI_SUCCESS != (err = opal_argv_append(&argc, argv, cstr))) {
opal_argv_free(*argv);
free(cstr);
return err;
}
free(cstr);
array += advance;
}
free(cstr);
return OMPI_SUCCESS;
}
/*
* Creates a C argument vector from an F77 array of array_len strings.
*
* This function is quite similar to ompi_fortran_argv_blank_f2c(),
* except that the length of the array is a parameter (vs. looking for
* a blank line to end the array).
*
* This function is used to convert "array_of_commands" in
* MPI_COMM_SPAWN_MULTIPLE (which is not precisely defined, but is
* assumed to be of length "count", and *not* terminated by a blank
* line).
*/
int ompi_fortran_argv_count_f2c(char *array, int array_len, int string_len, int advance,
char ***argv)
{
int err, argc = 0;
char *cstr;
/* Fortran lines up strings in memory, each delimited by \0. So
just convert them until we hit an extra \0. */
*argv = NULL;
for (int i = 0; i < array_len; ++i) {
if (OMPI_SUCCESS != (err = ompi_fortran_string_f2c(array, string_len,
&cstr))) {
opal_argv_free(*argv);
return err;
}
if (OMPI_SUCCESS != (err = opal_argv_append(&argc, argv, cstr))) {
opal_argv_free(*argv);
free(cstr);
return err;
}
free(cstr);
array += advance;
}
return OMPI_SUCCESS;
}
/*
* Creates a set of C argv arrays from an F77 array of argv's (where
* each argv array is terminated by a blank string). The returned
* arrays need to be freed by the caller.
*/
int ompi_fortran_multiple_argvs_f2c(int num_argv_arrays, char *array,
int string_len, char ****argv)
{
char ***argv_array;
int i;
char *current_array = array;
int ret;
argv_array = (char ***) malloc (num_argv_arrays * sizeof(char **));
for (i = 0; i < num_argv_arrays; ++i) {
ret = ompi_fortran_argv_blank_f2c(current_array, string_len,
string_len * num_argv_arrays,
&argv_array[i]);
if (OMPI_SUCCESS != ret) {
free(argv_array);
return ret;
}
current_array += string_len;
}
*argv = argv_array;
return OMPI_SUCCESS;
}