Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
lwrite.c
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001, Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2.1 of the GNU Lesser General Public License 
00007   as published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU Lesser General Public 
00021   License along with this program; if not, write the Free Software 
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, 
00023   USA.
00024 
00025   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00026   Mountain View, CA 94043, or:
00027 
00028   http://www.sgi.com
00029 
00030   For further information regarding this notice, see:
00031 
00032   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00033 
00034 */
00035 
00036 
00037 
00038 #pragma ident "@(#) libf/fio/lwrite.c   92.5    06/23/99 16:08:16"
00039 #include <ctype.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <fortran.h>
00043 #include <cray/fmtconv.h>
00044 #include <cray/nassert.h>
00045 #ifdef  _CRAYT3D
00046 #include <cray/mppsdd.h>
00047 #define MAXSH   512
00048 #else
00049 #define MAXSH   1
00050 #endif
00051 #include "fio.h"
00052 #include "fmt.h"
00053 #include "f90io.h"
00054 #include "lio.h"
00055 
00056 short   _old_list_out_repcounts         = 0;
00057 short   _90_char_nonchar_delim_blanks   = 1;
00058 short   _blank_at_start_of_empty_rec    = 1;
00059 
00060 extern oc_func  *_oldotab[DVTYPE_NTYPES];
00061 extern oc_func  _sd2udee;
00062 
00063 /*
00064  *      Forward reference
00065  */
00066 int
00067 _beautify(ftype_t type, long *plain, long *limit, long *pretty, short isf90);
00068 
00069 int
00070 _find_dupcnt(void *ptr, long count, long stride, int elsize, short ischar);
00071 
00072 int
00073 _write_delimited_char(FIOSPTR css, unit *cup, char *sptr, int len, long dchar);
00074 
00075 /*
00076  *      COMPEQ compares the current output item with a saved output item.
00077  *      Evaluates to 1 if equal, 0 if not equal.
00078  */
00079 #define COMPEQ(css, cptr, newtype, newelsize) ( \
00080         (css->u.fmt.u.le.type == newtype) && \
00081         (css->u.fmt.u.le.elsize == newelsize) && \
00082         (css->u.fmt.u.le.elsize > sizeof(css->u.fmt.u.le.u.value) ? \
00083                 (memcmp(css->u.fmt.u.le.u.copy, cptr, newelsize) == 0) : \
00084                 (memcmp(css->u.fmt.u.le.u.value, cptr, newelsize) == 0)))
00085 
00086 #define WINT1   4
00087 #define WINT2   6
00088 #define WINT4   11
00089 #define WDIG4   7
00090 #define WDIG8   16
00091 #define WDIG16  30
00092 #define WRL4    15
00093 #define WRL8    24
00094 #define WRL16   41
00095 
00096 /*
00097  *      _ld_write 
00098  *              List-directed write
00099  *
00100  *      Return Value:
00101  *               0      normal return
00102  *              >0      error return
00103  */
00104 
00105 int
00106 _ld_write(
00107         FIOSPTR         css,    /* Pointer to current state             */
00108         unit            *cup,   /* Unit pointer                         */
00109         void            *dptr,  /* Pointer to data                      */
00110         type_packet     *tip,   /* Type information packet              */
00111         int             _Unused)/* Unused by this routine               */
00112 {
00113         register short  blanks; /* Number of leading blanks             */
00114         register short  ischar; /* Is variable type CHARACTER?          */
00115         register short  ndchar; /* Local copy of css->u.fmt.u.le.ndchar */
00116         register ftype_t type;  /* Fortran data type                    */
00117         register int    elsize; /* Size of each data time (bytes)       */
00118         register int    i;      /* Loop index                           */
00119         register int    realsz; /* size in bytes of the real data item  */
00120         register int    repcnt; /* Local copy of css->u.fmt.u.le.repcnt */
00121         register int    tbsz;   /* Number of characters in tbuf         */
00122         register long   count;  /* Number of data items                 */
00123         register long   delim;  /* Delimiter, else 0 if none            */
00124         register long   vinc;   /* Virtual stride                       */
00125         long            tbuf[ITEMBUFSIZ];
00126         long            plain[ITEMBUFSIZ]; /* buffer for numeric output */
00127         long            *tptr;  /* Pointer to location in tbuf          */
00128         char            *cptr;  /* Character pointer to datum           */
00129         const long      zero = 0;
00130 #ifdef  _CRAYT3D
00131         register short  shared; /* Is variable shared?                  */
00132         register int    elwords;/* Number of words per item             */
00133         register int    offset; /* Offset from address in item units    */
00134         register int    tcount; /* Number of items to move              */
00135         long            shrd[MAXSH];    /* Shared data copy buffer      */
00136 #endif
00137 
00138         /* Assertions */
00139 
00140         assert ( cup != NULL );
00141         assert ( css != NULL );
00142         assert ( tip != NULL );
00143 
00144         cptr    = (char *) dptr;
00145 
00146         type    = tip->type90;
00147         count   = tip->count;
00148         elsize  = tip->elsize;
00149         vinc    = tip->stride;
00150 
00151         ischar  = (type == DVTYPE_ASCII) ? 1 : 0;
00152 
00153 /*
00154  *      The ldwinit field is set to 1 the first time _ld_write is called
00155  *      during any WRITE statement.
00156  */
00157         if (css->u.fmt.u.le.ldwinit) {
00158                 css->u.fmt.u.le.item1   = 1;
00159                 css->u.fmt.u.le.repcnt  = 0;
00160                 css->u.fmt.u.le.ndchar  = 0;
00161                 css->u.fmt.u.le.ldwinit = 0;
00162         }
00163 
00164         repcnt  = css->u.fmt.u.le.repcnt;
00165         ndchar  = css->u.fmt.u.le.ndchar;
00166 
00167 /*
00168  *      Figure out if character variables would be delimited by a quote or
00169  *      a character.
00170  */
00171         delim   = 0;
00172 
00173         if (cup->udelim != OS_NONE)
00174                 delim   = ((cup->udelim == OS_QUOTE) ? DQUOTE : SQUOTE);
00175         else if (css->f_iostmt == T_WNL && !cup->uft90)
00176                 delim   = SQUOTE;
00177 
00178         if (cup->ulinemax > cup->uldwsize || cup->uldwsize <= 1)
00179                 RERROR(FEWRLONG);       /* Record too long */
00180 
00181         if (count > 0 || repcnt > 0 || _blank_at_start_of_empty_rec) {
00182                 if (cup->ulinemax == 0) {       /* If line empty */
00183                         *(cup->ulineptr++)      = BLANK;
00184                         cup->ulinemax           = cup->ulinemax + 1;
00185                 }                               
00186         }
00187 
00188 /*
00189  *      If count is zero, then _ld_write is being called to terminate the
00190  *      current list-directed write statement processing.
00191  */
00192         if (count == 0) {
00193                 if (repcnt > 0)
00194                         goto print_saved_value;
00195                 else
00196                         goto fin;
00197         }
00198 
00199 /*
00200  *      Special processing for T3D CRAFT shared variables.
00201  */
00202 
00203 #ifdef  _CRAYT3D
00204         if (_issddptr(dptr)) {
00205                 offset  = 0;
00206                 elwords = elsize / sizeof(long);
00207                 tcount  = count;
00208                 vinc    = 1;    /* We now have a unit stride */
00209                 shared  = 1;
00210         }
00211         else
00212                 shared  = 0;
00213 
00214    do {
00215         if (shared) {
00216 
00217                 /* Copy data into local array shrd, and write from there */
00218 
00219                 count   = MIN(MAXSH / elwords, (tcount - offset));
00220                 _cpyfrmsdd(dptr, shrd, count, elwords, tip->stride, offset);
00221                 offset  = offset + count;
00222                 cptr    = (char *) shrd;
00223         }
00224 #endif
00225 
00226         /*
00227          *      M A I N   L O O P
00228          */
00229 
00230         while (count > 0) {     /* While more to write */
00231                 register int    dupcnt; /* Number of duplicate data items */
00232                 long            width;  /* Conversion field width */
00233                 long            mode;   /* Conversion mode flags */
00234                 long            digits; /* Number of digits */
00235                 long            expon;  /* Conversion exponent */
00236                 long            scale;  /* Conversion scale factor */
00237                 long            *newp;  /* Pointer to end of numeric conversion */
00238                 oc_func *gcf;   /* Generic NOCV-type conversion func */
00239 
00240                 /*
00241                  * If there is a saved output value, and a nondelimited
00242                  * character is being printed or old output style is selected
00243                  * or the current output item is not equal to the stored
00244                  * output item, or the assign option to skip the
00245                  * repeat count is present, then print the stored
00246                  * output item.
00247                  */
00248 
00249                 if (repcnt > 0 && ( _old_list_out_repcounts ||
00250                     !COMPEQ(css, cptr, type, elsize) ||
00251                     (cup->ufrptcnt !=0))) {
00252                         register int    prevlen;
00253                         register ftype_t prevtyp;
00254                         char            *prevptr;
00255 print_saved_value:
00256 
00257                         prevlen = css->u.fmt.u.le.elsize;
00258                         prevtyp = css->u.fmt.u.le.type;
00259 
00260                         if (prevlen <= sizeof(css->u.fmt.u.le.u.value))
00261                                 prevptr = (char *) &css->u.fmt.u.le.u.value[0];
00262                         else
00263                                 prevptr = (char *) css->u.fmt.u.le.u.copy;
00264 
00265                         tptr    = tbuf;
00266                         blanks  = 0;
00267 
00268                         /*
00269                          * Now we handle the printing of a value separator
00270                          * between the last-printed value and the current
00271                          * value (possibly with a repeat count).  Value
00272                          * separators used are:
00273                          *
00274                          *  Adjacent types                Value separator
00275                          *
00276                          *  nonchar, nonchar              comma and 2 blanks
00277                          *  delim-char, delim-char        comma and 2 blanks
00278                          *  delim-char, nonchar           comma and 2 blanks
00279                          *  nondelim-char, nondelim-char  no delimiter
00280                          *  nondelim-char, other          space (see note)
00281                          *
00282                          * Note: If we are in cf77 compatibility mode, no
00283                          * value separator is placed between a nondelimited 
00284                          * character and any other type.
00285                          *
00286                          * The comma separator is printed directly to the line
00287                          * buffer, but the blanks are deferred until we can
00288                          * determine if the next value fits on the current
00289                          * record or not.  If we must go to the next record,
00290                          * the blanks are not printed.
00291                          */
00292 
00293                         if (css->u.fmt.u.le.item1 != 0)
00294                                 css->u.fmt.u.le.item1   = 0;
00295 
00296                         /*
00297                          * No value separator between consecutive nondelimited 
00298                          * character.  One space is used as value separator.
00299                          */
00300                         else if (ndchar && (prevtyp == DVTYPE_ASCII)) 
00301                                 blanks  = 0;
00302                         /*
00303                          * Use one space as a value separator between 
00304                          * nondelimited character and non-character values.
00305                          */
00306                         else if (ndchar || (delim == 0 && prevtyp == DVTYPE_ASCII)) {
00307                                 if (cup->ulinemax < cup->uldwsize && cup->uft90) 
00308                                         blanks  = _90_char_nonchar_delim_blanks;
00309                                 else
00310                                         blanks  = 0;
00311                         }
00312 
00313                         /*
00314                          * Else a comma and 2 blanks normally separate
00315                          * consecutive items.  If the previous output item 
00316                          * lies out at the very end of the record, we 
00317                          * suppress the comma.  The leading blank on 
00318                          * the next record serves as value separator.
00319                          */
00320                         else {
00321                                 if (cup->ulinemax < cup->uldwsize) {
00322                                         if (cup->ufcomsep == 0) {
00323                                                 *(cup->ulineptr++)      = COMMA;
00324                                                 cup->ulinemax   = cup->ulinemax + 1;
00325                                                 blanks          = 2;
00326                                         } else
00327                                                 blanks          = 1;
00328                                 }
00329                                 else
00330                                         blanks          = 0;
00331                         }
00332 
00333                         /*
00334                          * Print the repeat count into the item buffer.
00335                          */
00336 
00337                         if (repcnt > 1) {
00338                                 long    rcnt;
00339 
00340                                 rcnt    = repcnt;
00341                                 width   = WINT;
00342                                 digits  = 1;
00343 
00344                                 if (sizeof(rcnt) == 4)
00345                                         mode    = MODEHP;
00346 #if     defined(_F_INT2) && (defined(__mips) || defined(_LITTLE_ENDIAN))
00347                                 else if (sizeof(rcnt) == 2)
00348                                         mode    = MODEWP;
00349                                 else if (sizeof(rcnt) == 1)
00350                                         mode    = MODEBP;
00351 #endif  /* _f_int2 and mips or little endian */
00352                                 else
00353                                         mode    = 0;
00354 
00355                                 newp    = _s2ui(&rcnt, plain, &mode, &width,
00356                                                 &digits, &zero, &zero);
00357 
00358                                 tptr    = tptr + _beautify(DVTYPE_INTEGER, plain,
00359                                                         newp, tptr, cup->uft90);
00360                                 *tptr++ = STAR;
00361                         }
00362 
00363                         /*
00364                          * Print a saved (delimited) character value.
00365                          */
00366 
00367                         if (prevtyp == DVTYPE_ASCII) {  /* delimited character */
00368                                 register int    errn;   /* Error code */
00369 
00370                                 /*
00371                                  * Check that there's room on the current
00372                                  * line for the blanks, the repeat count,
00373                                  * the asterisk, and the starting delimiter.
00374                                  */
00375 
00376                                 tbsz    = tptr - tbuf;
00377 
00378                                 if ((cup->ulinemax + blanks + tbsz + 1) >
00379                                      cup->uldwsize) {
00380 
00381                                         /*
00382                                          * Check that the repeat specification
00383                                          * (with asterisk), the leading blank,
00384                                          * and the leading delimiter fit on a
00385                                          * single line.
00386                                          */
00387 
00388                                         if ((tbsz + 2) > cup->uldwsize)
00389                                                 RERROR(FEWRLONG); /* Record too long */
00390 
00391                                         /* Write record */
00392 
00393                                         errn    = (*css->u.fmt.endrec)(css, cup, 1);
00394 
00395                                         if (errn != 0)
00396                                                 RERROR(errn);
00397 
00398                                         /* Write one space at start of new record */
00399 
00400                                         *(cup->ulineptr++)      = BLANK;
00401                                         cup->ulinemax           = cup->ulinemax + 1;
00402                                 }
00403                                 else {
00404                                         /* This loop should vectorize */
00405 #ifdef  _CRAY
00406 #pragma _CRI shortloop
00407 #endif
00408                                         for (i = 0; i < blanks; i++)
00409                                                 cup->ulineptr[i]        = BLANK;
00410 
00411                                         cup->ulinemax   = cup->ulinemax + blanks;
00412                                         cup->ulineptr   = cup->ulineptr + blanks;
00413                                 }
00414 
00415                                 /*
00416                                  * Transfer the optional repeat count (with
00417                                  * asterisk) and the starting delimiter to
00418                                  * the line buffer.
00419                                  */
00420 
00421                                 for (i = 0; i < tbsz; i++)      /* Should vectorize */
00422                                         cup->ulineptr[i]        = tbuf[i];
00423 
00424                                 cup->ulineptr   = cup->ulineptr + tbsz;
00425                                 cup->ulinemax   = cup->ulinemax + tbsz;
00426 
00427                                 errn    = _write_delimited_char(css, cup, prevptr,
00428                                                 prevlen, delim);
00429 
00430                                 if (errn != 0)
00431                                         RERROR(errn);
00432 
00433                                 goto done_printing_saved_value;
00434                         }
00435 
00436                         /*
00437                          * Print a saved non-character value.
00438                          */
00439 
00440                         gcf     = _oldotab[prevtyp];    /* Conversion function */
00441                         mode    = 0;
00442                         expon   = 0;
00443                         scale   = 0;
00444 
00445                         switch (prevtyp) {
00446 
00447                         case DVTYPE_TYPELESS:
00448                                 switch (prevlen) {
00449                                 case 4:
00450                                         mode    = MODEUN | MODEHP;
00451                                         width   = WOCTHWD;
00452                                         break;
00453 
00454                                 case 8:
00455                                         mode    = MODEUN;
00456                                         width   = WOCTWRD;
00457                                         break;
00458 
00459                                 default:
00460                                         return(FEKNTSUP); /* kind not supported */
00461                                 }
00462 
00463                                 digits  = width;
00464                                 break;
00465 
00466                         case DVTYPE_INTEGER:
00467                                 width   = WINT; 
00468                                 digits  = 1;
00469 
00470 #ifdef  _F_INT4
00471                                 if (prevlen == 4) {
00472                                         mode    = MODEHP;
00473                                         if (cup->ufcomplen != 0)
00474                                                 width   = WINT4;
00475 #if     defined(_F_INT2) && (defined(__mips) || defined(_LITTLE_ENDIAN))
00476                                 } else if (prevlen == 2) {
00477                                         mode    = MODEWP;
00478                                         if (cup->ufcomplen != 0)
00479                                                 width   = WINT2;
00480                                 } else if (prevlen == 1) {
00481                                         mode    = MODEBP;
00482                                         if (cup->ufcomplen != 0)
00483                                                 width   = WINT1;
00484 #endif  /* _F_INT2 and mips or little endian */
00485                                 }
00486 #endif  /* _F_INT4 */
00487                                 break;
00488 
00489                         case DVTYPE_REAL:
00490                         case DVTYPE_COMPLEX:
00491                                 scale   = 1;
00492                                 realsz  = prevlen; /* bytes */
00493 
00494                                 if (prevtyp == DVTYPE_COMPLEX)
00495                                         realsz  = realsz >> 1;
00496 
00497                                 switch (realsz) {
00498 
00499                                         /* 
00500                                          * Use G editing to print 'digits'
00501                                          * of precision with G-as-F conversions
00502                                          * and 'digits' + 1 precision with
00503                                          * G-as-E conversions and a scale
00504                                          * factor of 1.
00505                                          *
00506                                          * We put up with this inconsistency
00507                                          * to avoid having to prescan the datum
00508                                          * to determine its magnitude.
00509                                          */
00510 #ifdef  _F_REAL4
00511                                 case 4:
00512                                         mode    = MODEHP;
00513 
00514                                         /*
00515                                          * if ignore-minus-flag of -0.0
00516                                          * set, do not write minus.
00517                                          */
00518 
00519                                         if (cup->ufnegzero != 0)
00520                                                 mode    = mode | MODEMSN;
00521 
00522                                         expon   = DEXP4;
00523 
00524                                         if (cup->ufcomplen == 0) {
00525                                                 width   = WREAL4;       
00526                                                 digits  = _dreal4;
00527                                         } else {
00528                                                 width   = WRL4; 
00529                                                 digits  = WDIG4;
00530                                         }
00531                                         break;
00532 #endif
00533                                 case 8:
00534 
00535                                         /* if ignore-minus-flag of -0.0
00536                                          * set, do not write minus.
00537                                          */
00538 
00539                                         if (cup->ufnegzero != 0)
00540                                                 mode    = MODEMSN;
00541 
00542                                         expon   = DEXP8;
00543 
00544                                         if (cup->ufcomplen == 0) {
00545                                                 width   = WREAL8;
00546                                                 digits  = _dreal8;
00547                                         } else {
00548                                                 width   = WRL8; 
00549                                                 digits  = WDIG8;
00550                                         }
00551                                         break;
00552 
00553                                 case 16:
00554                                         /*
00555                                          * When printing with D format,
00556                                          * decrease the digits by one because
00557                                          * we are setting the scale factor to
00558                                          * 1.  This ensures that _dreal16
00559                                          * digits of precision are printed.
00560                                          */
00561                                         gcf     = _sd2udee;
00562                                         mode    = MODEDP;
00563 
00564                                         /* if ignore-minus-flag of -0.0
00565                                          * set, do not write minus.
00566                                          */
00567 
00568                                         if (cup->ufnegzero != 0)
00569                                                 mode    = mode | MODEMSN;
00570                                         expon   = DEXP16;
00571                                         if (cup->ufcomplen == 0) {
00572                                                 width   = WREAL16;      
00573                                                 digits  = _dreal16 - 1;
00574                                         } else {
00575                                                 width   = WRL16;        
00576                                                 digits  = WDIG16;
00577                                         }
00578                                         break;
00579 
00580                                 default:
00581                                         return(FEKNTSUP); /* kind not supported */
00582                                 }
00583                                 break;
00584                         } /* switch */
00585 
00586                         /*
00587                          *      Perform the numeric output conversion.
00588                          */
00589 
00590                         switch (prevtyp) {      /* set up for each data type */
00591                                 register long   ldatum;
00592 
00593                         default:        /* Integer, Short Integer, Real, or Double */
00594         
00595                                 if (cup->ufcomplen == 0) {
00596                                         newp = gcf(prevptr, plain,
00597                                            &mode, &width, &digits,
00598                                            &expon, &scale);
00599                                         if (prevtyp == DVTYPE_TYPELESS)
00600                                                 *newp++ = (int) 'B';
00601                                         tptr    = tptr + _beautify(prevtyp, plain,
00602                                                 newp, tptr, cup->uft90);
00603                                 } else {
00604                                         newp = gcf(prevptr, tptr,
00605                                            &mode, &width, &digits,
00606                                            &expon, &scale);
00607 
00608                                         if (prevtyp == DVTYPE_TYPELESS)
00609                                                 *newp++ = (int) 'B';
00610                                         tptr    = tptr + width;
00611 
00612                                         }
00613                                 break;  
00614 
00615                         case DVTYPE_COMPLEX:
00616                                 *tptr++ = LPAREN;
00617 
00618                                 if (cup->ufcomplen == 0) {
00619                                         newp = gcf(prevptr, plain, &mode,
00620                                                 &width, &digits, &expon,
00621                                                 &scale);
00622 
00623                                         tptr = tptr + _beautify(prevtyp, plain,
00624                                                 newp, tptr, cup->uft90);
00625 
00626                                         *tptr++ = COMMA;
00627 
00628                                         newp = gcf(((char *)prevptr + realsz),
00629                                                 plain, &mode, &width, &digits,
00630                                                 &expon, &scale);
00631 
00632                                         tptr = tptr + _beautify(prevtyp, plain,
00633                                                 newp, tptr, cup->uft90);
00634                                 } else {
00635                                         newp = gcf(prevptr, tptr, &mode,
00636                                                 &width, &digits, &expon,
00637                                                 &scale);
00638                                         tptr    = tptr + width;
00639                                         *tptr++ = COMMA;
00640                                         newp = gcf(((char *)prevptr + realsz),
00641                                                 tptr, &mode, &width, &digits,
00642                                                 &expon, &scale);
00643                                         tptr    = tptr + width;
00644                                 }
00645                                 *tptr++ = RPAREN;
00646 
00647                                 break;
00648 
00649                         case DVTYPE_LOGICAL:
00650                                 switch (prevlen) {
00651 
00652 #ifdef  _F_LOG4
00653 #if     defined(_F_LOG2) && (defined(__mips) || defined(_LITTLE_ENDIAN))
00654                                         case 1:
00655                                                 ldatum  = *(_f_log1 *)prevptr;
00656                                                 break;
00657                                         case 2:
00658                                                 ldatum  = *(_f_log2 *)prevptr;
00659                                                 break;
00660 #endif  /* _F_LOG2 and mips or little endian */
00661                                         case 4:
00662                                                 ldatum  = *(_f_log4 *)prevptr;
00663                                                 break;
00664 #endif
00665                                         case 8:
00666                                                 ldatum  = *(_f_log8 *)prevptr;
00667                                                 break;
00668 
00669                                         default:
00670                                                 return(FEKNTSUP); /* kind not supported */
00671                                 }
00672 
00673                                 *tptr++ = _lvtob(ldatum) ? (long) 'T' : (long) 'F';
00674                                 break;
00675 
00676                         } /* switch */
00677 
00678                         tbsz    = tptr - tbuf;
00679 
00680                         if ((cup->ulinemax + blanks + tbsz) > cup->uldwsize) {
00681                                 register int    errn;   /* Error code */
00682 
00683                                 /*
00684                                  * Check that the item plus leading blank
00685                                  * would fit on a single line.
00686                                  */
00687 
00688                                 if (tbsz + 1 > cup->uldwsize)
00689                                         RERROR(FEWRLONG);       /* Record too long */
00690 
00691                                 /* Write record */
00692 
00693                                 errn    = (*css->u.fmt.endrec)(css, cup, 1);
00694 
00695                                 if (errn != 0)
00696                                         RERROR(errn);
00697 
00698                                 /* Leading blank */
00699 
00700                                 *(cup->ulineptr++)      = BLANK;
00701                                 cup->ulinemax           = cup->ulinemax + 1;
00702                         }
00703                         else {
00704                                 if ((cup->ulinemax + blanks) > cup->uldwsize)
00705                                         RERROR(FEWRLONG); /* Record too long */
00706 
00707 #ifdef  _CRAY
00708 #pragma _CRI shortloop
00709 #endif
00710                                 for (i = 0; i < blanks; i++)
00711                                         cup->ulineptr[i]        = BLANK;
00712 
00713                                 cup->ulinemax   = cup->ulinemax + blanks;
00714                                 cup->ulineptr   = cup->ulineptr + blanks;
00715                         }
00716 
00717                         /*
00718                          * Now copy the current output from tbuf into the 
00719                          * line buffer.  We should never exceed the size
00720                          * of the item buffer since ITEMBUFSIZ is set up
00721                          * to be sufficiently large for all cases. 
00722                          */
00723 
00724                         if (tbsz > ITEMBUFSIZ)
00725                                 _ferr(css, FEINTUNK);   /* deep weeds */
00726 
00727                         for (i = 0; i < tbsz; i++)      /* Should vectorize */
00728                                 cup->ulineptr[i]        = tbuf[i];
00729 
00730                         cup->ulineptr   = cup->ulineptr + tbsz;
00731                         cup->ulinemax   = cup->ulinemax + tbsz;
00732 
00733 done_printing_saved_value:
00734                         if (prevlen > sizeof(css->u.fmt.u.le.u.value))
00735                                 free(css->u.fmt.u.le.u.copy);
00736 
00737                         css->u.fmt.u.le.ndchar  = 0;    /* item was not nondelim char */
00738                         css->u.fmt.u.le.repcnt  = 0;    /* value buffer is now empty */
00739                         ndchar                  = 0;
00740                         repcnt                  = 0;
00741 
00742                 } /* End of saved output processing */
00743 
00744                 /*
00745                  * If count is zero, we are completing list-directed output
00746                  * statement processing.  
00747                  */
00748 
00749                 if (count == 0)
00750                         goto fin;
00751 
00752                 /*
00753                  * At this point, we are finally ready to handle the new 
00754                  * output value.  If it is nondelimited character, then we 
00755                  * print it right out.  Otherwise, we store the value in
00756                  * the css structure.
00757                  */
00758 
00759                 if (ischar && delim == 0) {     /* If nondelimited character */
00760                         register long   cnt;
00761                         register long   stride;
00762 
00763                         /*
00764                          * Take care of printing the possible value separator.
00765                          */
00766 
00767                         blanks  = 0;
00768 
00769                         if (css->u.fmt.u.le.item1)
00770                                 css->u.fmt.u.le.item1   = 0;
00771                         else if (!ndchar && cup->uft90 &&
00772                                   cup->ulinemax < cup->uldwsize) 
00773                                 blanks  = _90_char_nonchar_delim_blanks;
00774 
00775                         /* blanks is always 0 or 1 here */
00776 
00777                         assert ( blanks == 0 || blanks == 1 );
00778 
00779                         if (blanks > 0) {
00780                                 *(cup->ulineptr++)      = BLANK;
00781                                 cup->ulinemax           = cup->ulinemax + 1;
00782                         }
00783 
00784                         /*
00785                          * Check for unit stride character data.  These can
00786                          * be coalesced and transferred as a single datum.
00787                          */
00788 
00789                         cnt     = count;
00790 
00791                         if (vinc == 0 || vinc == 1) {
00792                                 elsize  = elsize * cnt;
00793                                 cnt     = 1;
00794                                 vinc    = 1;
00795                         }
00796 
00797                         stride  = elsize * vinc;
00798 
00799                         for (i = 0; i < cnt ; i++) {
00800                                 register int    j;
00801 
00802                                 for (j = 0; j < elsize; j++) {
00803 
00804                                         if (cup->ulinemax >= cup->uldwsize) {
00805                                                 register int    errn;
00806 
00807                                                 /* Write record */
00808 
00809                                                 errn    = (*css->u.fmt.endrec)(css, cup, 1);
00810 
00811                                                 if (errn != 0)
00812                                                         RERROR(errn);
00813 
00814                                                 /* Print blank in column 1 */
00815 
00816                                                 *(cup->ulineptr++)      = BLANK;
00817                                                 cup->ulinemax   = cup->ulinemax + 1;
00818                                         }
00819 
00820                                         *cup->ulineptr++        = (long) cptr[j];
00821                                         cup->ulinemax           = cup->ulinemax + 1;
00822                                 }
00823 
00824                                 cptr    = cptr + stride;
00825                         }
00826 
00827                         css->u.fmt.u.le.ndchar  = 1;    /* Set nondelim char */
00828                         css->u.fmt.u.le.repcnt  = 0;    /* Value buffer is empty */
00829 
00830                         goto fin;
00831 
00832                 } /* End of nondelimited character processing */
00833 
00834                 /*
00835                  * Find the number of consecutive duplicated values in the
00836                  * current batch of iolist items.
00837                  */
00838 
00839                 if ((count > 1) && (cup->ufrptcnt == 0))
00840                         dupcnt  = _find_dupcnt(cptr, count, vinc, elsize, ischar);
00841                 else
00842                         dupcnt  = 1;
00843 
00844                 /*
00845                  * If repcnt is zero, then we save a new value in the css
00846                  * structure and set the repeat count appropriately.
00847                  *
00848                  * If repcnt is nonzero, then we know that the value pointed
00849                  * to by cptr is equal to that saved with the previous repeat
00850                  * count.   In this case we simply increase the repeat count
00851                  * to allow for current data.
00852                  */
00853 
00854                 if (repcnt == 0) {
00855                         void    *valptr;
00856 
00857                         if (elsize > sizeof(css->u.fmt.u.le.u.value)) {
00858 
00859                                 valptr  = malloc(elsize);
00860 
00861                                 if (valptr == NULL) {
00862                                         RERROR(FENOMEMY);
00863                                 }
00864 
00865                                 css->u.fmt.u.le.u.copy  = valptr;
00866                         }
00867                         else
00868                                 valptr  = &css->u.fmt.u.le.u.value[0];
00869 
00870                         /* Copy the possibly repeated value */
00871 
00872                         if (ischar)     /* If character variable */
00873                                 (void) memcpy(valptr, cptr, elsize);
00874                         else {
00875                                 /* On Mips systems, it's possible to have */
00876                                 /* elsize == sizeof(long), but the */
00877                                 /* item is not aligned on a long boundary */
00878                                 /* e.g., Complex data in the 64bit-ABI */
00879                                 if (elsize == sizeof(int))
00880                                         *(int *) valptr = *(int *) cptr;
00881                                 else if (elsize == sizeof(short))
00882                                         *(short *) valptr       = *(short *) cptr;
00883                                 else
00884                                         (void) memcpy(valptr, cptr, elsize);
00885                         }
00886                 }
00887 
00888                 repcnt                  = repcnt + dupcnt;
00889                 css->u.fmt.u.le.repcnt  = repcnt;
00890                 css->u.fmt.u.le.type    = type;
00891                 css->u.fmt.u.le.elsize  = elsize;
00892 
00893                 /* Decrement count and advance data address */
00894 
00895 done:
00896                 count   = count - dupcnt;
00897                 cptr    = cptr + (dupcnt * vinc * elsize);
00898 
00899         } /* while */
00900 
00901 #ifdef  _CRAYT3D
00902         continue;
00903    } while (shared && offset < tcount);
00904 #endif
00905 
00906 fin:
00907         return(0);
00908 }
00909 
00910 /*
00911  *      _find_dupcnt
00912  *              Find and return the repeat count.  
00913  *
00914  *      Return Value
00915  *              The number of times the first datum is repeated
00916  *              consecutively in the data list.  If the datum is
00917  *              not repeated, a value of one is returned.
00918  */ 
00919 
00920 int
00921 _find_dupcnt(
00922         void    *ptr,   /* Pointer to data              */
00923         long    count,  /* Maximum number of data items */
00924         long    stride, /* Stride between items (in units of elsize)    */
00925         int     elsize, /* Bytes per datum              */
00926         short   ischar) /* Is type == CHARACTER?        */
00927 {
00928         register long   i;
00929 
00930         /* Assertions */
00931 
00932         assert ( ptr != NULL );
00933         assert ( count > 1 );
00934         assert ( elsize > 0 );
00935 
00936         if (! ischar && elsize != sizeof(char)) {/* If not character or 1 byte*/
00937 #if     (!defined(_WORD32) && ( defined(_F_INT4) || defined(_F_REAL4))) \
00938         || defined(__mips) || defined(_LITTLE_ENDIAN)
00939                 if (elsize == sizeof(short)) {
00940                         register short  value;
00941                         short           *sptr;
00942 
00943                         sptr    = (short *) ptr;
00944                         value   = *sptr;
00945  
00946                         for (i = 1; i < count; i++) {
00947 
00948                                 sptr    = sptr + stride;
00949 
00950                                 if (value != *sptr)
00951                                         break;
00952                         }
00953                 }
00954                 else
00955 #endif  /* (not _word32 and (_f_int4 or _f_real4)) or mips or little endian */
00956                 if (elsize == sizeof(int)){ 
00957                         register int    value;
00958                         int             *lptr;
00959 
00960                         lptr    = (int *) ptr;
00961                         value   = *lptr;
00962 
00963                         for (i = 1; i < count; i++) {
00964 
00965                                 lptr    = lptr + stride;
00966 
00967                                 if (value != *lptr)
00968                                         break;
00969                         }
00970                 }
00971                 else {                          /* elsize > sizeof(int) */
00972                         register int    words;
00973                         register int    linc;
00974                         int             *p1, *p2;
00975 
00976                         words   = elsize / sizeof(int);
00977                         linc    = stride * words;
00978                         p1      = (int * ) ptr;
00979                         p2      = p1 + linc;
00980 
00981                         for (i = 1; i < count; i++) {
00982                                 register int    j;
00983 
00984 #ifdef  _CRAY
00985 #pragma _CRI shortloop
00986 #endif
00987                                 for (j = 0; j < words; j++)
00988                                         if ((p1[j] != p2[j]))
00989                                                 goto done;
00990 
00991                                 p2      = p2 + linc;
00992                         }
00993                 }
00994         }
00995         else {                  /* Character */
00996                 register long   cinc;
00997                 char            *pchr;
00998 
00999                 cinc    = elsize * stride;
01000                 pchr    = ((char *) ptr) + cinc;
01001 
01002                 for (i = 1; i < count; i++) {
01003 
01004                         if (memcmp(ptr, pchr, elsize) != 0)
01005                                 break;
01006 
01007                         pchr    = pchr + cinc;
01008                 }
01009         }
01010 
01011 done:
01012         return(i);
01013 }
01014 
01015 /*
01016  *      _beautify 
01017  *
01018  *              Beautify numeric output by deleting blanks and
01019  *              truncating unnecessary trailing zeroes.  The altered
01020  *              ascii number is placed in "pretty".
01021  *
01022  *              Input is in this form: {LH part}[{E}{exponent}]
01023  *
01024  *      Return value:
01025  *              The number of characters in the beautified output.
01026  */
01027 int
01028 _beautify(
01029         ftype_t type,           /* Data type of the number */
01030         long    *plain,         /* Raw ascii representation of a number */
01031         long    *limit,         /* Pointer to one past end of ASCII data in plain */
01032         long    *pretty,        /* Receives the beautified output */
01033         short   isf90)          /* 1 iff Fortran 90 style printing of 0.E+0 */ 
01034 {
01035         register short  i;
01036         register short  length;
01037         long            *p, *start, *exp, *end;
01038 
01039         /* Point start to the first nonblank character */
01040 
01041         start   = plain;
01042 
01043         while (*start == BLANK)
01044                 start   = start + 1;
01045 
01046         /* Point end one past the last nonblank character */ 
01047 
01048         end     = limit;                /* find end point */
01049 
01050         while (*(end - 1) == BLANK)
01051                 end     = end - 1;
01052 
01053         if (type == DVTYPE_TYPELESS || type == DVTYPE_INTEGER) {
01054 
01055                 length  = end - start;
01056 
01057                 /* The following loop should vectorize */
01058 
01059 #ifdef  _MAXVL
01060                 assert (length < 64);
01061 
01062 #pragma _CRI shortloop
01063 #endif
01064                 for (i = 0; i < length; i++)
01065                         pretty[i]       = start[i];
01066 
01067                 return((int) length);
01068         }
01069 
01070 /*
01071  *      Point exp to the 'E'.  Assign it NULL if there is not 'E' in the 
01072  *      number (integer or F format style).
01073  */
01074         exp     = NULL;
01075 
01076         for (p = end - 1; p > start; p--) {
01077                 if (*p == (long) 'E') {
01078                         exp     = p;
01079                         break;
01080                 }
01081         }
01082 
01083         if (exp != NULL) {      /* If E format output */
01084                 long    *zero;
01085 
01086                 zero    = exp;
01087 
01088                 /*
01089                  * Point zero to one place past the last nonzero digit in 
01090                  * the LH part. 
01091                  */
01092 
01093                 while ( *(zero - 1) == ZERO)
01094                         zero    = zero - 1;             
01095 
01096                 /*
01097                  * Copy 'E+(-)'.  Then zero is advanced to the future
01098                  * location of the exponent, and exp is pointed to the
01099                  * current location of the exponent.  
01100                  */
01101 
01102                 *zero++ = *exp++;
01103                 *zero++ = *exp++;
01104 
01105                 /* 
01106                  * Remove all leading zeroes in the exponent.  Do not remove
01107                  * a zero exponent though.  Let the G editing output function
01108                  * called previously or the 0 beautification below be 
01109                  * responsible for choosing the F or E edit descriptor output 
01110                  * form.
01111                  */
01112 
01113                 while (exp < (end - 1) && *exp == ZERO)  
01114                         exp     = exp + 1;
01115 
01116                 while (exp < end)
01117                         *zero++ = *exp++;
01118 
01119                 end     = zero;
01120         }
01121         else {                  /* Else if F format output */
01122                 while (*(end - 1) == ZERO)
01123                         end     = end - 1;      /* trim trailing zeroes */
01124         }
01125 
01126         length  = end - start;
01127 
01128         /* The following loop should vectorize */
01129 
01130 #ifdef  _MAXVL
01131                 assert (length < 64);
01132 
01133 #pragma _CRI shortloop
01134 #endif
01135         for (i = 0; i < length; i++)
01136                 pretty[i]       = start[i];
01137 
01138 /*
01139  *      Floating point 0 values, both single and double precision, are
01140  *      printed as:
01141  *
01142  *              If in Fortran 90 mode:           0.E+0
01143  *              If in CF77 mode:                 0.
01144  */
01145 
01146         if (pretty[0] == ZERO && pretty[1] == PERIOD &&
01147             (length == 2 || (length > 2 && pretty[2] == (long) 'E'))) {
01148 
01149                 length  = 2;
01150 
01151                 if (isf90) {
01152                         pretty[length++]        = (long) 'E';
01153                         pretty[length++]        = PLUS;
01154                         pretty[length++]        = ZERO;
01155                 }
01156         }
01157 
01158         return (length);        /* return length of beautified output */
01159 }
01160 
01161 /*
01162  *      _write_delimited_char
01163  *              Write out to the line buffer a delimited character value
01164  *              with internal doubling of the delimiter characters.  If
01165  *              the value will not fit on the current line, spill to 
01166  *              subsequent lines as needed.  (On subsequent lines, no extra
01167  *              space character is is placed in column 1).
01168  *
01169  *      Return value:
01170  *
01171  *               0 on success.  
01172  *              >0 error code if an error condition is encountered.
01173  */
01174 int
01175 _write_delimited_char(
01176         FIOSPTR css,            /* Fortran statement state */
01177         unit    *cup,           /* Unit pointer */
01178         char    *sptr,          /* Pointer to string */
01179         int     len,            /* Length of string to be printed */
01180         long    dchar           /* delimiter character to use */
01181 )
01182 {
01183         register short  eoln;   /* End of line flag */
01184         register int    errn;   /* Error code */
01185 
01186 /*
01187  *      Print out the opening delimiter.
01188  */
01189         if (cup->ulinemax >= cup->uldwsize) {
01190 
01191                 errn    = (*css->u.fmt.endrec)(css, cup, 1);
01192 
01193                 if (errn != 0)
01194                         return(errn);
01195 
01196                 if (css->f_iostmt == T_WNL && !cup->uft90) {
01197                         cup->ulinemax           = cup->ulinemax + 1;
01198                         *(cup->ulineptr++)      = BLANK;
01199                 }
01200         }
01201 
01202         *(cup->ulineptr++)      = dchar;        
01203         cup->ulinemax           = cup->ulinemax + 1;
01204 /*
01205  *      Print out the string.
01206  */
01207         eoln    = 0;
01208 
01209         while (len > 0) {
01210                 if (eoln) {
01211 
01212                         errn    = (*css->u.fmt.endrec)(css, cup, 1);
01213 
01214                         if (errn != 0)
01215                                 return(errn);
01216 
01217                         eoln    = 0;
01218 
01219                         if (css->f_iostmt == T_WNL && !cup->uft90) {
01220                                 cup->ulinemax           = cup->ulinemax + 1;
01221                                 *(cup->ulineptr++)      = BLANK;
01222                         }
01223                 }
01224 
01225                 if (*sptr == (char) dchar) {
01226                         /*
01227                          * Next part of string is an imbedded delimiter 
01228                          * character.  Double the delimiter character.
01229                          */
01230                         if ((cup->ulinemax + 2) > cup->uldwsize)
01231                                 eoln    = 1;
01232                         else {
01233                                 *(cup->ulineptr++)      = dchar;        
01234                                 *(cup->ulineptr++)      = dchar;        
01235                                 cup->ulinemax           = cup->ulinemax + 2;
01236                                 len                     = len - 1;
01237                                 sptr                    = sptr + 1;
01238                         }
01239                 }
01240                 else {
01241                         /*
01242                          * Process a chunk of the string which contains no 
01243                          * imbedded delimiter characters and can fit on the 
01244                          * current line.
01245                          */
01246 
01247                         if (cup->ulinemax >= cup->uldwsize)
01248                                 eoln    = 1;
01249                         else {
01250                                 register int    chunk;
01251                                 char            *nxtdelm;
01252 
01253                                 chunk   = cup->uldwsize - cup->ulinemax;
01254                                 chunk   = (len < chunk) ? len : chunk;
01255 
01256                                 nxtdelm = memchr(sptr, (int) dchar, chunk);
01257 
01258                                 if (nxtdelm != NULL)
01259                                         chunk   = nxtdelm - sptr;
01260 
01261                                 (void) _unpack(sptr, cup->ulineptr, chunk, -1);
01262 
01263                                 cup->ulinemax   = cup->ulinemax + chunk;
01264                                 cup->ulineptr   = cup->ulineptr + chunk;
01265                                 len             = len - chunk;
01266                                 sptr            = sptr + chunk;
01267                         }
01268                 }
01269         } /* while */
01270 
01271 /*
01272  *      Print out the closing delimiter.
01273  */
01274         if (cup->ulinemax >= cup->uldwsize) {
01275 
01276                 errn    = (*css->u.fmt.endrec)(css, cup, 1);
01277 
01278                 if (errn != 0)
01279                         return(errn);
01280 
01281                 if (css->f_iostmt == T_WNL && !cup->uft90) {
01282                         cup->ulinemax           = cup->ulinemax + 1;
01283                         *(cup->ulineptr++)      = BLANK;
01284                 }
01285         }
01286 
01287         *(cup->ulineptr++)      = dchar;        
01288         cup->ulinemax           = cup->ulinemax + 1;
01289 
01290         return(0);
01291 }
01292 
01293 /*
01294  *      _lwrite_setup
01295  *
01296  *              Access the LISTIO_PRECISION environment variable to choose 
01297  *              between styles of list directed output of reals.
01298  *
01299  *              FULL    - full precision output.   This ensures that all digits
01300  *                        with any precision (and possibly some with no
01301  *                        precision) are printed.  This is default.
01302  *              PRECISION - the number of digits printed is P or P+1,
01303  *                        depending on whether the library chooses
01304  *                        F or E format.  P is the value of the 
01305  *                        F90 PRECISION() intrinsic function.
01306  *              YMP80     - the number of digits printed is compatible with
01307  *                        UNICOS 8.0 and previous.   This is available only
01308  *                        on YMP/C90/TS systems.
01309  *              F77       - the number of digits printed is mostly compatible 
01310  *                        with that chosen by the Sparc f77 compiler.  This
01311  *                        is available only on Sparc, and only for internal
01312  *                        use.
01313  *
01314  *
01315  *              This function is called by _initialize_fortran_io()
01316  */
01317 void
01318 _lwrite_setup(void)        
01319 {
01320         char    *str;
01321 
01322 #ifdef  _F_REAL4
01323         _dreal4         = DREAL4;
01324 #endif
01325 
01326         _dreal8         = DREAL8;
01327         _dreal16        = DREAL16;
01328 
01329 /*
01330  *      The LISTIO_PRECISION environment variable can be set to specify
01331  *      a choice in the number of digits of precision requested for real
01332  *      values being printed via list directed output.
01333  */
01334         str     = getenv("LISTIO_PRECISION");
01335 
01336         if (str != NULL) {
01337                 if (strcmp(str, "FULL") == 0) {
01338                         _dreal8         = DREAL8;
01339                         _dreal16        = DREAL16;
01340                 }
01341                 else if (strcmp(str, "PRECISION") == 0) {
01342 #ifdef  _F_REAL4
01343                         _dreal4         = DREAL4_P;
01344 #endif
01345                         _dreal8         = DREAL8_P;
01346                         _dreal16        = DREAL16_P;
01347                 }
01348                 else if (strcmp(str, "YMP80") == 0) {
01349                         _dreal8         = DREAL8_YMP80;
01350                         _dreal16        = DREAL16_YMP80;
01351                 }
01352                 else if (strcmp(str, "F77") == 0) {     /* internal use only */
01353 #ifdef  _F_REAL4
01354                         _dreal4         = 6;
01355 #endif
01356                         _dreal8         = 14;
01357                 }
01358         }
01359 
01360 /*
01361  *      The LISTIO_OUTPUT_STYLE environment variable can be set to 'OLD' 
01362  *      to cause list-directed output to be more consistent with CrayLibs 1.2.  
01363  *      Specifically, this will cause the following effects:
01364  *
01365  *              1) Repeat counts will not span separate calls to _ld_write().
01366  *              2) A space will not be printed as a value separator between
01367  *                 non-delimited character and non-character output list items
01368  *                 in F90 mode (if cup->uft90==1).
01369  *              3) A space will not be printed in column 1 of a list-directed
01370  *                 WRITE statement containing no I/O list items.
01371  *
01372  */
01373         str     = getenv("LISTIO_OUTPUT_STYLE");
01374 
01375         if (str != NULL && strcmp(str, "OLD") == 0) {
01376                 _old_list_out_repcounts         = 1;
01377                 _90_char_nonchar_delim_blanks   = 0;
01378                 _blank_at_start_of_empty_rec    = 0;
01379         }
01380 
01381         return;
01382 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines