Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
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 }