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
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
38
39
40
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
47 eds = expand_edit_descriptors(eds)
48 reversion_eds = expand_edit_descriptors(reversion_eds)
49
50 get_ed = has_next_iterator(eds)
51 get_value = has_next_iterator(values)
52 tmp_reversion_eds = []
53
54 while True:
55
56
57 if not get_ed.has_next() and not get_value.has_next():
58 break
59
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
68
69 while True:
70 if len(tmp_reversion_eds):
71 ed = tmp_reversion_eds.pop()
72
73 if not isinstance(ed, NON_REVERSION_EDS):
74 break
75 else:
76
77
78 record = record + config.RECORD_SEPARATOR
79 state['position'] = len(record)
80 tmp_reversion_eds = reversion_eds[::-1]
81 else:
82
83
84 break
85
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
94
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
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
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
172 return record
173
175 if ftype in ['B', 'O', 'Z']:
176 return ''
177 else:
178
179 if w == 0:
180 w = 4
181 if w < 3:
182 return '*' * w
183 return 'NaN'.rjust(w)
184
186 if ftype in ['B', 'O', 'Z']:
187 return ''
188 else:
189 sign = '+'
190
191 if w == 0:
192 w = 4
193 if w < 3:
194 return '*' * w
195
196 if sign_bit:
197 sign = '-'
198
199 if w == 3:
200 return '*' * w
201
202 if w > 8:
203 return (sign + 'Infinity').rjust(w)
204
205 elif w > 3:
206 return (sign + 'Inf').rjust(w)
207
208 else:
209 return 'Inf'
210
211
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
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
227 edigits = 4
228 if (ftype in ['F', 'EN', 'G']) or \
229 ((ftype in ['D', 'E']) and (state['scale'] != 0)):
230
231 ndigits = PROC_MIN_FIELD_WIDTH - 4 - edigits
232 else:
233
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
241
242 if val == 0.0:
243 sign_bit = '-' in str(val)
244 else:
245 sign_bit = val < 0
246
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
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
259
260
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
267 if ftype != 'G':
268 return _output_float(w, d, e, state, ftype, buff, sign_bit, zero_flag, ndigits, edigits)
269 else:
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
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
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
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
331
332
333
334
335
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
343 if d != 0:
344 assert(buff[2] in ['.', ','])
345 assert(buff[ndigits + 2] == 'e')
346
347 ex = int(buff[ndigits + 3:]) + 1
348
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
356 if w == 0:
357 w = d + 2
358
359 if (w == 1) and (ft == 'F'):
360 if state['incl_plus']:
361 return '*'
362 else:
363 return '.'
364
365 digits = buff[1] + buff[3:]
366
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
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
424 if (nbefore + nafter) == 0:
425 ndigits = 0
426 if (nzero_real == d) and (int(digits[0]) >= 5):
427
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
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
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
463 if expchar is not None:
464
465
466
467
468 if e < 0:
469
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
480 if edigits > e:
481 edigits = -1
482 else:
483 edigits = e + 2
484 else:
485 edigits = 0
486
487 i = 0
488 while i < ndigits:
489 if digits[i] != '0':
490 break
491 i = i + 1
492 if i == ndigits:
493
494 if PROC_SIGN_ZERO:
495 sign = _calculate_sign(state, sign_bit)
496 else:
497 sign = _calculate_sign(state, False)
498
499 if w <= 0:
500 w = nbefore + nzero + nafter + 1 + len(sign)
501
502 nblanks = w - (nbefore + nzero + nafter + edigits + 1)
503 if sign != '':
504 nblanks = nblanks - 1
505
506 if G0_NO_BLANKS:
507 w = w - nblanks
508 nblanks = 0
509
510 if (nblanks < 0) or (edigits == -1):
511 return '*' * w
512
513 if (nbefore == 0) and (nblanks > 0):
514 leadzero = True
515 nblanks = nblanks - 1
516 else:
517 leadzero = False
518 out = ''
519
520 if (nblanks > 0) and not PROC_NO_LEADING_BLANK:
521 out = out + ' ' * nblanks
522
523 out = out + sign
524
525 if leadzero:
526 out = out + '0'
527
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
539 out = out + PROC_DECIMAL_CHAR
540
541 if nzero > 0:
542 out = out + ('0' * nzero)
543
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
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
561 if PROC_NO_LEADING_BLANK:
562 tmp_buf = tmp_buff + (nblanks * ' ')
563 out = out + tmp_buff
564 return out
565
566
568 s = ''
569 if negative_flag:
570 s = '-'
571 elif state['incl_plus']:
572 s = '+'
573 else:
574 s = ''
575 return s
576
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
587
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
599
600 try:
601 val = bool(val)
602 except ValueError:
603 raise ValueError("cannot convert '%s' to a boolean" % str(val))
604
605 if val == True:
606 sub_string = 'T'
607 else:
608 sub_string = 'F'
609
610 sub_string = sub_string.rjust(w)
611 return sub_string
612
613
615
616 null_field = False
617
618
619 try:
620 val = int(val)
621 except ValueError:
622 raise ValueError("cannot convert '%s' to a integer" % str(val))
623
624 int_string = '%d' % int(round(math.fabs(val)))
625
626 if m is not None:
627 int_string = left_pad(int_string, m, '0')
628
629 if (val == 0) and (m == 0):
630 int_string = ''
631
632 if int_string != '':
633 int_string = _get_sign(val, state['incl_plus']) + int_string
634
635
636 if len(int_string) > w:
637 int_string = '*' * w
638 else:
639 int_string = int_string.rjust(w)
640 return int_string
641
643 if val >= 0:
644 if incl_plus == True:
645 return '+'
646 else:
647 return ''
648 else:
649 return '-'
650
652 try:
653 val = int(val)
654 except ValueError:
655 raise ValueError("Cannot convert %s to an integer" % str(val))
656
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
669 s = ''
670 if ftype == 'B':
671
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
679 if val < 0:
680 return '*' * w
681 s = '%o' % val
682 elif ftype == 'Z':
683
684
685
686
687
688
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
705 '''Function that actually writes the generated strings to a 'stream'''''
706 new_pos = pos + len(sub_string)
707
708
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
721 padding = pad_char * (width - len(sub_string))
722 return padding + sub_string
723