[patch, fortran] Wide character I/O Part 1

FX fxcoudert@gmail.com
Thu May 29 22:10:00 GMT 2008


Here's my review. I don't think the patch is OK, unless I made a  
mistake below (see the place where I talk about GFC_SIZE_OF_CHAR_KIND).

FX


> @@ -327,6 +328,13 @@ gfc_build_io_library_fndecls (void)
>  				     void_type_node, 3, dt_parm_type,
>  				     pvoid_type_node, gfc_int4_type_node);
>
> +  iocall[IOCALL_X_CHARACTER_WIDE] =
> +    gfc_build_library_function_decl (get_identifier
> +				     (PREFIX("transfer_character_wide")),
> +				     void_type_node, 4, dt_parm_type,
> +				     pvoid_type_node, gfc_int4_type_node,
> +				     gfc_int4_type_node);
> +
>    iocall[IOCALL_X_REAL] =
>      gfc_build_library_function_decl (get_identifier (PREFIX 
> ("transfer_real")),
>  				     void_type_node, 3, dt_parm_type,

You give them gfc_int4_type_node type and they're just "int" in the  
library version. I know there are a few other places like that lying  
around, but we shouldn't introduce new ones :)  I think the kind  
argument should be an int, and the length should be a  
gfc_charlen_type_node (which is really an integer(kind=4), but that's  
clearer that way).

>      case BT_CHARACTER:
> +      if (kind == 4)
> +	{
> +	  if (se->string_length)
> +	    arg2 = se->string_length;
> +	  else
> +	    {
> +	      tmp = build_fold_indirect_ref (addr_expr);
> +	      gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE);
> +	      arg2 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tmp)));
> +	    }

Even though it's probable safe already, I'd be tempted to fold_convert 
() arg2 into a gfc_charlen_type_node, just to make sure.


>  /* This is the offset (in bytes) required to cast from logical(8)* to
>     logical(4)*. and still get the same result.  Will be 0 for  
> little-endian
> -   machines and 4 for big-endian machines.  */
> +   machines and 1 for big-endian machines.  */
>  int l8_to_l4_offset = 0;

The thing is, you've corrected the values, but it's not "the offset  
(in bytes) required to cast from logical(8) to logical(4)". I suggest  
also remording the start of the comment, and maybe renaming that  
constant into "big_endian". But, if you don't want to do that last  
part right now, I can understand :)

> +  for (n = 0; n < m; n++, dest += 4, s++)
> +      dest[endian_off] = *s;
> +
> +  for (n = 0; n < length - (int) w; n++, dest++)
> +      dest[endian_off] = ' ';

In the second for loop, shouldn't that be "dest += 4" also? And also,  
maybe try to make sure it's tested somewhere in the testcases...

> @@ -1406,10 +1422,23 @@ formatted_transfer (st_parameter_dt *dtp
>    tmp = (char *) p;
>
>    /* Big loop over all the elements.  */
> -  for (elem = 0; elem < nelems; elem++)
> +  if (type == BT_CHARACTER && kind == 4)
>      {
> -      dtp->u.p.item_count++;
> -      formatted_transfer_scalar (dtp, type, tmp + size*elem, kind,  
> size);
> +      size_t stride;
> +      stride = size * 4;
> +      for (elem = 0; elem < nelems; elem++)
> +	{
> +	  dtp->u.p.item_count++;
> +	  formatted_transfer_scalar (dtp, type, tmp + stride*elem, kind,  
> size);
> +	}
> +    }
> +  else
> +    {
> +      for (elem = 0; elem < nelems; elem++)
> +	{
> +	  dtp->u.p.item_count++;
> +	  formatted_transfer_scalar (dtp, type, tmp + size*elem, kind,  
> size);
> +	}
>      }

I'd prefer having a single loop and use the GFC_SIZE_OF_CHAR_KIND  
macro. Something like that:

    /* Big loop over all the elements.  */
   size_t stride = (type == BT_CHARACTER ? size *  
GFC_SIZE_OF_CHAR_KIND(kind) : size;
   for (elem = 0; elem < nelems; elem++)
     {
       dtp->u.p.item_count++;
       formatted_transfer_scalar (dtp, type, tmp + stride*elem, kind,  
size);
     }

(not tested). I actually see you've done that in list_formatted_write 
() already, so it's probably that you forgot it here.


> +/* The primary difference between write_a_char4 and write_a is  
> that we have to
> +   deal with writing from the first byte of the 4-byte character  
> and take care
> +   of endianess.  This currently implements encoding="default"  
> which means we
> +   ignore the upper 3 bytes of the character.  TODO: Implement  
> encoding="UTF-8"
> +   which will process all 4 bytes and translate to the encoded  
> output.  */

Well, we shouldn't really ignore them as we do want to check them and  
potentially translate into a '?'. See below.


> +	  if (source[kk + endian_off] == '\n')

That doesn't work if, for example, you have a wide character c such  
that (c % 255) == '\n'. You need to correctly extract source as a  
gfc_char4_t and compare that to '\n' directly.

> +		  for (j = k = 0; j < bytes; j++, k += 4)
> +		    p[j] = source[k + endian_off];

Here, shouldn't you check for too large characters and print '?'  
instead? See below.

> +	  for (j = k =0; j < bytes; j++, k += 4)
> +	    p[j] = source[k + endian_off];

Same here.

> +	for (j = k = 0; j < wlen; j++, k += 4)
> +	  p[j] = source[k + endian_off];
> +      else
> +	{
> +	  memset (p, ' ', wlen - len);
> +	  for (j = k = wlen - len; j < wlen; j++, k += 4)
> +	    p[j] = source[k + endian_off];

And here (twice).

>    if (d == ' ')
> -    memcpy (p, source, length);
> +    for (i = 0; i < length; i++)
> +      p[i] = (unsigned int) source[i * kind] > 255 ?
> +	     '?' : source[i * kind + endian_off];

I think you should make a macro of that check:

#define FOLD_TO_CHAR1(x) ((x) > 255 ? '?' : (unsigned char) x)

Furthermore, I don't follow the logic here: source[i * kind] might  
not be the significant thing. Hum... that one is a mess, and I think  
we can't do it without having two loops depending on kind value. For  
gfc_char4_t, you need to extract the value from source like that:

   *(gfc_char4_t *)&source[i * kind]

and call the FOLD_TO_CHAR1 macro on that. For kind 1, just do the  
usual thing.


> -	  *p++ = source[i];
> -	  if (source[i] == d)
> +	  *p++ = (unsigned int) source[i * kind] > 255 ?
> +		 '?' : source[i * kind + endian_off];
> +	  if ((unsigned int) source[i * kind] <= 255
> +	      && source[i * kind + endian_off] == d)
>  	    *p++ = d;

Same here.


FX

-- 
François-Xavier Coudert
http://www.homepages.ucl.ac.uk/~uccafco/



More information about the Fortran mailing list