Package chianti :: Package fortranformat :: Module _output
[hide private]
[frames] | no frames]

Source Code for Module chianti.fortranformat._output

  1  import math 
  2  import itertools 
  3  import sys 
  4  IS_PYTHON3 = sys.version_info[0] >= 3 
  5   
  6  if IS_PYTHON3: 
  7      exec('from ._edit_descriptors import *') 
  8      exec('from ._misc import expand_edit_descriptors, has_next_iterator') 
  9      exec('from . import config') 
 10  else: 
 11      exec('from _edit_descriptors import *') 
 12      exec('from _misc import expand_edit_descriptors, has_next_iterator') 
 13      import config     
 14  #    exec('import fortranformat.config as config') 
 15   
 16   
 17  PROC_SIGN_ZERO = config.PROC_SIGN_ZERO 
 18  PROC_MIN_FIELD_WIDTH = config.PROC_MIN_FIELD_WIDTH 
 19  PROC_DECIMAL_CHAR = config.PROC_DECIMAL_CHAR 
 20  G0_NO_BLANKS = config.G0_NO_BLANKS 
 21  PROC_NO_LEADING_BLANK = config.PROC_NO_LEADING_BLANK 
 22   
23 -def output(eds, reversion_eds, values):
24 ''' 25 a function to take a list of valid f77 edit descriptors and respective values 26 and output the corresponding string 27 ''' 28 record = '' 29 state = { 30 'position' : 0, 31 'scale' : 0, 32 'incl_plus' : False, 33 'blanks_as_zeros' : False, 34 'halt_if_no_vals' : False, 35 } 36 37 # if format is empty with no values specified, then output blank record - 38 # see section 13.3 39 40 # check that if there is a reversion, that values can be output 41 reversion_contains_output_ed = False 42 for ed in reversion_eds: 43 if isinstance(ed, OUTPUT_EDS): 44 reversion_contains_output_ed = True 45 break 46 # Get full list of edit descriptors 47 eds = expand_edit_descriptors(eds) 48 reversion_eds = expand_edit_descriptors(reversion_eds) 49 # use iterators 50 get_ed = has_next_iterator(eds) 51 get_value = has_next_iterator(values) 52 tmp_reversion_eds = [] 53 # continue until out of edit descriptors or values 54 while True: 55 # no more edit descriptors, no more values, stop output, 56 # todo: this will cut short a reversion edit descriptor section - is this right? 57 if not get_ed.has_next() and not get_value.has_next(): 58 break 59 # take a edit descriptor off the queue if there is any 60 if get_ed.has_next(): 61 if IS_PYTHON3: 62 ed = next(get_ed) 63 else: 64 ed = get_ed.next() 65 else: 66 if reversion_contains_output_ed == True: 67 # take from reversion edit descriptors if there is a value 68 # requiring output still 69 while True: 70 if len(tmp_reversion_eds): 71 ed = tmp_reversion_eds.pop() 72 # these edit descriptors are ignored in reversion state 73 if not isinstance(ed, NON_REVERSION_EDS): 74 break 75 else: 76 # Regardless of where cursor is, is moved to the 77 # next record 78 record = record + config.RECORD_SEPARATOR 79 state['position'] = len(record) 80 tmp_reversion_eds = reversion_eds[::-1] 81 else: 82 # ignore the revsion edit descriptors as cannot output the 83 # final value 84 break 85 # check if edit descriptor requires a value 86 if isinstance(ed, OUTPUT_EDS): 87 if get_value.has_next(): 88 if IS_PYTHON3: 89 val = next(get_value) 90 else: 91 val = get_value.next() 92 else: 93 # is a edit descriptor that requires a value but no value 94 # todo: does it stop gracefully or raise error? 95 break 96 if isinstance(ed, I): 97 sub_string = _compose_i_string(ed.width, ed.min_digits, state, val) 98 elif isinstance(ed, B): 99 w = ed.width 100 m = ed.min_digits 101 sub_string = _compose_boz_string(w, m, state, val, 'B') 102 if isinstance(ed, O): 103 w = ed.width 104 m = ed.min_digits 105 sub_string = _compose_boz_string(w, m, state, val, 'O') 106 if isinstance(ed, Z): 107 w = ed.width 108 m = ed.min_digits 109 sub_string = _compose_boz_string(w, m, state, val, 'Z') 110 elif isinstance(ed, F): 111 w = ed.width 112 e = None 113 d = ed.decimal_places 114 sub_string = _compose_float_string(w, e, d, state, val, 'F') 115 elif isinstance(ed, E): 116 w = ed.width 117 e = ed.exponent 118 d = ed.decimal_places 119 sub_string = _compose_float_string(w, e, d, state, val, 'E') 120 elif isinstance(ed, D): 121 w = ed.width 122 e = None 123 d = ed.decimal_places 124 sub_string = _compose_float_string(w, e, d, state, val, 'D') 125 elif isinstance(ed, G): 126 w = ed.width 127 e = ed.exponent 128 d = ed.decimal_places 129 sub_string = _compose_float_string(w, e, d, state, val, 'G') 130 elif isinstance(ed, EN): 131 w = ed.width 132 e = ed.exponent 133 d = ed.decimal_places 134 sub_string = _compose_float_string(w, e, d, state, val, 'EN') 135 elif isinstance(ed, ES): 136 w = ed.width 137 e = ed.exponent 138 d = ed.decimal_places 139 sub_string = _compose_float_string(w, e, d, state, val, 'ES') 140 elif isinstance(ed, L): 141 sub_string = _compose_l_string(ed.width, state, val) 142 elif isinstance(ed, A): 143 sub_string = _compose_a_string(ed.width, state, val) 144 state['position'], record = _write_string(record, sub_string, state['position']) 145 else: 146 # token does not require a value 147 if isinstance(ed, (S, SS)): 148 state['incl_plus'] = False 149 if isinstance(ed, SP): 150 state['incl_plus'] = True 151 elif isinstance(ed, P): 152 state['scale'] = ed.scale 153 elif isinstance(ed, BN): 154 # This is moot since for output, this does not do anything 155 state['blanks_as_zeros'] = False 156 elif isinstance(ed, BZ): 157 state['blanks_as_zeros'] = True 158 elif isinstance(ed, Colon): 159 state['halt_if_no_vals'] = True 160 elif isinstance(ed, Slash): 161 state['position'], record = _write_string(record, config.RECORD_SEPARATOR, state['position']) 162 elif isinstance(ed, (X, TR)): 163 state['position'] = state['position'] + ed.num_chars 164 elif isinstance(ed, TL): 165 state['position'] = state['position'] - ed.num_chars 166 elif isinstance(ed, T): 167 state['position'] = ed.num_chars - 1 168 elif isinstance(ed, QuotedString): 169 sub_string = ed.char_string 170 state['position'], record = _write_string(record, sub_string, state['position']) 171 # output the final record 172 return record
173
174 -def _compose_nan_string(w, ftype):
175 if ftype in ['B', 'O', 'Z']: 176 return '' 177 else: 178 # Allow at least 'NaN' to be printed 179 if w == 0: 180 w = 4 # n.b. this is what is set in Gfortran 4.4.0 181 if w < 3: 182 return '*' * w 183 return 'NaN'.rjust(w)
184
185 -def _compose_inf_string(w, ftype, sign_bit):
186 if ftype in ['B', 'O', 'Z']: 187 return '' 188 else: 189 sign = '+' 190 # Allow at least 'Inf' to be printed 191 if w == 0: 192 w = 4 193 if w < 3: 194 return '*' * w 195 # Change sign if negative 196 if sign_bit: 197 sign = '-' 198 # Require sign if negative, if no space then overflow 199 if w == 3: 200 return '*' * w 201 # Output long version if long enough 202 if w > 8: 203 return (sign + 'Infinity').rjust(w) 204 # Output shortened version with sign if long enough 205 elif w > 3: 206 return (sign + 'Inf').rjust(w) 207 # Should only output short version with no sign if positive 208 else: 209 return 'Inf'
210 211
212 -def _compose_float_string(w, e, d, state, val, ftype):
213 ''' 214 Adapted from code in glibfortran which is written in C so is somwhat 215 'bit-pushy' in nature. Writes the value to an initial string (buffer) 216 and then pulls the subsequent strings from that 217 ''' 218 if (d < 0) or (d is None): 219 raise InvalidFormat('Unspecified precision') 220 # Make sure they are ints 221 d = int(round(d)) 222 if e is not None: 223 e = int(round(e)) 224 if w is not None: 225 w = int(round(w)) 226 # ==== write_float ==== (function) 227 edigits = 4 # Largest number of exponent digits expected 228 if (ftype in ['F', 'EN', 'G']) or \ 229 ((ftype in ['D', 'E']) and (state['scale'] != 0)): 230 # Convert with full possible precision 231 ndigits = PROC_MIN_FIELD_WIDTH - 4 - edigits 232 else: 233 # Otherwise convert knowing what the required precision is (i.e. knowing d) 234 if ftype == 'ES': 235 ndigits = d + 1 236 else: 237 ndigits = d 238 if ndigits > (PROC_MIN_FIELD_WIDTH - 4 - edigits): 239 ndigits = PROC_MIN_FIELD_WIDTH - 4 - edigits 240 # ==== WRITE_FLOAT ==== (macro) 241 # Determine sign of value 242 if val == 0.0: 243 sign_bit = '-' in str(val) 244 else: 245 sign_bit = val < 0 246 # handle the nan and inf cases 247 if type(val) is float and val != val : 248 return _compose_nan_string(w, ed) 249 Infinity = 1e1000000 250 if val in (-Infinity, Infinity): 251 return _compose_inf_string(w, ed, sign_bit) 252 tmp = abs(val) 253 # Round the input if the input is less than 1 254 if (ftype == 'F') and (d == state['scale']) and (d == 0): 255 if tmp < 1.0: 256 tmp = round(tmp) 257 zero_flag = (tmp == 0) 258 # === DTOA === (macro) 259 # write the tmp value to the string buffer 260 # sprintf seems to allow negative number of decimal places, need to correct for this 261 if ndigits <= 0: 262 fmt = '%+-#' + str(PROC_MIN_FIELD_WIDTH) + 'e' 263 else: 264 fmt = '%+-#' + str(PROC_MIN_FIELD_WIDTH) + '.' + str(ndigits - 1) + 'e' 265 buff = fmt % tmp 266 # === WRITE_FLOAT === (macro) 267 if ftype != 'G': 268 return _output_float(w, d, e, state, ftype, buff, sign_bit, zero_flag, ndigits, edigits) 269 else: 270 # Perform different actions for G edit descriptors depending on value 271 # 272 # Generate corresponding I/O format for FMT_G and output. 273 # The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran 274 # LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is: 275 # 276 # Data Magnitude Equivalent Conversion 277 # 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee] 278 # m = 0 F(w-n).(d-1), n' ' 279 # 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' ' 280 # 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' ' 281 # 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' ' 282 # ................ .......... 283 # 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ') 284 # m >= 10**d-0.5 Ew.d[Ee] 285 # 286 # notes: for Gw.d , n' ' means 4 blanks 287 # for Gw.dEe, n' ' means e+2 blanks 288 nb = 0 289 save_scale_factor = state['scale'] 290 exp_d = 10 ** d 291 if (0.0 <= tmp < (0.1 - 0.05 / exp_d)) or \ 292 (tmp >= (exp_d - 0.5)): 293 ftype = 'E' 294 else: 295 mag = int(abs(round(math.log10(tmp)))) 296 low = lambda mag, d : 10 ** (mag - 1) - 5 * 10 ** (-d - 1 + mag) 297 high = lambda mag, d : 10 ** mag - 0.5 * 10 ** (-d + mag) 298 while tmp < low(mag, d): 299 mag = mag - 1 300 while tmp >= high(mag, d): 301 mag = mag + 1 302 assert(low(mag, d) <= tmp < high(mag, d)) 303 if e < 0: 304 nb = 4 305 else: 306 nb = e + 2 307 ftype = 'F' 308 w = w - nb 309 if tmp == 0.0: 310 d = d - 1 311 else: 312 d = d - mag 313 # d = -(mid - d - 1) 314 state['scale'] = 0 315 out = _output_float(w, d, e, state, ftype, buff, sign_bit, zero_flag, ndigits, edigits) 316 state['scale'] = save_scale_factor 317 # TODO: this may not be right ... 318 if nb > 0: 319 if '*' in out: 320 out = out + ('*' * nb) 321 else: 322 out = out + (' ' * nb) 323 if len(out) > (w + nb): 324 out = '*' * (w + nb) 325 return out
326 327
328 -def _output_float(w, d, e, state, ft, buff, sign_bit, zero_flag, ndigits, edigits):
329 330 # nbefore - number of digits before the decimal point 331 # nzero - number of zeros after the decimal point 332 # nafter - number of digits after the decimal point 333 # nzero_real - number of zeros after the decimal point regardles of the precision 334 335 # Some hacks to change None to -1 (C convention) 336 if w is None: 337 w = -1 338 if e is None: 339 e = -1 340 nzero_real = -1 341 sign = _calculate_sign(state, sign_bit) 342 # Some debug 343 if d != 0: 344 assert(buff[2] in ['.', ',']) 345 assert(buff[ndigits + 2] == 'e') 346 # Read in the exponent 347 ex = int(buff[ndigits + 3:]) + 1 348 # Handle zero case 349 if zero_flag: 350 ex = 0 351 if PROC_SIGN_ZERO: 352 sign = _calculate_sign(state, sign_bit) 353 else: 354 sign = _calculate_sign(state, False) 355 # Handle special case 356 if w == 0: 357 w = d + 2 358 # This case does not include a decimal point 359 if (w == 1) and (ft == 'F'): 360 if state['incl_plus']: 361 return '*' # This is ifort behaviour 362 else: 363 return '.' # CHANGED: Was '0' 364 # Get rid of the decimal and the initial sign i.e. normalise the digits 365 digits = buff[1] + buff[3:] 366 # Find out where to place the decimal point 367 if ft == 'F': 368 nbefore = ex + state['scale'] 369 if nbefore < 0: 370 nzero = -nbefore 371 nzero_real = nzero 372 if nzero > d: 373 nzero = d 374 nafter = d - nzero 375 nbefore = 0 376 else: 377 nzero = 0 378 nafter = d 379 expchar = None 380 elif ft in ['E', 'D']: 381 i = state['scale'] 382 if (d <= 0) and (i == 0): 383 raise InvalidFormat("Precision not greater than zero in format specifier 'E' or 'D'") 384 if (i <= -d) or (i >= (d + 2)): 385 raise InvalidFormat("Scale factor out of range in format specifier 'E' or 'D'") 386 if not zero_flag: 387 ex = ex - i 388 if i < 0: 389 nbefore = 0 390 nzero = -i; 391 nafter = d + i 392 elif i > 0: 393 nbefore = i 394 nzero = 0 395 nafter = (d - i) + 1 396 else: 397 nbefore = 0 398 nzero = 0 399 nafter = d 400 expchar = ft 401 elif ft == 'EN': 402 # Exponent must be a multiple of 3 with 1-3 digits before the d.p 403 if not zero_flag: 404 ex = ex - 1 405 if ex >= 0: 406 nbefore = ex % 3 407 else: 408 nbefore = (-ex) % 3 409 if nbefore != 0: 410 nbefore = 3 - nbefore 411 ex = ex - nbefore 412 nbefore = nbefore + 1 413 nzero = 0 414 nafter = d 415 expchar = 'E' 416 elif ft == 'ES': 417 if not zero_flag: 418 ex = ex - 1 419 nbefore = 1 420 nzero = 0 421 nafter = d 422 expchar = 'E' 423 # Round the value 424 if (nbefore + nafter) == 0: 425 ndigits = 0 426 if (nzero_real == d) and (int(digits[0]) >= 5): # n.b. character comparison not very pythonic! 427 # We rounded to zero but shouldn't have 428 nzero = nzero - 1 429 nafter = 1 430 digits = '1' + digits[1:] 431 ndigits = 1 432 elif (nbefore + nafter) < ndigits: 433 ndigits = nbefore + nafter 434 i = ndigits 435 if int(digits[i]) >= 5: 436 # Propagate the carry 437 i = i - 1 438 while i >= 0: 439 digit = int(digits[i]) 440 if digit != 9: 441 digits = _swapchar(digits, i, str(digit + 1)) 442 break 443 else: 444 digits = _swapchar(digits, i, '0') 445 i = i - 1 446 # Did the carry overflow? 447 if i < 0: 448 digits = '1' + digits 449 if ft == 'F': 450 if nzero > 0: 451 nzero = nzero - 1 452 nafter = nafter + 1 453 else: 454 nbefore = nbefore + 1 455 elif ft == 'EN': 456 nbefore = nbefore + 1 457 if nbefore == 4: 458 nbefore = 1 459 ex = ex + 3 460 else: 461 ex = ex + 1 462 # Calculate the format of the exponent field 463 if expchar is not None: 464 # i = abs(ex) 465 # while i >= 10: 466 # edigits = edigits + 1 467 # i = i / 10.0 468 if e < 0: 469 # Width not specified, must be no more than 3 digits 470 if (ex > 999) or (ex < -999): 471 edigits = -1 472 else: 473 edigits = 4 474 if (ex > 99) or (ex < -99): 475 expchar = ' ' 476 else: 477 assert(isinstance(ex, int)) 478 edigits = len(str(abs(ex))) 479 # Exponenet width specified, check it is wide enough 480 if edigits > e: 481 edigits = -1 482 else: 483 edigits = e + 2 484 else: 485 edigits = 0 486 # Zero values always output as positive, even if the value was egative before rounding 487 i = 0 488 while i < ndigits: 489 if digits[i] != '0': 490 break 491 i = i + 1 492 if i == ndigits: 493 # The output is zero so set sign accordingly 494 if PROC_SIGN_ZERO: 495 sign = _calculate_sign(state, sign_bit) 496 else: 497 sign = _calculate_sign(state, False) 498 # Pick a field size if none was specified 499 if w <= 0: 500 w = nbefore + nzero + nafter + 1 + len(sign) 501 # Work out how much padding is needed 502 nblanks = w - (nbefore + nzero + nafter + edigits + 1) 503 if sign != '': 504 nblanks = nblanks - 1 505 # TODO: Find out what this is 506 if G0_NO_BLANKS: # dtp->u.p.g0_no_blanks 507 w = w - nblanks 508 nblanks = 0 509 # Check value fits in specified width 510 if (nblanks < 0) or (edigits == -1): 511 return '*' * w 512 # See if we have space for a zero before the decimal point 513 if (nbefore == 0) and (nblanks > 0): 514 leadzero = True 515 nblanks = nblanks - 1 516 else: 517 leadzero = False 518 out = '' 519 # Pad to full field width 520 if (nblanks > 0) and not PROC_NO_LEADING_BLANK: # dtp->u.p.no_leading_blank 521 out = out + ' ' * nblanks 522 # Attach the sign 523 out = out + sign 524 # Add the lead zero if necessary 525 if leadzero: 526 out = out + '0' 527 # Output portion before the decimal point padded with zeros 528 if nbefore > 0: 529 if nbefore > ndigits: 530 out = out + digits[:ndigits] + (' ' * (nbefore - ndigits)) 531 digits = digits[ndigits:] 532 ndigits = 0 533 else: 534 i = nbefore 535 out = out + digits[:i] 536 digits = digits[i:] 537 ndigits = ndigits - i 538 # Output the decimal point 539 out = out + PROC_DECIMAL_CHAR 540 # Output the leading zeros after the decimal point 541 if nzero > 0: 542 out = out + ('0' * nzero) 543 # Output the digits after the decimal point, padded with zeros 544 if nafter > 0: 545 if nafter > ndigits: 546 i = ndigits 547 else: 548 i = nafter 549 zeros = '0' * (nafter - i) 550 out = out + digits[:i] + zeros 551 digits = digits[nafter:] 552 ndigits = ndigits - nafter 553 # Output the exponent 554 if expchar is not None: 555 if expchar != ' ': 556 out = out + expchar 557 edigits = edigits - 1 558 fmt = '%+0' + str(edigits) + 'd' 559 tmp_buff = fmt % ex 560 # if not state['blanks_as_zeros']: 561 if PROC_NO_LEADING_BLANK: 562 tmp_buf = tmp_buff + (nblanks * ' ') 563 out = out + tmp_buff 564 return out
565 566
567 -def _calculate_sign(state, negative_flag):
568 s = '' 569 if negative_flag: 570 s = '-' 571 elif state['incl_plus']: 572 s = '+' 573 else: 574 s = '' 575 return s
576
577 -def _swapchar(s, ind, newch):
578 ''' 579 Helper function to make chars in a string mutableish 580 ''' 581 if 0 < ind >= len(s): 582 raise IndexError('index out of range') 583 return s[:ind] + newch + s[ind+1:]
584 585
586 -def _compose_a_string(w, state, val):
587 # f77 spec 13.5.11 covers a editing 588 val = str(val) 589 if w is None: 590 output = val 591 elif w >= len(val): 592 output = val.rjust(w) 593 else: 594 output = val[:w] 595 return output
596 597
598 -def _compose_l_string(w, state, val):
599 # f77 spec 13.5.10 covers l editing 600 try: 601 val = bool(val) 602 except ValueError: 603 raise ValueError("cannot convert '%s' to a boolean" % str(val)) 604 # single t or f 605 if val == True: 606 sub_string = 'T' 607 else: 608 sub_string = 'F' 609 # now pad to the specified width 610 sub_string = sub_string.rjust(w) 611 return sub_string
612 613
614 -def _compose_i_string(w, m, state, val):
615 # f77 spec 13.5.9.1 covers integer editing 616 null_field = False 617 # be pythonic in what values to accept, if it looks like an integer, then 618 # so be it 619 try: 620 val = int(val) 621 except ValueError: 622 raise ValueError("cannot convert '%s' to a integer" % str(val)) 623 # get the basic string without sign etc. 624 int_string = '%d' % int(round(math.fabs(val))) 625 # pad if necessary 626 if m is not None: 627 int_string = left_pad(int_string, m, '0') 628 # weird case where if zero width specified and is zero, can have zero space 629 if (val == 0) and (m == 0): 630 int_string = '' 631 # prepend the sign 632 if int_string != '': 633 int_string = _get_sign(val, state['incl_plus']) + int_string 634 # fill the field with blanks if the number takes more room than the width 635 # see f77 spec 13.5.9 remark 5. 636 if len(int_string) > w: 637 int_string = '*' * w 638 else: 639 int_string = int_string.rjust(w) 640 return int_string
641
642 -def _get_sign(val, incl_plus):
643 if val >= 0: 644 if incl_plus == True: 645 return '+' 646 else: 647 return '' 648 else: 649 return '-'
650
651 -def _compose_boz_string(w, m, state, val, ftype):
652 try: 653 val = int(val) 654 except ValueError: 655 raise ValueError("Cannot convert %s to an integer" % str(val)) 656 # Special case for zero 657 if val == 0: 658 if m is None: 659 return '0'.rjust(w) 660 elif w == m == 0: 661 return ' ' 662 elif m == 0: 663 return w * ' ' 664 else: 665 s = left_pad('0', m, '0').rjust(w) 666 if len(s) > w: 667 return w * '*' 668 # Normal cases 669 s = '' 670 if ftype == 'B': 671 # Binary case 672 if val < 0: 673 return '*' * w 674 while val > 0: 675 s = str(val % 2) + s 676 val = val >> 1 677 elif ftype == 'O': 678 # Octal case 679 if val < 0: 680 return '*' * w 681 s = '%o' % val 682 elif ftype == 'Z': 683 # Hex case 684 # Fortran uses Two's complement to represent negative numbers, this 685 # restricts hex values to sys.maxint, if greater than this overflow, 686 # however this is not perfoect as sys.maxint is Pythons build maximum 687 # rather than the systems bit size which is difficult to find reliably 688 # across platforms 689 if abs(val) > config.PROC_MAXINT: 690 return '*' * w 691 if val < 0: 692 s = '%X' % ((config.PROC_MAXINT * 2) + 2 + val) 693 else: 694 s = '%X' % val 695 if m is None: 696 s = s.rjust(w) 697 else: 698 s = left_pad(s, m, '0').rjust(w) 699 if len(s) > w: 700 return w * '*' 701 else: 702 return s
703
704 -def _write_string(record, sub_string, pos):
705 '''Function that actually writes the generated strings to a 'stream''''' 706 new_pos = pos + len(sub_string) 707 # pad if required with blanks - i.e. input after a tr edit descriptor - see 708 # f77 format sec. 13.5.3 709 if pos > len(record): 710 record = record.ljust(pos) 711 out = record + sub_string 712 elif pos == len(record): 713 out = record + sub_string 714 elif pos < len(record): 715 out = record[:pos] + sub_string + record[new_pos:] 716 return (new_pos, out)
717 718
719 -def left_pad(sub_string, width, pad_char):
720 # Python 2.3 does not have the character argument to rjust 721 padding = pad_char * (width - len(sub_string)) 722 return padding + sub_string
723